ddx-python 1.0.4__cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ddx/.gitignore +1 -0
- ddx/__init__.py +58 -0
- ddx/_rust/__init__.pyi +2685 -0
- ddx/_rust/common/__init__.pyi +17 -0
- ddx/_rust/common/accounting.pyi +6 -0
- ddx/_rust/common/enums.pyi +3 -0
- ddx/_rust/common/requests/__init__.pyi +23 -0
- ddx/_rust/common/requests/intents.pyi +19 -0
- ddx/_rust/common/specs.pyi +17 -0
- ddx/_rust/common/state/__init__.pyi +41 -0
- ddx/_rust/common/state/keys.pyi +29 -0
- ddx/_rust/common/transactions.pyi +7 -0
- ddx/_rust/decimal.pyi +3 -0
- ddx/_rust/h256.pyi +3 -0
- ddx/_rust.abi3.so +0 -0
- ddx/app_config/ethereum/addresses.json +526 -0
- ddx/auditor/README.md +32 -0
- ddx/auditor/__init__.py +0 -0
- ddx/auditor/auditor_driver.py +1043 -0
- ddx/auditor/websocket_message.py +54 -0
- ddx/common/__init__.py +0 -0
- ddx/common/epoch_params.py +28 -0
- ddx/common/fill_context.py +141 -0
- ddx/common/logging.py +184 -0
- ddx/common/market_aware_account.py +259 -0
- ddx/common/market_specs.py +64 -0
- ddx/common/trade_mining_params.py +19 -0
- ddx/common/transaction_utils.py +85 -0
- ddx/common/transactions/__init__.py +0 -0
- ddx/common/transactions/advance_epoch.py +91 -0
- ddx/common/transactions/advance_settlement_epoch.py +63 -0
- ddx/common/transactions/all_price_checkpoints.py +84 -0
- ddx/common/transactions/cancel.py +76 -0
- ddx/common/transactions/cancel_all.py +88 -0
- ddx/common/transactions/complete_fill.py +103 -0
- ddx/common/transactions/disaster_recovery.py +96 -0
- ddx/common/transactions/event.py +48 -0
- ddx/common/transactions/fee_distribution.py +119 -0
- ddx/common/transactions/funding.py +292 -0
- ddx/common/transactions/futures_expiry.py +123 -0
- ddx/common/transactions/genesis.py +108 -0
- ddx/common/transactions/inner/__init__.py +0 -0
- ddx/common/transactions/inner/adl_outcome.py +25 -0
- ddx/common/transactions/inner/fill.py +232 -0
- ddx/common/transactions/inner/liquidated_position.py +41 -0
- ddx/common/transactions/inner/liquidation_entry.py +41 -0
- ddx/common/transactions/inner/liquidation_fill.py +118 -0
- ddx/common/transactions/inner/outcome.py +32 -0
- ddx/common/transactions/inner/trade_fill.py +292 -0
- ddx/common/transactions/insurance_fund_update.py +138 -0
- ddx/common/transactions/insurance_fund_withdraw.py +100 -0
- ddx/common/transactions/liquidation.py +353 -0
- ddx/common/transactions/partial_fill.py +125 -0
- ddx/common/transactions/pnl_realization.py +120 -0
- ddx/common/transactions/post.py +72 -0
- ddx/common/transactions/post_order.py +95 -0
- ddx/common/transactions/price_checkpoint.py +97 -0
- ddx/common/transactions/signer_registered.py +62 -0
- ddx/common/transactions/specs_update.py +61 -0
- ddx/common/transactions/strategy_update.py +158 -0
- ddx/common/transactions/tradable_product_update.py +98 -0
- ddx/common/transactions/trade_mining.py +147 -0
- ddx/common/transactions/trader_update.py +131 -0
- ddx/common/transactions/withdraw.py +90 -0
- ddx/common/transactions/withdraw_ddx.py +74 -0
- ddx/common/utils.py +176 -0
- ddx/config.py +17 -0
- ddx/derivadex_client.py +270 -0
- ddx/models/__init__.py +0 -0
- ddx/models/base.py +132 -0
- ddx/py.typed +0 -0
- ddx/realtime_client/__init__.py +2 -0
- ddx/realtime_client/config.py +2 -0
- ddx/realtime_client/models/__init__.py +611 -0
- ddx/realtime_client/realtime_client.py +646 -0
- ddx/rest_client/__init__.py +0 -0
- ddx/rest_client/clients/__init__.py +0 -0
- ddx/rest_client/clients/base_client.py +60 -0
- ddx/rest_client/clients/market_client.py +1243 -0
- ddx/rest_client/clients/on_chain_client.py +439 -0
- ddx/rest_client/clients/signed_client.py +292 -0
- ddx/rest_client/clients/system_client.py +843 -0
- ddx/rest_client/clients/trade_client.py +357 -0
- ddx/rest_client/constants/__init__.py +0 -0
- ddx/rest_client/constants/endpoints.py +66 -0
- ddx/rest_client/contracts/__init__.py +0 -0
- ddx/rest_client/contracts/checkpoint/__init__.py +560 -0
- ddx/rest_client/contracts/ddx/__init__.py +1949 -0
- ddx/rest_client/contracts/dummy_token/__init__.py +1014 -0
- ddx/rest_client/contracts/i_collateral/__init__.py +1414 -0
- ddx/rest_client/contracts/i_stake/__init__.py +696 -0
- ddx/rest_client/exceptions/__init__.py +0 -0
- ddx/rest_client/exceptions/exceptions.py +32 -0
- ddx/rest_client/http/__init__.py +0 -0
- ddx/rest_client/http/http_client.py +336 -0
- ddx/rest_client/models/__init__.py +0 -0
- ddx/rest_client/models/market.py +693 -0
- ddx/rest_client/models/signed.py +61 -0
- ddx/rest_client/models/system.py +311 -0
- ddx/rest_client/models/trade.py +185 -0
- ddx/rest_client/utils/__init__.py +0 -0
- ddx/rest_client/utils/encryption_utils.py +26 -0
- ddx/utils/__init__.py +0 -0
- ddx_python-1.0.4.dist-info/METADATA +63 -0
- ddx_python-1.0.4.dist-info/RECORD +106 -0
- ddx_python-1.0.4.dist-info/WHEEL +5 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
import sexpdata
|
|
4
|
+
from ddx._rust.common.specs import (
|
|
5
|
+
ProductSpecs,
|
|
6
|
+
QuarterlyExpiryFuture,
|
|
7
|
+
SingleNamePerpetual,
|
|
8
|
+
SpecsKind,
|
|
9
|
+
)
|
|
10
|
+
from ddx._rust.common.state.keys import SpecsKey
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class MarketSpecs:
|
|
16
|
+
"""
|
|
17
|
+
Defines the MarketSpecs of all symbols
|
|
18
|
+
|
|
19
|
+
Attributes:
|
|
20
|
+
market_specs: SpecsKey <> ProductSpecs
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(self, genesis_params: dict):
|
|
24
|
+
self.market_specs = {}
|
|
25
|
+
for spec_key, spec in genesis_params["specs"].items():
|
|
26
|
+
if spec_key.startswith("SINGLENAMEPERP"):
|
|
27
|
+
spec_kind = SpecsKind.SingleNamePerpetual
|
|
28
|
+
spec_type = SingleNamePerpetual
|
|
29
|
+
elif spec_key.startswith("INDEXFUNDPERP"):
|
|
30
|
+
# TODO: implement this
|
|
31
|
+
# spec_kind = SpecsKind.IndexFundPerpetual
|
|
32
|
+
# spec_type = IndexFundPerpetual
|
|
33
|
+
raise NotImplementedError("IndexFundPerpetual is not implemented")
|
|
34
|
+
elif spec_key.startswith("QUARTERLYFUTURE"):
|
|
35
|
+
spec_kind = SpecsKind.QuarterlyExpiryFuture
|
|
36
|
+
spec_type = QuarterlyExpiryFuture
|
|
37
|
+
else:
|
|
38
|
+
continue
|
|
39
|
+
spec = sexpdata.loads(spec)
|
|
40
|
+
inner = spec_type(
|
|
41
|
+
**{
|
|
42
|
+
str(k)[1:].replace("-", "_"): v
|
|
43
|
+
for k, v in zip(spec[1::2], spec[2::2])
|
|
44
|
+
}
|
|
45
|
+
)
|
|
46
|
+
if isinstance(inner, SingleNamePerpetual):
|
|
47
|
+
product_specs = ProductSpecs.SingleNamePerpetual(inner)
|
|
48
|
+
elif isinstance(inner, QuarterlyExpiryFuture):
|
|
49
|
+
product_specs = ProductSpecs.QuarterlyExpiryFuture(inner)
|
|
50
|
+
else:
|
|
51
|
+
raise NotImplementedError("Unknown product specs type")
|
|
52
|
+
self.market_specs[SpecsKey(spec_kind, spec_key.split("-")[1])] = (
|
|
53
|
+
product_specs
|
|
54
|
+
)
|
|
55
|
+
logger.info(f"Loaded market specs: {self.market_specs}")
|
|
56
|
+
|
|
57
|
+
def __getitem__(self, specs_key: SpecsKey) -> ProductSpecs:
|
|
58
|
+
return self.market_specs[specs_key]
|
|
59
|
+
|
|
60
|
+
def keys(self):
|
|
61
|
+
return self.market_specs.keys()
|
|
62
|
+
|
|
63
|
+
def items(self):
|
|
64
|
+
return self.market_specs.items()
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from attrs import define, field
|
|
2
|
+
from ddx._rust.decimal import Decimal
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@define
|
|
6
|
+
class TradeMiningParams:
|
|
7
|
+
"""
|
|
8
|
+
Defines the trade mining parameters determined at the start of a scenario
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
trade_mining_length: int
|
|
12
|
+
trade_mining_reward_per_epoch: Decimal
|
|
13
|
+
trade_mining_maker_reward_percentage: Decimal
|
|
14
|
+
trade_mining_taker_reward_percentage: Decimal = field(init=False)
|
|
15
|
+
|
|
16
|
+
def __attrs_post_init__(self):
|
|
17
|
+
self.trade_mining_taker_reward_percentage = (
|
|
18
|
+
Decimal("1") - self.trade_mining_maker_reward_percentage
|
|
19
|
+
)
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from ddx.common.logging import auditor_logger
|
|
5
|
+
from ddx._rust.common import ProductSymbol
|
|
6
|
+
from ddx._rust.common.state import DerivadexSMT, Price
|
|
7
|
+
from ddx._rust.common.state.keys import PriceKey
|
|
8
|
+
from ddx._rust.decimal import Decimal
|
|
9
|
+
from sortedcontainers import SortedKeyList
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def get_prices_for_symbol_and_duration(
|
|
15
|
+
smt: DerivadexSMT,
|
|
16
|
+
symbol: ProductSymbol,
|
|
17
|
+
duration: int,
|
|
18
|
+
) -> SortedKeyList:
|
|
19
|
+
"""
|
|
20
|
+
Get Price leaves from SMT for a given market and a certain duration. This is used
|
|
21
|
+
internally when computing the funding rate since we need to
|
|
22
|
+
obtain all the Price leaves in the state to derive the
|
|
23
|
+
time-weighted average of the premium rate.
|
|
24
|
+
|
|
25
|
+
Parameters
|
|
26
|
+
----------
|
|
27
|
+
smt: DerivadexSMT
|
|
28
|
+
DerivaDEX Sparse Merkle Tree
|
|
29
|
+
symbol : ProductSymbol
|
|
30
|
+
Market symbol
|
|
31
|
+
duration : int
|
|
32
|
+
Duration of lookback in ticks
|
|
33
|
+
"""
|
|
34
|
+
logger.debug(f"Getting price leaves for {symbol} for the last {duration} ticks")
|
|
35
|
+
|
|
36
|
+
price_leaves = smt.all_prices_for_symbol(symbol)
|
|
37
|
+
logger.debug(f"All price leaves for {symbol}: {price_leaves}")
|
|
38
|
+
if not price_leaves:
|
|
39
|
+
return SortedKeyList()
|
|
40
|
+
|
|
41
|
+
sorted_price_leaves = SortedKeyList(key=lambda price: price[1].time_value)
|
|
42
|
+
for key, value in price_leaves:
|
|
43
|
+
sorted_price_leaves.add((key, value))
|
|
44
|
+
|
|
45
|
+
last_time_value = sorted_price_leaves[-1][1].time_value
|
|
46
|
+
|
|
47
|
+
bisect_time_value = max(last_time_value - duration, 0)
|
|
48
|
+
logger.debug(
|
|
49
|
+
f"Retrieving price leaves from within ticks [{bisect_time_value}, {last_time_value}]"
|
|
50
|
+
)
|
|
51
|
+
bisect_index = sorted_price_leaves.bisect_key_left(bisect_time_value)
|
|
52
|
+
logger.debug(f"Bisection index: {bisect_index}")
|
|
53
|
+
|
|
54
|
+
return sorted_price_leaves[bisect_index:]
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def get_most_recent_price(
|
|
58
|
+
smt: DerivadexSMT, symbol: ProductSymbol, time_value: int
|
|
59
|
+
) -> Optional[tuple[PriceKey, Price]]:
|
|
60
|
+
"""
|
|
61
|
+
Get the most recent Price leaf for a given market and time value.
|
|
62
|
+
|
|
63
|
+
Parameters
|
|
64
|
+
----------
|
|
65
|
+
smt: DerivadexSMT
|
|
66
|
+
DerivaDEX Sparse Merkle Tree
|
|
67
|
+
symbol : ProductSymbol
|
|
68
|
+
Market symbol
|
|
69
|
+
time_value : int
|
|
70
|
+
Time value of reference
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
logger.debug(
|
|
74
|
+
f"Getting the most recent price for {symbol} at time value {time_value}"
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
price_leaves = smt.all_prices_for_symbol(symbol)
|
|
78
|
+
logger.debug(f"All price leaves for {symbol}: {price_leaves}")
|
|
79
|
+
|
|
80
|
+
# Find the most recent price leaf at or before time_value
|
|
81
|
+
return max(
|
|
82
|
+
filter(lambda price: price[1].time_value <= time_value, price_leaves),
|
|
83
|
+
key=lambda price: price[1].ordinal,
|
|
84
|
+
default=None,
|
|
85
|
+
)
|
|
File without changes
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AdvanceEpoch module
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from attrs import define, field
|
|
6
|
+
from ddx.common.transactions.event import Event
|
|
7
|
+
from ddx._rust.common import ProductSymbol, TokenSymbol
|
|
8
|
+
from ddx._rust.common.state import DerivadexSMT, EpochMetadata
|
|
9
|
+
from ddx._rust.common.state.keys import EpochMetadataKey
|
|
10
|
+
from ddx._rust.decimal import Decimal
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@define
|
|
14
|
+
class AdvanceEpoch(Event):
|
|
15
|
+
"""
|
|
16
|
+
Defines an AdvanceEpoch
|
|
17
|
+
|
|
18
|
+
An AdvanceEpoch is a non-transitioning transaction that indicates
|
|
19
|
+
the start of a new epoch.
|
|
20
|
+
|
|
21
|
+
Attributes:
|
|
22
|
+
next_book_ordinals (dict[ProductSymbol, int]): dictionary ({symbol: next_book_ordinal}) indicating the next book ordinal by symbol
|
|
23
|
+
new_epoch_id (int): New epoch ID after epoch marker
|
|
24
|
+
request_index (int): Sequenced request index of transaction
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
next_book_ordinals: dict[ProductSymbol, int]
|
|
28
|
+
new_epoch_id: int
|
|
29
|
+
request_index: int = field(default=-1, eq=False)
|
|
30
|
+
|
|
31
|
+
@classmethod
|
|
32
|
+
def decode_value_into_cls(cls, raw_tx_log_event: dict):
|
|
33
|
+
"""
|
|
34
|
+
Decode a raw transaction log event (dict) into an AdvanceEpoch
|
|
35
|
+
instance.
|
|
36
|
+
|
|
37
|
+
Parameters
|
|
38
|
+
----------
|
|
39
|
+
raw_tx_log_event : dict
|
|
40
|
+
Raw transaction log event being processed
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
advance_epoch_tx_event = raw_tx_log_event["event"]["c"]
|
|
44
|
+
|
|
45
|
+
return cls(
|
|
46
|
+
{
|
|
47
|
+
ProductSymbol(symbol): ordinal
|
|
48
|
+
for symbol, ordinal in advance_epoch_tx_event[
|
|
49
|
+
"nextBookOrdinals"
|
|
50
|
+
].items()
|
|
51
|
+
},
|
|
52
|
+
advance_epoch_tx_event["newEpochId"],
|
|
53
|
+
raw_tx_log_event["requestIndex"],
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
def process_tx(
|
|
57
|
+
self,
|
|
58
|
+
smt: DerivadexSMT,
|
|
59
|
+
**kwargs,
|
|
60
|
+
):
|
|
61
|
+
"""
|
|
62
|
+
Process an EpochMarker transaction of type AdvanceEpoch. This
|
|
63
|
+
indicates the a new epoch in the transaction log, although
|
|
64
|
+
it is not state-transitioning in the way typical transactions
|
|
65
|
+
are.
|
|
66
|
+
|
|
67
|
+
Parameters
|
|
68
|
+
----------
|
|
69
|
+
smt: DerivadexSMT
|
|
70
|
+
DerivaDEX Sparse Merkle Tree
|
|
71
|
+
**kwargs
|
|
72
|
+
Additional args specific to AdvanceEpoch transactions
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
# Update current epoch next book ordinals for closing
|
|
76
|
+
old_epoch_metadata_key = EpochMetadataKey(self.new_epoch_id - 1)
|
|
77
|
+
old_epoch_metadata = smt.epoch_metadata(old_epoch_metadata_key)
|
|
78
|
+
old_epoch_metadata.next_book_ordinals = self.next_book_ordinals
|
|
79
|
+
smt.store_epoch_metadata(old_epoch_metadata_key, old_epoch_metadata)
|
|
80
|
+
|
|
81
|
+
# Create a new epoch metadata
|
|
82
|
+
smt.store_epoch_metadata(
|
|
83
|
+
EpochMetadataKey(self.new_epoch_id), EpochMetadata.default()
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
# Set the expected epoch ID to be the new epoch ID and the
|
|
87
|
+
# expected tx ordinal to be -1, because we immediately increment
|
|
88
|
+
# this by 1, thus setting it to 0, which will be the first
|
|
89
|
+
# tx ordinal of the next epoch
|
|
90
|
+
kwargs["expected_epoch_id"](kwargs["auditor_instance"], self.new_epoch_id)
|
|
91
|
+
kwargs["expected_tx_ordinal"](kwargs["auditor_instance"], -1)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AdvanceSettlementEpoch module
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from attrs import define, field
|
|
6
|
+
from ddx.common.transactions.event import Event
|
|
7
|
+
from ddx._rust.common.state import DerivadexSMT
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@define
|
|
11
|
+
class AdvanceSettlementEpoch(Event):
|
|
12
|
+
"""
|
|
13
|
+
Defines a AdvanceSettlementEpoch
|
|
14
|
+
|
|
15
|
+
A AdvanceSettlementEpoch is a non-transitioning transaction that indicates
|
|
16
|
+
the start of a new settlement epoch.
|
|
17
|
+
|
|
18
|
+
Attributes:
|
|
19
|
+
request_index (int): Sequenced request index of transaction
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
request_index: int = field(default=-1, eq=False)
|
|
23
|
+
|
|
24
|
+
@classmethod
|
|
25
|
+
def decode_value_into_cls(cls, raw_tx_log_event: dict):
|
|
26
|
+
"""
|
|
27
|
+
Decode a raw transaction log event (dict) into a AdvanceSettlementEpoch
|
|
28
|
+
instance.
|
|
29
|
+
|
|
30
|
+
Parameters
|
|
31
|
+
----------
|
|
32
|
+
raw_tx_log_event : dict
|
|
33
|
+
Raw transaction log event being processed
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
return cls(
|
|
37
|
+
raw_tx_log_event["requestIndex"],
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
def process_tx(
|
|
41
|
+
self,
|
|
42
|
+
smt: DerivadexSMT,
|
|
43
|
+
**kwargs,
|
|
44
|
+
):
|
|
45
|
+
"""
|
|
46
|
+
Process a AdvanceSettlementEpoch transaction.
|
|
47
|
+
|
|
48
|
+
Parameters
|
|
49
|
+
----------
|
|
50
|
+
smt: DerivadexSMT
|
|
51
|
+
DerivaDEX Sparse Merkle Tree
|
|
52
|
+
**kwargs
|
|
53
|
+
Additional args specific to AdvanceSettlementEpoch transactions
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
latest_price_keys = {
|
|
57
|
+
price_key for price_key, _ in kwargs["latest_price_leaves"].values()
|
|
58
|
+
}
|
|
59
|
+
for price_key, _ in smt.all_prices():
|
|
60
|
+
if price_key in latest_price_keys:
|
|
61
|
+
continue
|
|
62
|
+
|
|
63
|
+
smt.store_price(price_key, None)
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AllPriceCheckpoints module
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from attrs import define, field
|
|
6
|
+
from ddx.common.transactions.event import Event
|
|
7
|
+
from ddx.common.transactions.price_checkpoint import PriceCheckpoint
|
|
8
|
+
from ddx._rust.common import ProductSymbol
|
|
9
|
+
from ddx._rust.common.accounting import MarkPriceMetadata
|
|
10
|
+
from ddx._rust.common.state import DerivadexSMT
|
|
11
|
+
from ddx._rust.decimal import Decimal
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@define
|
|
15
|
+
class AllPriceCheckpoints(Event):
|
|
16
|
+
"""
|
|
17
|
+
Defines a AllPriceCheckpoints
|
|
18
|
+
|
|
19
|
+
An AllPriceCheckpoints is when a market registers an update to the
|
|
20
|
+
composite index price a perpetual is tracking along with the ema
|
|
21
|
+
component for 1+ symbols.
|
|
22
|
+
|
|
23
|
+
Attributes:
|
|
24
|
+
price_checkpoints (list[PriceCheckpoint]): The price checkpoints that make up this transaction
|
|
25
|
+
request_index (int): Sequenced request index of transaction
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
price_checkpoints: list[PriceCheckpoint] = field(eq=set)
|
|
29
|
+
request_index: int = field(default=-1, eq=False)
|
|
30
|
+
|
|
31
|
+
@classmethod
|
|
32
|
+
def decode_value_into_cls(cls, raw_tx_log_event: dict):
|
|
33
|
+
"""
|
|
34
|
+
Decode a raw transaction log event (dict) into an
|
|
35
|
+
AllPriceCheckpoints instance.
|
|
36
|
+
|
|
37
|
+
Parameters
|
|
38
|
+
----------
|
|
39
|
+
raw_tx_log_event : dict
|
|
40
|
+
Raw transaction log event being processed
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
all_price_checkpoint_tx_event = raw_tx_log_event["event"]["c"]
|
|
44
|
+
|
|
45
|
+
return cls(
|
|
46
|
+
[
|
|
47
|
+
PriceCheckpoint(
|
|
48
|
+
ProductSymbol(all_price_checkpoints_key),
|
|
49
|
+
MarkPriceMetadata.from_dict(
|
|
50
|
+
all_price_checkpoints_val["markPriceMetadata"]
|
|
51
|
+
),
|
|
52
|
+
all_price_checkpoints_val["indexPriceHash"],
|
|
53
|
+
Decimal(all_price_checkpoints_val["indexPrice"]),
|
|
54
|
+
all_price_checkpoints_val["ordinal"],
|
|
55
|
+
all_price_checkpoints_val["timeValue"],
|
|
56
|
+
raw_tx_log_event["requestIndex"],
|
|
57
|
+
)
|
|
58
|
+
for all_price_checkpoints_key, all_price_checkpoints_val in all_price_checkpoint_tx_event.items()
|
|
59
|
+
],
|
|
60
|
+
raw_tx_log_event["requestIndex"],
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
def process_tx(
|
|
64
|
+
self,
|
|
65
|
+
smt: DerivadexSMT,
|
|
66
|
+
**kwargs,
|
|
67
|
+
):
|
|
68
|
+
"""
|
|
69
|
+
Process an AllPriceCheckpoints transaction. An
|
|
70
|
+
AllPriceCheckpoints consists of information relating to a new
|
|
71
|
+
price checkpoint for 1+ symbols.
|
|
72
|
+
|
|
73
|
+
Parameters
|
|
74
|
+
----------
|
|
75
|
+
smt: DerivadexSMT
|
|
76
|
+
DerivaDEX Sparse Merkle Tree
|
|
77
|
+
**kwargs
|
|
78
|
+
Additional args specific to AllPriceCheckpoints transactions
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
# Loop through each price checkpoint event and process them
|
|
82
|
+
# individually
|
|
83
|
+
for price_checkpoint in self.price_checkpoints:
|
|
84
|
+
price_checkpoint.process_tx(smt, **kwargs)
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Cancel module
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
|
|
7
|
+
from attrs import define, field
|
|
8
|
+
from ddx.common.transactions.event import Event
|
|
9
|
+
from ddx._rust.common import ProductSymbol
|
|
10
|
+
from ddx._rust.common.state import DerivadexSMT
|
|
11
|
+
from ddx._rust.common.state.keys import BookOrderKey
|
|
12
|
+
from ddx._rust.decimal import Decimal
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@define(hash=True)
|
|
18
|
+
class Cancel(Event):
|
|
19
|
+
"""
|
|
20
|
+
Defines a Cancel
|
|
21
|
+
|
|
22
|
+
A Cancel is when an existing order is canceled and removed from the
|
|
23
|
+
order book.
|
|
24
|
+
|
|
25
|
+
Attributes:
|
|
26
|
+
symbol (ProductSymbol): The symbol for the market this order is for.
|
|
27
|
+
order_hash (str): Hexstr representation of the EIP-712 hash of the order
|
|
28
|
+
amount (Decimal): Amount/size of order
|
|
29
|
+
request_index (int): Sequenced request index of transaction
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
symbol: ProductSymbol
|
|
33
|
+
order_hash: str = field(eq=str.lower)
|
|
34
|
+
amount: Decimal
|
|
35
|
+
request_index: int = field(default=-1, eq=False, hash=False)
|
|
36
|
+
|
|
37
|
+
@classmethod
|
|
38
|
+
def decode_value_into_cls(cls, raw_tx_log_event: dict):
|
|
39
|
+
"""
|
|
40
|
+
Decode a raw transaction log event (dict) into a Cancel
|
|
41
|
+
instance.
|
|
42
|
+
|
|
43
|
+
Parameters
|
|
44
|
+
----------
|
|
45
|
+
raw_tx_log_event : dict
|
|
46
|
+
Raw transaction log event being processed
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
cancel_tx_event = raw_tx_log_event["event"]["c"]
|
|
50
|
+
|
|
51
|
+
return cls(
|
|
52
|
+
ProductSymbol(cancel_tx_event["symbol"]),
|
|
53
|
+
cancel_tx_event["orderHash"],
|
|
54
|
+
Decimal(cancel_tx_event["amount"]),
|
|
55
|
+
raw_tx_log_event["requestIndex"],
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
def process_tx(
|
|
59
|
+
self,
|
|
60
|
+
smt: DerivadexSMT,
|
|
61
|
+
**kwargs,
|
|
62
|
+
):
|
|
63
|
+
"""
|
|
64
|
+
Process a Cancel transaction. We will need to delete a
|
|
65
|
+
BookOrder leaf with this information.
|
|
66
|
+
|
|
67
|
+
Parameters
|
|
68
|
+
----------
|
|
69
|
+
smt: DerivadexSMT
|
|
70
|
+
DerivaDEX Sparse Merkle Tree
|
|
71
|
+
**kwargs
|
|
72
|
+
Additional args specific to Cancel transactions
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
logger.debug(f"Canceling {self.symbol} order {self.order_hash}")
|
|
76
|
+
smt.store_book_order(BookOrderKey(self.symbol, self.order_hash), None)
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CancelAll module
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from attrs import define, field
|
|
6
|
+
from ddx.common.transactions.cancel import Cancel
|
|
7
|
+
from ddx.common.transactions.event import Event
|
|
8
|
+
from ddx._rust.common import ProductSymbol
|
|
9
|
+
from ddx._rust.common.state import BookOrder, DerivadexSMT
|
|
10
|
+
from ddx._rust.common.state.keys import BookOrderKey
|
|
11
|
+
from ddx._rust.h256 import H256
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@define
|
|
15
|
+
class CancelAll(Event):
|
|
16
|
+
"""
|
|
17
|
+
Defines a CancelAll
|
|
18
|
+
|
|
19
|
+
A CancelAll is when all existing orders are canceled and removed from the
|
|
20
|
+
order book for a given trader, strategy, and symbol.
|
|
21
|
+
|
|
22
|
+
Attributes:
|
|
23
|
+
symbol (ProductSymbol): The symbol for the market to cancel all orders for.
|
|
24
|
+
trader_address (str): The trader address component of the strategy key pertaining to the CancelAll tx.
|
|
25
|
+
strategy_id_hash (str): The strategy id hash component of the strategy key pertaining to the CancelAll tx.
|
|
26
|
+
request_index (int): Sequenced request index of transaction
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
symbol: ProductSymbol
|
|
30
|
+
trader_address: str = field(eq=str.lower)
|
|
31
|
+
strategy_id_hash: str = field(eq=str.lower)
|
|
32
|
+
request_index: int = field(default=-1, eq=False)
|
|
33
|
+
|
|
34
|
+
@classmethod
|
|
35
|
+
def decode_value_into_cls(cls, raw_tx_log_event: dict):
|
|
36
|
+
"""
|
|
37
|
+
Decode a raw transaction log event (dict) into a CancelAll
|
|
38
|
+
instance.
|
|
39
|
+
|
|
40
|
+
Parameters
|
|
41
|
+
----------
|
|
42
|
+
raw_tx_log_event : dict
|
|
43
|
+
Raw transaction log event being processed
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
cancel_tx_event = raw_tx_log_event["event"]["c"]
|
|
47
|
+
|
|
48
|
+
return cls(
|
|
49
|
+
ProductSymbol(cancel_tx_event["symbol"]),
|
|
50
|
+
cancel_tx_event["strategyKey"]["traderAddress"],
|
|
51
|
+
cancel_tx_event["strategyKey"]["strategyIdHash"],
|
|
52
|
+
raw_tx_log_event["requestIndex"],
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
def process_tx(
|
|
56
|
+
self,
|
|
57
|
+
smt: DerivadexSMT,
|
|
58
|
+
**kwargs,
|
|
59
|
+
):
|
|
60
|
+
"""
|
|
61
|
+
Process a CancelAll transaction. We will need to delete a
|
|
62
|
+
BookOrder leaf with this information.
|
|
63
|
+
|
|
64
|
+
Parameters
|
|
65
|
+
----------
|
|
66
|
+
smt: DerivadexSMT
|
|
67
|
+
DerivaDEX Sparse Merkle Tree
|
|
68
|
+
**kwargs
|
|
69
|
+
Additional args specific to CancelAll transactions
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
book_order_leaves: list[tuple[BookOrderKey, BookOrder]] = [
|
|
73
|
+
(book_order_key, book_order)
|
|
74
|
+
for book_order_key, book_order in smt.all_book_orders_for_symbol(
|
|
75
|
+
self.symbol
|
|
76
|
+
)
|
|
77
|
+
if book_order.trader_address == self.trader_address
|
|
78
|
+
and book_order.strategy_id_hash == self.strategy_id_hash
|
|
79
|
+
]
|
|
80
|
+
|
|
81
|
+
for book_order_key, book_order in book_order_leaves:
|
|
82
|
+
cancel = Cancel(
|
|
83
|
+
book_order_key.symbol,
|
|
84
|
+
book_order_key.order_hash,
|
|
85
|
+
book_order.amount,
|
|
86
|
+
self.request_index,
|
|
87
|
+
)
|
|
88
|
+
cancel.process_tx(smt)
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CompleteFill module
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from attrs import define, field
|
|
6
|
+
from ddx.common.transactions.cancel import Cancel
|
|
7
|
+
from ddx.common.transactions.event import Event
|
|
8
|
+
from ddx.common.transactions.inner.outcome import Outcome
|
|
9
|
+
from ddx.common.transactions.inner.trade_fill import TradeFill
|
|
10
|
+
from ddx._rust.common import ProductSymbol
|
|
11
|
+
from ddx._rust.common.enums import OrderSide
|
|
12
|
+
from ddx._rust.common.state import DerivadexSMT
|
|
13
|
+
from ddx._rust.decimal import Decimal
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@define
|
|
17
|
+
class CompleteFill(Event):
|
|
18
|
+
"""
|
|
19
|
+
Defines an CompleteFill
|
|
20
|
+
|
|
21
|
+
A CompleteFill is a scenario where the taker order has been completely filled
|
|
22
|
+
across 1 or more maker orders along with any canceled maker orders.
|
|
23
|
+
|
|
24
|
+
Attributes:
|
|
25
|
+
trade_outcomes (list[TradeFill | Cancel]): A list of trade outcome objects
|
|
26
|
+
request_index (int): Sequenced request index of transaction
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
trade_outcomes: list[TradeFill | Cancel] = field(eq=set)
|
|
30
|
+
request_index: int = field(default=-1, eq=False)
|
|
31
|
+
|
|
32
|
+
@classmethod
|
|
33
|
+
def decode_value_into_cls(cls, raw_tx_log_event: dict):
|
|
34
|
+
"""
|
|
35
|
+
Decode a raw transaction log event (dict) into a CompleteFill
|
|
36
|
+
instance.
|
|
37
|
+
|
|
38
|
+
Parameters
|
|
39
|
+
----------
|
|
40
|
+
raw_tx_log_event : dict
|
|
41
|
+
Raw transaction log event being processed
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
event = raw_tx_log_event["event"]["c"]
|
|
45
|
+
trade_outcomes_tx_event = event["tradeOutcomes"]
|
|
46
|
+
|
|
47
|
+
return cls(
|
|
48
|
+
[
|
|
49
|
+
(
|
|
50
|
+
TradeFill(
|
|
51
|
+
ProductSymbol(trade_outcome["Fill"]["symbol"]),
|
|
52
|
+
trade_outcome["Fill"]["takerOrderHash"],
|
|
53
|
+
trade_outcome["Fill"]["makerOrderHash"],
|
|
54
|
+
Decimal(trade_outcome["Fill"]["makerOrderRemainingAmount"]),
|
|
55
|
+
Decimal(trade_outcome["Fill"]["amount"]),
|
|
56
|
+
Decimal(trade_outcome["Fill"]["price"]),
|
|
57
|
+
OrderSide(trade_outcome["Fill"]["takerSide"]),
|
|
58
|
+
Outcome(
|
|
59
|
+
trade_outcome["Fill"]["makerOutcome"]["trader"],
|
|
60
|
+
trade_outcome["Fill"]["makerOutcome"]["strategyIdHash"],
|
|
61
|
+
),
|
|
62
|
+
Outcome(
|
|
63
|
+
trade_outcome["Fill"]["takerOutcome"]["trader"],
|
|
64
|
+
trade_outcome["Fill"]["takerOutcome"]["strategyIdHash"],
|
|
65
|
+
),
|
|
66
|
+
raw_tx_log_event["timeValue"],
|
|
67
|
+
raw_tx_log_event["requestIndex"],
|
|
68
|
+
)
|
|
69
|
+
if "Fill" in trade_outcome
|
|
70
|
+
else Cancel(
|
|
71
|
+
ProductSymbol(trade_outcome["Cancel"]["symbol"]),
|
|
72
|
+
trade_outcome["Cancel"]["orderHash"],
|
|
73
|
+
Decimal(trade_outcome["Cancel"]["amount"]),
|
|
74
|
+
raw_tx_log_event["requestIndex"],
|
|
75
|
+
)
|
|
76
|
+
)
|
|
77
|
+
for trade_outcome in trade_outcomes_tx_event
|
|
78
|
+
],
|
|
79
|
+
raw_tx_log_event["requestIndex"],
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
def process_tx(
|
|
83
|
+
self,
|
|
84
|
+
smt: DerivadexSMT,
|
|
85
|
+
**kwargs,
|
|
86
|
+
):
|
|
87
|
+
"""
|
|
88
|
+
Process a CompleteFill transaction. A CompleteFill consists of
|
|
89
|
+
Fill objects, which will adjust the maker BookOrder leaf in the
|
|
90
|
+
SMT, while also adjusting the Strategy, Position, and Trader
|
|
91
|
+
leaves corresponding to both the maker and the taker.
|
|
92
|
+
|
|
93
|
+
Parameters
|
|
94
|
+
----------
|
|
95
|
+
smt: DerivadexSMT
|
|
96
|
+
DerivaDEX Sparse Merkle Tree
|
|
97
|
+
**kwargs
|
|
98
|
+
Additional args specific to CompleteFill transactions
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
# Loop through each trade outcome event and process them individually
|
|
102
|
+
for trade_outcome in self.trade_outcomes:
|
|
103
|
+
trade_outcome.process_tx(smt, **kwargs)
|