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,292 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TradeFill module
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
|
|
7
|
+
from attrs import define, field
|
|
8
|
+
from ddx.common.transactions.inner.fill import Fill
|
|
9
|
+
from ddx.common.transactions.inner.outcome import Outcome
|
|
10
|
+
from ddx._rust.common import ProductSymbol, TokenSymbol
|
|
11
|
+
from ddx._rust.common.enums import OrderSide
|
|
12
|
+
from ddx._rust.common.state import DerivadexSMT, Price
|
|
13
|
+
from ddx._rust.common.state.keys import (
|
|
14
|
+
BookOrderKey,
|
|
15
|
+
EpochMetadataKey,
|
|
16
|
+
InsuranceFundKey,
|
|
17
|
+
PriceKey,
|
|
18
|
+
StrategyKey,
|
|
19
|
+
TraderKey,
|
|
20
|
+
)
|
|
21
|
+
from ddx._rust.decimal import Decimal
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
AFFILIATE_STANDARD_L1 = Decimal("0.10")
|
|
25
|
+
AFFILIATE_STANDARD_L2 = Decimal("0.05")
|
|
26
|
+
AFFILIATE_STANDARD_REBATE = Decimal("0.10")
|
|
27
|
+
AFFILIATE_PREMIUM_L1 = Decimal("0.20")
|
|
28
|
+
AFFILIATE_PREMIUM_L2 = Decimal("0.10")
|
|
29
|
+
AFFILIATE_PREMIUM_REBATE = Decimal("0.20")
|
|
30
|
+
AFFILIATE_STANDARD_MIN_DDX = Decimal("1_000")
|
|
31
|
+
AFFILIATE_PREMIUM_MIN_DDX = Decimal("10_000")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _affiliate_schedule_for(trader):
|
|
35
|
+
if trader is None:
|
|
36
|
+
return None
|
|
37
|
+
stake = trader.avail_ddx_balance + trader.locked_ddx_balance
|
|
38
|
+
if stake >= AFFILIATE_PREMIUM_MIN_DDX:
|
|
39
|
+
return (AFFILIATE_PREMIUM_L1, AFFILIATE_PREMIUM_L2, AFFILIATE_PREMIUM_REBATE)
|
|
40
|
+
if stake >= AFFILIATE_STANDARD_MIN_DDX:
|
|
41
|
+
return (
|
|
42
|
+
AFFILIATE_STANDARD_L1,
|
|
43
|
+
AFFILIATE_STANDARD_L2,
|
|
44
|
+
AFFILIATE_STANDARD_REBATE,
|
|
45
|
+
)
|
|
46
|
+
return None
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _resolve_affiliate_chain(smt: DerivadexSMT, taker_address: str):
|
|
50
|
+
taker = smt.trader(TraderKey(taker_address))
|
|
51
|
+
if taker is None:
|
|
52
|
+
return (None, None, None, None)
|
|
53
|
+
l1 = taker.referral_address
|
|
54
|
+
l1_trader = smt.trader(TraderKey(l1)) if l1 is not None else None
|
|
55
|
+
l2 = None
|
|
56
|
+
l2_trader = None
|
|
57
|
+
if l1_trader is not None and l1_trader.referral_address is not None:
|
|
58
|
+
l2 = l1_trader.referral_address
|
|
59
|
+
l2_trader = smt.trader(TraderKey(l2))
|
|
60
|
+
return (l1, l1_trader, l2, l2_trader)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _compute_affiliate_split(
|
|
64
|
+
total_fee: Decimal,
|
|
65
|
+
l1_schedule,
|
|
66
|
+
l2_schedule,
|
|
67
|
+
l1_exists: bool,
|
|
68
|
+
l2_exists: bool,
|
|
69
|
+
taker_schedule,
|
|
70
|
+
):
|
|
71
|
+
if total_fee == Decimal("0"):
|
|
72
|
+
return {
|
|
73
|
+
"platform": Decimal("0"),
|
|
74
|
+
"l1": Decimal("0"),
|
|
75
|
+
"l2": Decimal("0"),
|
|
76
|
+
"rebate": Decimal("0"),
|
|
77
|
+
}
|
|
78
|
+
l1 = total_fee * l1_schedule[0] if l1_exists and l1_schedule else Decimal("0")
|
|
79
|
+
l2 = total_fee * l2_schedule[1] if l2_exists and l2_schedule else Decimal("0")
|
|
80
|
+
# TODO: in alpha1 where there are 100 traders, they always get the taker rebate
|
|
81
|
+
if l1_exists and l1_schedule:
|
|
82
|
+
rebate = total_fee * l1_schedule[2]
|
|
83
|
+
elif taker_schedule:
|
|
84
|
+
rebate = total_fee * taker_schedule[2]
|
|
85
|
+
else:
|
|
86
|
+
rebate = Decimal("0")
|
|
87
|
+
platform = total_fee - (l1 + l2 + rebate)
|
|
88
|
+
return {"platform": platform, "l1": l1, "l2": l2, "rebate": rebate}
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _credit_affiliate_usdc(smt: DerivadexSMT, trader_address: str, amount: Decimal):
|
|
92
|
+
if amount == Decimal("0"):
|
|
93
|
+
return
|
|
94
|
+
strategy_key = StrategyKey(
|
|
95
|
+
trader_address, StrategyKey.generate_strategy_id_hash("main")
|
|
96
|
+
)
|
|
97
|
+
strategy = smt.strategy(strategy_key)
|
|
98
|
+
if strategy is None:
|
|
99
|
+
return
|
|
100
|
+
strategy.set_avail_collateral(
|
|
101
|
+
TokenSymbol.USDC,
|
|
102
|
+
(strategy.avail_collateral[TokenSymbol.USDC] + amount).recorded_amount(),
|
|
103
|
+
)
|
|
104
|
+
smt.store_strategy(strategy_key, strategy)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _credit_affiliate_ddx(smt: DerivadexSMT, trader_address: str, amount: Decimal):
|
|
108
|
+
if amount == Decimal("0"):
|
|
109
|
+
return
|
|
110
|
+
trader = smt.trader(TraderKey(trader_address))
|
|
111
|
+
if trader is None:
|
|
112
|
+
return
|
|
113
|
+
trader.avail_ddx_balance = (
|
|
114
|
+
trader.avail_ddx_balance + amount
|
|
115
|
+
).recorded_amount()
|
|
116
|
+
smt.store_trader(TraderKey(trader_address), trader)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
@define(hash=True)
|
|
120
|
+
class TradeFill(Fill):
|
|
121
|
+
"""
|
|
122
|
+
Defines a TradeFill
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
maker_order_hash: str = field(eq=str.lower)
|
|
126
|
+
maker_outcome: Outcome = field(hash=False)
|
|
127
|
+
maker_order_remaining_amount: Decimal = field(hash=False)
|
|
128
|
+
taker_order_hash: str = field(eq=str.lower)
|
|
129
|
+
taker_outcome: Outcome = field(hash=False)
|
|
130
|
+
request_index: int = field(default=-1, eq=False, hash=False)
|
|
131
|
+
|
|
132
|
+
def __init__(
|
|
133
|
+
self,
|
|
134
|
+
symbol: ProductSymbol,
|
|
135
|
+
taker_order_hash: str,
|
|
136
|
+
maker_order_hash: str,
|
|
137
|
+
maker_order_remaining_amount: Decimal,
|
|
138
|
+
amount: Decimal,
|
|
139
|
+
price: Decimal,
|
|
140
|
+
taker_side: OrderSide,
|
|
141
|
+
maker_outcome: Outcome,
|
|
142
|
+
taker_outcome: Outcome,
|
|
143
|
+
time_value: int,
|
|
144
|
+
request_index: int = -1,
|
|
145
|
+
):
|
|
146
|
+
"""
|
|
147
|
+
Initialize a TradeFill instance
|
|
148
|
+
Parameters
|
|
149
|
+
----------
|
|
150
|
+
symbol : ProductSymbol
|
|
151
|
+
Product symbol
|
|
152
|
+
taker_order_hash : str
|
|
153
|
+
Taker order hash
|
|
154
|
+
maker_order_hash : str
|
|
155
|
+
Maker order hash
|
|
156
|
+
maker_order_remaining_amount : Decimal
|
|
157
|
+
Maker order remaining amount
|
|
158
|
+
amount : Decimal
|
|
159
|
+
Amount
|
|
160
|
+
price : Decimal
|
|
161
|
+
Price
|
|
162
|
+
taker_side : OrderSide
|
|
163
|
+
Taker side
|
|
164
|
+
maker_outcome : Outcome
|
|
165
|
+
Maker outcome
|
|
166
|
+
taker_outcome : Outcome
|
|
167
|
+
Taker outcome
|
|
168
|
+
time_value : int
|
|
169
|
+
Time value
|
|
170
|
+
request_index : int
|
|
171
|
+
Request index
|
|
172
|
+
"""
|
|
173
|
+
super().__init__(
|
|
174
|
+
symbol,
|
|
175
|
+
amount,
|
|
176
|
+
price,
|
|
177
|
+
taker_side,
|
|
178
|
+
time_value,
|
|
179
|
+
request_index,
|
|
180
|
+
)
|
|
181
|
+
self.maker_order_hash = maker_order_hash
|
|
182
|
+
self.maker_outcome = maker_outcome
|
|
183
|
+
self.maker_order_remaining_amount = maker_order_remaining_amount
|
|
184
|
+
self.taker_order_hash = taker_order_hash
|
|
185
|
+
self.taker_outcome = taker_outcome
|
|
186
|
+
|
|
187
|
+
def process_tx(
|
|
188
|
+
self,
|
|
189
|
+
smt: DerivadexSMT,
|
|
190
|
+
**kwargs,
|
|
191
|
+
):
|
|
192
|
+
"""
|
|
193
|
+
Process a TradeFill transaction. These are Fill transactions
|
|
194
|
+
that have risen from either a CompleteFill or a PartialFill
|
|
195
|
+
transaction.
|
|
196
|
+
|
|
197
|
+
Parameters
|
|
198
|
+
----------
|
|
199
|
+
smt: DerivadexSMT
|
|
200
|
+
DerivaDEX Sparse Merkle Tree
|
|
201
|
+
**kwargs
|
|
202
|
+
Additional args specific to CompleteFill/PartialFill transactions
|
|
203
|
+
"""
|
|
204
|
+
|
|
205
|
+
maker_book_order_key: BookOrderKey = BookOrderKey(
|
|
206
|
+
self.symbol, self.maker_order_hash
|
|
207
|
+
)
|
|
208
|
+
maker_book_order = smt.book_order(maker_book_order_key)
|
|
209
|
+
maker_book_order_time_value = maker_book_order.time_value
|
|
210
|
+
|
|
211
|
+
maker_book_order.amount = self.maker_order_remaining_amount
|
|
212
|
+
smt.store_book_order(maker_book_order_key, maker_book_order)
|
|
213
|
+
|
|
214
|
+
# Make the appropriate adjustments for both the maker and taker
|
|
215
|
+
# components of the Trade
|
|
216
|
+
self.adjust_for_maker(
|
|
217
|
+
smt,
|
|
218
|
+
kwargs["epoch_id"],
|
|
219
|
+
kwargs["trade_mining_active"],
|
|
220
|
+
maker_book_order_time_value,
|
|
221
|
+
reconcile_fees=False,
|
|
222
|
+
)
|
|
223
|
+
self.adjust_for_taker(
|
|
224
|
+
smt,
|
|
225
|
+
kwargs["epoch_id"],
|
|
226
|
+
kwargs["trade_mining_active"],
|
|
227
|
+
maker_book_order_time_value,
|
|
228
|
+
reconcile_fees=False,
|
|
229
|
+
)
|
|
230
|
+
self._reconcile_fees(
|
|
231
|
+
smt,
|
|
232
|
+
kwargs["epoch_id"],
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
def _reconcile_fees(self, smt: DerivadexSMT, epoch_id: int):
|
|
236
|
+
fees_default, fees_ddx = Decimal("0"), Decimal("0")
|
|
237
|
+
for outcome in (self.maker_outcome, self.taker_outcome):
|
|
238
|
+
if outcome.fee > Decimal("0"):
|
|
239
|
+
if outcome.pay_fee_in_ddx:
|
|
240
|
+
fees_ddx += outcome.fee
|
|
241
|
+
else:
|
|
242
|
+
fees_default += outcome.fee
|
|
243
|
+
|
|
244
|
+
l1 = l2 = l1_trader = l2_trader = None
|
|
245
|
+
if self.taker_outcome is not None:
|
|
246
|
+
l1, l1_trader, l2, l2_trader = _resolve_affiliate_chain(
|
|
247
|
+
smt, self.taker_outcome.trader
|
|
248
|
+
)
|
|
249
|
+
l1_schedule = _affiliate_schedule_for(l1_trader)
|
|
250
|
+
l2_schedule = _affiliate_schedule_for(l2_trader)
|
|
251
|
+
taker = smt.trader(TraderKey(self.taker_outcome.trader))
|
|
252
|
+
taker_schedule = _affiliate_schedule_for(taker)
|
|
253
|
+
|
|
254
|
+
if fees_default > Decimal("0"):
|
|
255
|
+
split = _compute_affiliate_split(
|
|
256
|
+
fees_default, l1_schedule, l2_schedule, l1 is not None, l2 is not None, taker_schedule
|
|
257
|
+
)
|
|
258
|
+
if l1 is not None:
|
|
259
|
+
_credit_affiliate_usdc(smt, l1, split["l1"])
|
|
260
|
+
if l2 is not None:
|
|
261
|
+
_credit_affiliate_usdc(smt, l2, split["l2"])
|
|
262
|
+
if self.taker_outcome is not None:
|
|
263
|
+
_credit_affiliate_usdc(
|
|
264
|
+
smt, self.taker_outcome.trader, split["rebate"]
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
insurance_fund_key = InsuranceFundKey()
|
|
268
|
+
insurance_fund = smt.insurance_fund(insurance_fund_key)
|
|
269
|
+
insurance_fund[TokenSymbol.USDC] = (
|
|
270
|
+
insurance_fund[TokenSymbol.USDC] + split["platform"]
|
|
271
|
+
).recorded_amount()
|
|
272
|
+
smt.store_insurance_fund(insurance_fund_key, insurance_fund)
|
|
273
|
+
|
|
274
|
+
if fees_ddx > Decimal("0"):
|
|
275
|
+
split = _compute_affiliate_split(
|
|
276
|
+
fees_ddx, l1_schedule, l2_schedule, l1 is not None, l2 is not None, taker_schedule
|
|
277
|
+
)
|
|
278
|
+
if l1 is not None:
|
|
279
|
+
_credit_affiliate_ddx(smt, l1, split["l1"])
|
|
280
|
+
if l2 is not None:
|
|
281
|
+
_credit_affiliate_ddx(smt, l2, split["l2"])
|
|
282
|
+
if self.taker_outcome is not None:
|
|
283
|
+
_credit_affiliate_ddx(
|
|
284
|
+
smt, self.taker_outcome.trader, split["rebate"]
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
epoch_metadata_key = EpochMetadataKey(epoch_id)
|
|
288
|
+
epoch_metadata = smt.epoch_metadata(epoch_metadata_key)
|
|
289
|
+
epoch_metadata.ddx_fee_pool = (
|
|
290
|
+
epoch_metadata.ddx_fee_pool + split["platform"]
|
|
291
|
+
).recorded_amount()
|
|
292
|
+
smt.store_epoch_metadata(epoch_metadata_key, epoch_metadata)
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"""
|
|
2
|
+
InsuranceFundUpdate
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from attrs import define, field
|
|
6
|
+
from ddx.common.transactions.event import Event
|
|
7
|
+
from ddx._rust.common import TokenSymbol
|
|
8
|
+
from ddx._rust.common.state import DerivadexSMT, InsuranceFundContribution
|
|
9
|
+
from ddx._rust.common.state.keys import InsuranceFundContributionKey, InsuranceFundKey
|
|
10
|
+
from ddx._rust.common.transactions import InsuranceFundUpdateKind
|
|
11
|
+
from ddx._rust.decimal import Decimal
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@define
|
|
15
|
+
class InsuranceFundUpdate(Event):
|
|
16
|
+
"""
|
|
17
|
+
Defines an InsuranceFundUpdate
|
|
18
|
+
|
|
19
|
+
An InsuranceFundUpdate is an update to a trader's insurance fund
|
|
20
|
+
contribution (such as depositing or withdrawing
|
|
21
|
+
collateral).
|
|
22
|
+
|
|
23
|
+
Attributes:
|
|
24
|
+
address (str): Trader's Ethereum address this insurance fund update belongs to
|
|
25
|
+
collateral_address (str): Collateral's Ethereum address a deposit/withdrawal has been made with
|
|
26
|
+
amount (Decimal): The amount of collateral deposited or withdrawn
|
|
27
|
+
update_kind (InsuranceFundUpdateKind): Update kind (Deposit=0, Withdraw=1)
|
|
28
|
+
tx_hash (str): The Ethereum transaction's hash
|
|
29
|
+
request_index (int): Sequenced request index of transaction
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
address: str = field(eq=str.lower)
|
|
33
|
+
collateral_address: str = field(eq=str.lower)
|
|
34
|
+
amount: Decimal
|
|
35
|
+
update_kind: InsuranceFundUpdateKind
|
|
36
|
+
tx_hash: str = field(eq=str.lower)
|
|
37
|
+
request_index: int = field(default=-1, eq=False)
|
|
38
|
+
|
|
39
|
+
@classmethod
|
|
40
|
+
def decode_value_into_cls(cls, raw_tx_log_event: dict):
|
|
41
|
+
"""
|
|
42
|
+
Decode a raw transaction log event (dict) into an
|
|
43
|
+
InsuranceFundUpdate instance.
|
|
44
|
+
|
|
45
|
+
Parameters
|
|
46
|
+
----------
|
|
47
|
+
raw_tx_log_event : dict
|
|
48
|
+
Raw transaction log event being processed
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
insurance_fund_update_tx_event = raw_tx_log_event["event"]["c"]
|
|
52
|
+
|
|
53
|
+
return cls(
|
|
54
|
+
insurance_fund_update_tx_event["address"],
|
|
55
|
+
insurance_fund_update_tx_event["collateralAddress"],
|
|
56
|
+
Decimal(insurance_fund_update_tx_event["amount"]),
|
|
57
|
+
InsuranceFundUpdateKind(insurance_fund_update_tx_event["updateKind"]),
|
|
58
|
+
insurance_fund_update_tx_event["txHash"],
|
|
59
|
+
raw_tx_log_event["requestIndex"],
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
def process_tx(
|
|
63
|
+
self,
|
|
64
|
+
smt: DerivadexSMT,
|
|
65
|
+
**kwargs,
|
|
66
|
+
):
|
|
67
|
+
"""
|
|
68
|
+
Process an InsuranceFundUpdate transaction. An
|
|
69
|
+
InsuranceFundUpdate consists of information relating to updates
|
|
70
|
+
for a trader's insurance fund contribution, such
|
|
71
|
+
as when their free or frozen balance has changed due to a
|
|
72
|
+
deposit or withdrawal. This will update the
|
|
73
|
+
InsuranceFundContribution leaf in the SMT.
|
|
74
|
+
|
|
75
|
+
Parameters
|
|
76
|
+
----------
|
|
77
|
+
smt: DerivadexSMT
|
|
78
|
+
DerivaDEX Sparse Merkle Tree
|
|
79
|
+
**kwargs
|
|
80
|
+
Additional args specific to InsuranceFundUpdate transactions
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
insurance_fund_contribution_key: InsuranceFundContributionKey = (
|
|
84
|
+
InsuranceFundContributionKey(self.address)
|
|
85
|
+
)
|
|
86
|
+
insurance_fund_contribution = smt.insurance_fund_contribution(
|
|
87
|
+
insurance_fund_contribution_key
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
symbol = TokenSymbol.from_address(self.collateral_address)
|
|
91
|
+
if self.update_kind == InsuranceFundUpdateKind.Deposit:
|
|
92
|
+
# If InsuranceFundUpdate is of deposit type
|
|
93
|
+
|
|
94
|
+
if insurance_fund_contribution is None:
|
|
95
|
+
# If we haven't yet seen the InsuranceFundContribution
|
|
96
|
+
# leaf, create a new one
|
|
97
|
+
insurance_fund_contribution = InsuranceFundContribution.default()
|
|
98
|
+
|
|
99
|
+
# Adjust the existing strategy leaf by incrementing the
|
|
100
|
+
# free collateral by the amount in the deposit event
|
|
101
|
+
insurance_fund_contribution.set_avail_balance(
|
|
102
|
+
symbol,
|
|
103
|
+
insurance_fund_contribution.avail_balance[symbol] + self.amount,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
insurance_fund_key: InsuranceFundKey = InsuranceFundKey()
|
|
107
|
+
insurance_fund = smt.insurance_fund(insurance_fund_key)
|
|
108
|
+
|
|
109
|
+
insurance_fund[symbol] += self.amount
|
|
110
|
+
|
|
111
|
+
# Update the SMT with the H256 repr of the key and the
|
|
112
|
+
# InsuranceFundContribution leaf
|
|
113
|
+
smt.store_insurance_fund_contribution(
|
|
114
|
+
insurance_fund_contribution_key, insurance_fund_contribution
|
|
115
|
+
)
|
|
116
|
+
smt.store_insurance_fund(insurance_fund_key, insurance_fund)
|
|
117
|
+
elif self.update_kind == InsuranceFundUpdateKind.Withdraw:
|
|
118
|
+
# If InsuranceFundUpdate is of withdrawal (claimed) type
|
|
119
|
+
if (
|
|
120
|
+
insurance_fund_contribution is None
|
|
121
|
+
or insurance_fund_contribution.locked_balance[symbol] < self.amount
|
|
122
|
+
):
|
|
123
|
+
raise Exception(
|
|
124
|
+
"InsuranceFundContribution leaf either non-existent or insufficiently capitalized to facilitate withdrawal"
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
# Adjust the existing InsuranceFundContribution leaf by decrementing the
|
|
128
|
+
# locked balance by the amount in the withdrawal event
|
|
129
|
+
insurance_fund_contribution.set_locked_balance(
|
|
130
|
+
symbol,
|
|
131
|
+
insurance_fund_contribution.locked_balance[symbol] - self.amount,
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
# Update the SMT with the H256 repr of the key and the
|
|
135
|
+
# Strategy leaf
|
|
136
|
+
smt.store_insurance_fund_contribution(
|
|
137
|
+
insurance_fund_contribution_key, insurance_fund_contribution
|
|
138
|
+
)
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"""
|
|
2
|
+
InsuranceFundWithdraw module
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from attrs import define, field
|
|
6
|
+
from ddx.common.transactions.event import Event
|
|
7
|
+
from ddx._rust.common import TokenSymbol
|
|
8
|
+
from ddx._rust.common.state import DerivadexSMT, InsuranceFundContribution
|
|
9
|
+
from ddx._rust.common.state.keys import InsuranceFundContributionKey, InsuranceFundKey
|
|
10
|
+
from ddx._rust.decimal import Decimal
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@define
|
|
14
|
+
class InsuranceFundWithdraw(Event):
|
|
15
|
+
"""
|
|
16
|
+
Defines an InsuranceFundWithdraw Update
|
|
17
|
+
|
|
18
|
+
An InsuranceFundWithdraw is when a withdrawal of collateral is **signaled**.
|
|
19
|
+
|
|
20
|
+
Attributes:
|
|
21
|
+
recipient_address (str): Trader address DDX is being withdrawn to
|
|
22
|
+
amount (Decimal): The amount of DDX being withdrawn
|
|
23
|
+
request_index (int): Sequenced request index of transaction
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
recipient_address: str = field(eq=str.lower)
|
|
27
|
+
currency: str = field(eq=str.lower)
|
|
28
|
+
amount: Decimal
|
|
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 a Withdraw
|
|
35
|
+
instance.
|
|
36
|
+
|
|
37
|
+
Parameters
|
|
38
|
+
----------
|
|
39
|
+
raw_tx_log_event : dict
|
|
40
|
+
Raw transaction log event being processed
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
insurance_fund_withdraw_tx_event = raw_tx_log_event["event"]["c"]
|
|
44
|
+
|
|
45
|
+
return cls(
|
|
46
|
+
insurance_fund_withdraw_tx_event["recipientAddress"],
|
|
47
|
+
insurance_fund_withdraw_tx_event["currency"],
|
|
48
|
+
Decimal(insurance_fund_withdraw_tx_event["amount"]),
|
|
49
|
+
raw_tx_log_event["requestIndex"],
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
def process_tx(
|
|
53
|
+
self,
|
|
54
|
+
smt: DerivadexSMT,
|
|
55
|
+
**kwargs,
|
|
56
|
+
):
|
|
57
|
+
"""
|
|
58
|
+
Process a Withdraw transaction. A Withdraw event consists
|
|
59
|
+
of consists of information relating to withdrawal of collateral.
|
|
60
|
+
|
|
61
|
+
Parameters
|
|
62
|
+
----------
|
|
63
|
+
smt: DerivadexSMT
|
|
64
|
+
DerivaDEX Sparse Merkle Tree
|
|
65
|
+
**kwargs
|
|
66
|
+
Additional args specific to InsuranceFundWithdraw transactions
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
insurance_fund_key: InsuranceFundKey = InsuranceFundKey()
|
|
70
|
+
insurance_fund = smt.insurance_fund(insurance_fund_key)
|
|
71
|
+
|
|
72
|
+
contributor_key: InsuranceFundContributionKey = InsuranceFundContributionKey(
|
|
73
|
+
self.recipient_address
|
|
74
|
+
)
|
|
75
|
+
contributor: InsuranceFundContribution = smt.insurance_fund_contribution(
|
|
76
|
+
contributor_key
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
# Decrement the free balance by the withdrawn amount
|
|
80
|
+
symbol = TokenSymbol.from_address(self.currency)
|
|
81
|
+
contributor.set_avail_balance(
|
|
82
|
+
symbol,
|
|
83
|
+
contributor.avail_balance[symbol] - self.amount,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
# Increment the frozen balance by the withdrawn amount
|
|
87
|
+
contributor.set_locked_balance(
|
|
88
|
+
symbol,
|
|
89
|
+
contributor.locked_balance[symbol] + self.amount,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
# Update the SMT with the H256 repr of the key and
|
|
93
|
+
# the InsuranceFundContribution leaf for the signer
|
|
94
|
+
smt.store_insurance_fund_contribution(contributor_key, contributor)
|
|
95
|
+
|
|
96
|
+
insurance_fund[symbol] -= self.amount
|
|
97
|
+
|
|
98
|
+
# Update the SMT with the H256 repr of the key and the
|
|
99
|
+
# Strategy leaf
|
|
100
|
+
smt.store_insurance_fund(insurance_fund_key, insurance_fund)
|