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.
Files changed (106) hide show
  1. ddx/.gitignore +1 -0
  2. ddx/__init__.py +58 -0
  3. ddx/_rust/__init__.pyi +2685 -0
  4. ddx/_rust/common/__init__.pyi +17 -0
  5. ddx/_rust/common/accounting.pyi +6 -0
  6. ddx/_rust/common/enums.pyi +3 -0
  7. ddx/_rust/common/requests/__init__.pyi +23 -0
  8. ddx/_rust/common/requests/intents.pyi +19 -0
  9. ddx/_rust/common/specs.pyi +17 -0
  10. ddx/_rust/common/state/__init__.pyi +41 -0
  11. ddx/_rust/common/state/keys.pyi +29 -0
  12. ddx/_rust/common/transactions.pyi +7 -0
  13. ddx/_rust/decimal.pyi +3 -0
  14. ddx/_rust/h256.pyi +3 -0
  15. ddx/_rust.abi3.so +0 -0
  16. ddx/app_config/ethereum/addresses.json +526 -0
  17. ddx/auditor/README.md +32 -0
  18. ddx/auditor/__init__.py +0 -0
  19. ddx/auditor/auditor_driver.py +1043 -0
  20. ddx/auditor/websocket_message.py +54 -0
  21. ddx/common/__init__.py +0 -0
  22. ddx/common/epoch_params.py +28 -0
  23. ddx/common/fill_context.py +141 -0
  24. ddx/common/logging.py +184 -0
  25. ddx/common/market_aware_account.py +259 -0
  26. ddx/common/market_specs.py +64 -0
  27. ddx/common/trade_mining_params.py +19 -0
  28. ddx/common/transaction_utils.py +85 -0
  29. ddx/common/transactions/__init__.py +0 -0
  30. ddx/common/transactions/advance_epoch.py +91 -0
  31. ddx/common/transactions/advance_settlement_epoch.py +63 -0
  32. ddx/common/transactions/all_price_checkpoints.py +84 -0
  33. ddx/common/transactions/cancel.py +76 -0
  34. ddx/common/transactions/cancel_all.py +88 -0
  35. ddx/common/transactions/complete_fill.py +103 -0
  36. ddx/common/transactions/disaster_recovery.py +96 -0
  37. ddx/common/transactions/event.py +48 -0
  38. ddx/common/transactions/fee_distribution.py +119 -0
  39. ddx/common/transactions/funding.py +292 -0
  40. ddx/common/transactions/futures_expiry.py +123 -0
  41. ddx/common/transactions/genesis.py +108 -0
  42. ddx/common/transactions/inner/__init__.py +0 -0
  43. ddx/common/transactions/inner/adl_outcome.py +25 -0
  44. ddx/common/transactions/inner/fill.py +232 -0
  45. ddx/common/transactions/inner/liquidated_position.py +41 -0
  46. ddx/common/transactions/inner/liquidation_entry.py +41 -0
  47. ddx/common/transactions/inner/liquidation_fill.py +118 -0
  48. ddx/common/transactions/inner/outcome.py +32 -0
  49. ddx/common/transactions/inner/trade_fill.py +292 -0
  50. ddx/common/transactions/insurance_fund_update.py +138 -0
  51. ddx/common/transactions/insurance_fund_withdraw.py +100 -0
  52. ddx/common/transactions/liquidation.py +353 -0
  53. ddx/common/transactions/partial_fill.py +125 -0
  54. ddx/common/transactions/pnl_realization.py +120 -0
  55. ddx/common/transactions/post.py +72 -0
  56. ddx/common/transactions/post_order.py +95 -0
  57. ddx/common/transactions/price_checkpoint.py +97 -0
  58. ddx/common/transactions/signer_registered.py +62 -0
  59. ddx/common/transactions/specs_update.py +61 -0
  60. ddx/common/transactions/strategy_update.py +158 -0
  61. ddx/common/transactions/tradable_product_update.py +98 -0
  62. ddx/common/transactions/trade_mining.py +147 -0
  63. ddx/common/transactions/trader_update.py +131 -0
  64. ddx/common/transactions/withdraw.py +90 -0
  65. ddx/common/transactions/withdraw_ddx.py +74 -0
  66. ddx/common/utils.py +176 -0
  67. ddx/config.py +17 -0
  68. ddx/derivadex_client.py +270 -0
  69. ddx/models/__init__.py +0 -0
  70. ddx/models/base.py +132 -0
  71. ddx/py.typed +0 -0
  72. ddx/realtime_client/__init__.py +2 -0
  73. ddx/realtime_client/config.py +2 -0
  74. ddx/realtime_client/models/__init__.py +611 -0
  75. ddx/realtime_client/realtime_client.py +646 -0
  76. ddx/rest_client/__init__.py +0 -0
  77. ddx/rest_client/clients/__init__.py +0 -0
  78. ddx/rest_client/clients/base_client.py +60 -0
  79. ddx/rest_client/clients/market_client.py +1243 -0
  80. ddx/rest_client/clients/on_chain_client.py +439 -0
  81. ddx/rest_client/clients/signed_client.py +292 -0
  82. ddx/rest_client/clients/system_client.py +843 -0
  83. ddx/rest_client/clients/trade_client.py +357 -0
  84. ddx/rest_client/constants/__init__.py +0 -0
  85. ddx/rest_client/constants/endpoints.py +66 -0
  86. ddx/rest_client/contracts/__init__.py +0 -0
  87. ddx/rest_client/contracts/checkpoint/__init__.py +560 -0
  88. ddx/rest_client/contracts/ddx/__init__.py +1949 -0
  89. ddx/rest_client/contracts/dummy_token/__init__.py +1014 -0
  90. ddx/rest_client/contracts/i_collateral/__init__.py +1414 -0
  91. ddx/rest_client/contracts/i_stake/__init__.py +696 -0
  92. ddx/rest_client/exceptions/__init__.py +0 -0
  93. ddx/rest_client/exceptions/exceptions.py +32 -0
  94. ddx/rest_client/http/__init__.py +0 -0
  95. ddx/rest_client/http/http_client.py +336 -0
  96. ddx/rest_client/models/__init__.py +0 -0
  97. ddx/rest_client/models/market.py +693 -0
  98. ddx/rest_client/models/signed.py +61 -0
  99. ddx/rest_client/models/system.py +311 -0
  100. ddx/rest_client/models/trade.py +185 -0
  101. ddx/rest_client/utils/__init__.py +0 -0
  102. ddx/rest_client/utils/encryption_utils.py +26 -0
  103. ddx/utils/__init__.py +0 -0
  104. ddx_python-1.0.4.dist-info/METADATA +63 -0
  105. ddx_python-1.0.4.dist-info/RECORD +106 -0
  106. 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)