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,95 @@
1
+ """
2
+ PostOrder 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.post import Post
9
+ from ddx._rust.common import ProductSymbol
10
+ from ddx._rust.common.enums import OrderSide
11
+ from ddx._rust.common.state import DerivadexSMT
12
+ from ddx._rust.decimal import Decimal
13
+
14
+
15
+ @define
16
+ class PostOrder(Event):
17
+ """
18
+ Defines a PostOrder
19
+
20
+ A PostOrder is an order that enters the order book along with any
21
+ canceled maker orders.
22
+
23
+ Attributes:
24
+ post (Post): The posted order.
25
+ canceled_orders (list[Cancel]): Canceled maker orders as a result of the posted order
26
+ request_index (int): Sequenced request index of transaction
27
+ """
28
+
29
+ post: Post
30
+ canceled_orders: list[Cancel] = field(eq=set)
31
+ request_index: int = field(default=-1, eq=False)
32
+
33
+ @classmethod
34
+ def decode_value_into_cls(cls, raw_tx_log_event: dict):
35
+ """
36
+ Decode a raw transaction log event (dict) into a PostOrder
37
+ instance.
38
+
39
+ Parameters
40
+ ----------
41
+ raw_tx_log_event : dict
42
+ Raw transaction log event being processed
43
+ """
44
+
45
+ post_tx_event = raw_tx_log_event["event"]["c"]
46
+ cancel_orders_tx_event = post_tx_event["tradeOutcomes"]
47
+
48
+ return cls(
49
+ Post(
50
+ ProductSymbol(post_tx_event["symbol"]),
51
+ post_tx_event["orderHash"],
52
+ OrderSide(post_tx_event["side"]),
53
+ Decimal(post_tx_event["amount"]),
54
+ Decimal(post_tx_event["price"]),
55
+ post_tx_event["traderAddress"],
56
+ post_tx_event["strategyIdHash"],
57
+ post_tx_event["bookOrdinal"],
58
+ raw_tx_log_event["timeValue"],
59
+ raw_tx_log_event["requestIndex"],
60
+ ),
61
+ [
62
+ Cancel(
63
+ ProductSymbol(canceled_order["Cancel"]["symbol"]),
64
+ canceled_order["Cancel"]["orderHash"],
65
+ Decimal(canceled_order["Cancel"]["amount"]),
66
+ raw_tx_log_event["requestIndex"],
67
+ )
68
+ for canceled_order in cancel_orders_tx_event
69
+ ],
70
+ raw_tx_log_event["requestIndex"],
71
+ )
72
+
73
+ def process_tx(
74
+ self,
75
+ smt: DerivadexSMT,
76
+ **kwargs,
77
+ ):
78
+ """
79
+ Process a PostOrder transaction. We will need to create a new
80
+ BookOrder leaf with this information.
81
+
82
+ Parameters
83
+ ----------
84
+ smt: DerivadexSMT
85
+ DerivaDEX Sparse Merkle Tree
86
+ **kwargs
87
+ Additional args specific to PostOrder transactions
88
+ """
89
+
90
+ # Loop through each cancel event and process them individually
91
+ for canceled_order in self.canceled_orders:
92
+ canceled_order.process_tx(smt, **kwargs)
93
+
94
+ # Process the post event
95
+ self.post.process_tx(smt, **kwargs)
@@ -0,0 +1,97 @@
1
+ """
2
+ PriceCheckpoint module
3
+ """
4
+
5
+ from attrs import define, field
6
+ from ddx.common.transactions.event import Event
7
+ from ddx._rust.common import ProductSymbol
8
+ from ddx._rust.common.accounting import MarkPriceMetadata
9
+ from ddx._rust.common.state import DerivadexSMT, Price
10
+ from ddx._rust.common.state.keys import PriceKey
11
+ from ddx._rust.decimal import Decimal
12
+
13
+
14
+ @define(hash=True)
15
+ class PriceCheckpoint(Event):
16
+ """
17
+ Defines a PriceCheckpoint
18
+
19
+ A PriceCheckpoint is when a market registers an update to the
20
+ composite index price a perpetual is tracking along with the mark
21
+ price metadata component.
22
+
23
+ Attributes:
24
+ symbol (ProductSymbol): The symbol for the market this price update is for.
25
+ mark_price_metadata (MarkPriceMetadata): Mark price metadata used for calculating mark price
26
+ index_price_hash (str): Index price hash
27
+ index_price (Decimal): Composite index price (a weighted average across several oracle sources)
28
+ ordinal (int): The numerical sequence-identifying value for a PriceCheckpoint
29
+ time_value (int): Time value
30
+ request_index (int): Sequenced request index of transaction
31
+ """
32
+
33
+ symbol: ProductSymbol
34
+ mark_price_metadata: MarkPriceMetadata = field(hash=False)
35
+ index_price_hash: str = field(eq=str.lower)
36
+ index_price: Decimal = field(hash=False)
37
+ ordinal: int = field(hash=False)
38
+ time_value: int
39
+ request_index: int = field(default=-1, eq=False, hash=False)
40
+
41
+ def is_void(self):
42
+ return self.index_price == Decimal("0")
43
+
44
+ @property
45
+ def mark_price(self) -> Decimal:
46
+ if isinstance(self.mark_price_metadata, MarkPriceMetadata.Ema):
47
+ mark_price = min(
48
+ self.index_price * Decimal("1.005"),
49
+ max(
50
+ self.index_price * Decimal("0.995"),
51
+ self.index_price + self.mark_price_metadata.ema,
52
+ ),
53
+ ).recorded_amount()
54
+ elif (
55
+ isinstance(self.mark_price_metadata,
56
+ MarkPriceMetadata.Average) is not None
57
+ ):
58
+ mark_price = (self.index_price + self.mark_price_metadata.accum) / (
59
+ self.mark_price_metadata.count + 1
60
+ )
61
+ else:
62
+ raise ValueError("Invalid MarkPriceMetadata type")
63
+ return mark_price.recorded_amount()
64
+
65
+ def process_tx(
66
+ self,
67
+ smt: DerivadexSMT,
68
+ **kwargs,
69
+ ):
70
+ """
71
+ Process a PriceCheckpoint transaction. A PriceCheckpoint
72
+ consists of information relating to a new price checkpoint,
73
+ such as the symbol, composite index price, and mark price
74
+ metadata. This will update the Price leaf in the SMT.
75
+
76
+ Parameters
77
+ ----------
78
+ smt: DerivadexSMT
79
+ DerivaDEX Sparse Merkle Tree
80
+ **kwargs
81
+ Additional args specific to PriceCheckpoint transactions
82
+ """
83
+ price_key = PriceKey(self.symbol, self.index_price_hash)
84
+ price = Price(
85
+ self.index_price,
86
+ self.mark_price_metadata,
87
+ self.ordinal,
88
+ self.time_value,
89
+ )
90
+ smt.store_price(price_key, price)
91
+
92
+ # Update latest price leaves abstraction with the new price
93
+ # checkpoint data
94
+ kwargs["latest_price_leaves"][self.symbol] = (
95
+ price_key,
96
+ price,
97
+ )
@@ -0,0 +1,62 @@
1
+ """
2
+ Signer Registered 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, Signer
8
+ from ddx._rust.common.state.keys import SignerKey
9
+
10
+
11
+ @define
12
+ class SignerRegistered(Event):
13
+ """
14
+ Defines a SignerRegistered
15
+
16
+ A SignerRegistered is when a new enclave signer registers with the smart contract
17
+
18
+ Attributes:
19
+ signer_address (str): The signer address component of the signer key pertaining to the SignerRegistered tx.
20
+ release_hash (str): The release hash component of the signer key pertaining to the SignerRegistered tx.
21
+ """
22
+
23
+ signer_address: str = field(eq=str.lower)
24
+ release_hash: str = field(eq=str.lower)
25
+
26
+ @classmethod
27
+ def decode_value_into_cls(cls, raw_tx_log_event: dict):
28
+ """
29
+ Decode a raw transaction log event (dict) into a SignerRegistered
30
+ instance.
31
+
32
+ Parameters
33
+ ----------
34
+ raw_tx_log_event : dict
35
+ Raw transaction log event being processed
36
+ """
37
+
38
+ event = raw_tx_log_event["event"]["c"]
39
+
40
+ return cls(
41
+ event["signerAddress"],
42
+ event["releaseHash"],
43
+ )
44
+
45
+ def process_tx(
46
+ self,
47
+ smt: DerivadexSMT,
48
+ **kwargs,
49
+ ):
50
+ """
51
+ Process a SignerRegistered, inserting the signer into the tree
52
+
53
+ Parameters
54
+ ----------
55
+ smt: DerivadexSMT
56
+ DerivaDEX Sparse Merkle Tree
57
+ **kwargs
58
+ Additional args specific to SignerRegistered transactions
59
+ """
60
+ signer = Signer(self.release_hash)
61
+
62
+ smt.store_signer(SignerKey(self.signer_address), signer)
@@ -0,0 +1,61 @@
1
+ """
2
+ SpecsUpdate module
3
+ """
4
+
5
+ from attrs import define, field
6
+ from ddx.common.transactions.event import Event
7
+ from ddx._rust.common import ProductSymbol
8
+ from ddx._rust.common.specs import SpecsKind
9
+ from ddx._rust.common.state import Specs
10
+ from ddx._rust.common.state.keys import SpecsKey
11
+ from ddx._rust.decimal import Decimal
12
+
13
+
14
+ # TODO: test usage
15
+ @define
16
+ class SpecsUpdate(Event):
17
+ """
18
+ Defines an SpecsUpdate
19
+
20
+ An SpecsUpdate is a transaction that updates the market specs
21
+
22
+ Attributes:
23
+ key (SpecsKey): The key of the specs being updated
24
+ expr (Specs): The expression of the specs being updated
25
+ block_number (int): Block number of transaction
26
+ tx_hash (str): Transaction hash of on-chain action
27
+ request_index (int): Sequenced request index of transaction
28
+ """
29
+
30
+ key: SpecsKey
31
+ expr: Specs
32
+ block_number: int
33
+ tx_hash: str = field(eq=str.lower)
34
+ request_index: int = field(default=-1, eq=False)
35
+
36
+ @classmethod
37
+ def decode_value_into_cls(cls, raw_tx_log_event: dict):
38
+ """
39
+ Decode a raw transaction log event (dict) into a
40
+ SpecsUpdate instance.
41
+
42
+ Parameters
43
+ ----------
44
+ raw_tx_log_event : dict
45
+ Raw transaction log event being processed
46
+ """
47
+
48
+ specs_update_tx_event = raw_tx_log_event["event"]["c"]
49
+
50
+ return cls(
51
+ SpecsKey(
52
+ SpecsKind(specs_update_tx_event["key"]["kind"]),
53
+ specs_update_tx_event["key"]["name"],
54
+ ),
55
+ Specs(specs_update_tx_event["expr"]),
56
+ specs_update_tx_event["blockNumber"],
57
+ specs_update_tx_event["txHash"],
58
+ raw_tx_log_event["requestIndex"],
59
+ )
60
+
61
+ # TODO: process_tx
@@ -0,0 +1,158 @@
1
+ """
2
+ Strategy Update module
3
+ """
4
+
5
+ from typing import Optional
6
+
7
+ from attrs import define, field
8
+ from ddx.common.transactions.event import Event
9
+ from ddx.common.utils import calculate_max_collateral
10
+ from ddx._rust.common import TokenSymbol
11
+ from ddx._rust.common.state import DerivadexSMT, Strategy, Trader
12
+ from ddx._rust.common.state.keys import StrategyKey, TraderKey
13
+ from ddx._rust.common.transactions import StrategyUpdateKind
14
+ from ddx._rust.decimal import Decimal
15
+
16
+
17
+ @define
18
+ class StrategyUpdate(Event):
19
+ """
20
+ Defines a Strategy Update
21
+
22
+ A StrategyUpdate is an update to a trader's strategy (such as
23
+ depositing or withdrawing collateral).
24
+
25
+ Attributes:
26
+ trader_address (str): Trader's Ethereum address this strategy belongs to
27
+ collateral_address (str): Collateral's Ethereum address a deposit/withdrawal has been made with
28
+ strategy_id_hash (str): Strategy ID hash for the given trader this event belongs to
29
+ strategy_id (Optional[str]): Strategy ID for the given trader this event belongs to. Only deposits will fill this field
30
+ amount (Decimal): The amount of collateral deposited or withdrawn
31
+ update_kind (StrategyUpdateKind): Update kind (Deposit=0, Withdraw=1)
32
+ tx_hash (str): The Ethereum transaction's hash
33
+ request_index (int): Sequenced request index of transaction
34
+ """
35
+
36
+ trader_address: str = field(eq=str.lower)
37
+ collateral_address: str = field(eq=str.lower)
38
+ strategy_id_hash: str = field(eq=str.lower)
39
+ strategy_id: Optional[str]
40
+ amount: Decimal
41
+ update_kind: StrategyUpdateKind
42
+ tx_hash: str = field(eq=str.lower)
43
+ request_index: int = field(default=-1, eq=False)
44
+
45
+ @classmethod
46
+ def decode_value_into_cls(cls, raw_tx_log_event: dict):
47
+ """
48
+ Decode a raw transaction log event (dict) into a StrategyUpdate
49
+ instance.
50
+
51
+ Parameters
52
+ ----------
53
+ raw_tx_log_event : dict
54
+ Raw transaction log event being processed
55
+ """
56
+
57
+ strategy_update_tx_event = raw_tx_log_event["event"]["c"]
58
+
59
+ return cls(
60
+ strategy_update_tx_event["trader"],
61
+ strategy_update_tx_event["collateralAddress"],
62
+ strategy_update_tx_event["strategyIdHash"],
63
+ strategy_update_tx_event.get("strategyId"),
64
+ Decimal(strategy_update_tx_event["amount"]),
65
+ StrategyUpdateKind(strategy_update_tx_event["updateKind"]),
66
+ strategy_update_tx_event["txHash"],
67
+ raw_tx_log_event["requestIndex"],
68
+ )
69
+
70
+ def process_tx(
71
+ self,
72
+ smt: DerivadexSMT,
73
+ **kwargs,
74
+ ):
75
+ """
76
+ Process a StrategyUpdate transaction. A StrategyUpdate consists
77
+ of information relating to updates for a trader's strategy, such
78
+ as when their free or frozen collateral has changed due to a
79
+ deposit or withdrawal. This will update the Strategy leaf in the
80
+ SMT.
81
+
82
+ Parameters
83
+ ----------
84
+ smt: DerivadexSMT
85
+ DerivaDEX Sparse Merkle Tree
86
+ **kwargs
87
+ Additional args specific to StrategyUpdate transactions
88
+ """
89
+
90
+ strategy_key: StrategyKey = StrategyKey(
91
+ self.trader_address, self.strategy_id_hash
92
+ )
93
+ strategy = smt.strategy(strategy_key)
94
+
95
+ symbol = TokenSymbol.from_address(self.collateral_address)
96
+ if self.update_kind == StrategyUpdateKind.Deposit:
97
+ # If StrategyUpdate is of deposit type
98
+
99
+ trader_key: TraderKey = TraderKey(self.trader_address)
100
+ trader = smt.trader(trader_key)
101
+
102
+ if strategy is None:
103
+ # If we haven't yet seen the Strategy leaf, create a new
104
+ # one
105
+ strategy = Strategy.default()
106
+
107
+ if trader is None:
108
+ # Initialize a new Trader Leaf
109
+ trader = Trader.default()
110
+
111
+ smt.store_trader(trader_key, trader)
112
+
113
+ # Compute max allowable deposit given the collateral guard
114
+ # for the trader's DDX balance
115
+ max_allowable_deposit = max(
116
+ (
117
+ calculate_max_collateral(
118
+ kwargs["collateral_tranches"], trader.avail_ddx_balance
119
+ )
120
+ - strategy.avail_collateral.total_value()
121
+ ),
122
+ Decimal("0"),
123
+ )
124
+
125
+ # Compute how much of the attempted deposit will be added
126
+ # to the Strategy's free collateral
127
+ net = min(max_allowable_deposit, self.amount)
128
+
129
+ # Increment the Strategy's free collateral
130
+ strategy.set_avail_collateral(
131
+ symbol,
132
+ strategy.avail_collateral[symbol] + net,
133
+ )
134
+
135
+ # Compute how much of the attempted deposit will be added
136
+ # to the Strategy's frozen collateral
137
+ kickback = self.amount - net
138
+ if kickback != Decimal("0"):
139
+ # Increment the Strategy's frozen collateral
140
+ strategy.set_locked_collateral(
141
+ symbol,
142
+ strategy.locked_collateral[symbol] + kickback,
143
+ )
144
+ elif self.update_kind == StrategyUpdateKind.Withdraw:
145
+ # If StrategyUpdate is of withdrawal (claimed) type
146
+ if strategy is None or strategy.locked_collateral[symbol] < self.amount:
147
+ raise Exception(
148
+ "Strategy leaf either non-existent or insufficiently capitalized to facilitate withdrawal"
149
+ )
150
+
151
+ # Adjust the existing strategy leaf by decrementing the
152
+ # free collateral by the amount in the withdrawal event
153
+ strategy.set_locked_collateral(
154
+ symbol,
155
+ strategy.locked_collateral[symbol] - self.amount,
156
+ )
157
+
158
+ smt.store_strategy(strategy_key, strategy)
@@ -0,0 +1,98 @@
1
+ """
2
+ Tradable Product Update module
3
+ """
4
+
5
+ from attrs import define, field
6
+ from ddx.common.transactions.event import Event
7
+ from ddx._rust.common.specs import SpecsKind
8
+ from ddx._rust.common.state import (DerivadexSMT, TradableProduct,
9
+ TradableProductParameters)
10
+ from ddx._rust.common.state.keys import SpecsKey, TradableProductKey
11
+
12
+
13
+ @define
14
+ class TradableProductUpdate(Event):
15
+ """
16
+ Defines a Tradable Product Update
17
+
18
+ A TradableProductUpdate is an update to a trader's strategy (such as depositing or withdrawing collateral).
19
+
20
+ Attributes:
21
+ additions (list[TradableProductKey]): List of tradable product keys that are marked tradable
22
+ removals (list[TradableProductKey]): List of tradable product keys that are marked untradable
23
+ request_index (int): Sequenced request index of transaction
24
+ """
25
+
26
+ additions: list[TradableProductKey]
27
+ removals: list[TradableProductKey]
28
+ request_index: int = field(default=-1, eq=False, hash=False)
29
+
30
+ @classmethod
31
+ def decode_value_into_cls(cls, raw_tx_log_event: dict):
32
+ """
33
+ Decode a raw transaction log event (dict) into a StrategyUpdate
34
+ instance.
35
+
36
+ Parameters
37
+ ----------
38
+ raw_tx_log_event : dict
39
+ Raw transaction log event being processed
40
+ """
41
+
42
+ tradable_product_update_tx_event = raw_tx_log_event["event"]["c"]
43
+
44
+ return cls(
45
+ [
46
+ TradableProductKey(
47
+ SpecsKey(
48
+ SpecsKind(tradable_product_key["specsKey"]["kind"]),
49
+ tradable_product_key["specsKey"]["name"],
50
+ ),
51
+ TradableProductParameters.from_dict(
52
+ tradable_product_key["parameters"]
53
+ ),
54
+ )
55
+ for tradable_product_key in tradable_product_update_tx_event[
56
+ "additions"
57
+ ]
58
+ ],
59
+ [
60
+ TradableProductKey(
61
+ SpecsKey(
62
+ SpecsKind(tradable_product_key["specsKey"]["kind"]),
63
+ tradable_product_key["specsKey"]["name"],
64
+ ),
65
+ TradableProductParameters.from_dict(
66
+ tradable_product_key["parameters"]
67
+ ),
68
+ )
69
+ for tradable_product_key in tradable_product_update_tx_event["removals"]
70
+ ],
71
+ raw_tx_log_event["requestIndex"],
72
+ )
73
+
74
+ def process_tx(
75
+ self,
76
+ smt: DerivadexSMT,
77
+ **kwargs,
78
+ ):
79
+ """
80
+ Process a TradableProductUpdate transaction. A TradableProductUpdate consists
81
+ of information relating to updates of the list of tradable products.
82
+
83
+ Parameters
84
+ ----------
85
+ smt: DerivadexSMT
86
+ DerivaDEX Sparse Merkle Tree
87
+ **kwargs
88
+ Additional args specific to TradableProductUpdate transactions
89
+ """
90
+
91
+ for tradable_product_key in self.additions:
92
+ smt.store_tradable_product(
93
+ tradable_product_key,
94
+ TradableProduct(),
95
+ )
96
+
97
+ for tradable_product_key in self.removals:
98
+ smt.store_tradable_product(tradable_product_key, None)