avantis-trader-sdk 0.8.2__py3-none-any.whl → 0.8.3__py3-none-any.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 (39) hide show
  1. avantis_trader_sdk/__init__.py +5 -5
  2. avantis_trader_sdk/abis/AggregatorV3Interface.json +606 -606
  3. avantis_trader_sdk/abis/IPyth.sol/IPyth.dbg.json +4 -4
  4. avantis_trader_sdk/abis/Referral.sol/ReferralStorage.json +7132 -7132
  5. avantis_trader_sdk/abis/Sanctions.json +190 -190
  6. avantis_trader_sdk/abis/USDC.sol/USDC.dbg.json +4 -4
  7. avantis_trader_sdk/abis/interfaces/ICallbacks.sol/ICallbacks.json +2637 -2637
  8. avantis_trader_sdk/abis/interfaces/IExecute.sol/IExecute.json +1628 -1628
  9. avantis_trader_sdk/abis/interfaces/IPairInfos.sol/IPairInfos.json +2781 -2781
  10. avantis_trader_sdk/abis/interfaces/IPairStorage.sol/IPairStorage.json +3729 -3729
  11. avantis_trader_sdk/abis/interfaces/IPriceAggregator.sol/IPriceAggregator.json +2330 -2330
  12. avantis_trader_sdk/abis/interfaces/IReferral.sol/IReferral.json +1890 -1890
  13. avantis_trader_sdk/abis/interfaces/ITradingStorage.sol/ITradingStorage.json +7022 -7022
  14. avantis_trader_sdk/abis/interfaces/ITranche.sol/ITranche.json +1283 -1283
  15. avantis_trader_sdk/abis/interfaces/IVaultManager.sol/IVaultManager.json +2424 -2424
  16. avantis_trader_sdk/abis/interfaces/IVeTranche.sol/IVeTranche.json +855 -855
  17. avantis_trader_sdk/abis/library/PositionMath.sol/PositionMath.dbg.json +4 -4
  18. avantis_trader_sdk/abis/library/PositionMath.sol/PositionMath.json +10 -10
  19. avantis_trader_sdk/abis/testnet/USDC.sol/USDC.dbg.json +4 -4
  20. avantis_trader_sdk/abis/testnet/USDC.sol/USDC.json +320 -320
  21. avantis_trader_sdk/client.py +369 -367
  22. avantis_trader_sdk/config.py +14 -14
  23. avantis_trader_sdk/feed/feed_client.py +263 -261
  24. avantis_trader_sdk/rpc/asset_parameters.py +499 -499
  25. avantis_trader_sdk/rpc/blended.py +71 -71
  26. avantis_trader_sdk/rpc/category_parameters.py +216 -216
  27. avantis_trader_sdk/rpc/fee_parameters.py +237 -237
  28. avantis_trader_sdk/rpc/pairs_cache.py +130 -130
  29. avantis_trader_sdk/rpc/rpc_helpers.py +8 -8
  30. avantis_trader_sdk/rpc/snapshot.py +142 -142
  31. avantis_trader_sdk/rpc/trade.py +701 -710
  32. avantis_trader_sdk/rpc/trading_parameters.py +139 -139
  33. avantis_trader_sdk/types.py +462 -462
  34. avantis_trader_sdk/utils.py +78 -78
  35. {avantis_trader_sdk-0.8.2.dist-info → avantis_trader_sdk-0.8.3.dist-info}/METADATA +124 -113
  36. {avantis_trader_sdk-0.8.2.dist-info → avantis_trader_sdk-0.8.3.dist-info}/RECORD +38 -39
  37. {avantis_trader_sdk-0.8.2.dist-info → avantis_trader_sdk-0.8.3.dist-info}/WHEEL +1 -1
  38. avantis_trader_sdk/feed/feedIds.json +0 -214
  39. {avantis_trader_sdk-0.8.2.dist-info → avantis_trader_sdk-0.8.3.dist-info}/top_level.txt +0 -0
@@ -1,710 +1,701 @@
1
- from ..types import (
2
- TradeInput,
3
- TradeInputOrderType,
4
- TradeExtendedResponse,
5
- TradeResponse,
6
- TradeInfo,
7
- PendingLimitOrderExtendedResponse,
8
- MarginUpdateType,
9
- )
10
- from typing import Optional
11
- import math
12
-
13
-
14
- class TradeRPC:
15
- """
16
- The TradeRPC class contains methods for retrieving trading parameters from the Avantis Protocol.
17
- """
18
-
19
- def __init__(self, client, FeedClient):
20
- """
21
- Constructor for the TradeRPC class.
22
-
23
- Args:
24
- client: The TraderClient object.
25
- FeedClient: The FeedClient object.
26
- """
27
- self.client = client
28
- self.FeedClient = FeedClient
29
-
30
- async def build_trade_open_tx(
31
- self,
32
- trade_input: TradeInput,
33
- trade_input_order_type: TradeInputOrderType,
34
- slippage_percentage: int,
35
- execution_fee: Optional[float] = None,
36
- ):
37
- """
38
- Builds a transaction to open a trade.
39
-
40
- Args:
41
- trade: The trade input object.
42
- trade_input_order_type: The trade input order type.
43
- slippage_percentage: The slippage percentage.
44
-
45
- Returns:
46
- A transaction object.
47
- """
48
- Trading = self.client.contracts.get("Trading")
49
-
50
- if (
51
- trade_input.trader == "0x1234567890123456789012345678901234567890"
52
- and self.client.get_signer() is not None
53
- ):
54
- trade_input.trader = await self.client.get_signer().get_ethereum_address()
55
-
56
- if execution_fee is not None:
57
- execution_fee_wei = int(execution_fee * 10**18)
58
- else:
59
- execution_fee_wei = await self.get_trade_execution_fee()
60
-
61
- if (
62
- trade_input_order_type == TradeInputOrderType.MARKET
63
- or trade_input_order_type == TradeInputOrderType.MARKET_ZERO_FEE
64
- ) and not trade_input.openPrice:
65
- feed_client = self.FeedClient()
66
-
67
- pair_name = await self.client.pairs_cache.get_pair_name_from_index(
68
- trade_input.pairIndex
69
- )
70
- price_data = await feed_client.get_latest_price_updates([pair_name])
71
- price = int(price_data.parsed[0].converted_price * 10**10)
72
- trade_input.openPrice = price
73
-
74
- if (
75
- trade_input_order_type == TradeInputOrderType.LIMIT
76
- or trade_input_order_type == TradeInputOrderType.STOP_LIMIT
77
- ) and not trade_input.openPrice:
78
- raise Exception("Open price is required for LIMIT/STOP LIMIT order type")
79
-
80
- transaction = await Trading.functions.openTrade(
81
- trade_input.model_dump(),
82
- trade_input_order_type.value,
83
- slippage_percentage * 10**10,
84
- ).build_transaction(
85
- {
86
- "from": trade_input.trader,
87
- "value": execution_fee_wei,
88
- "chainId": self.client.chain_id,
89
- "nonce": await self.client.get_transaction_count(trade_input.trader),
90
- }
91
- )
92
-
93
- return transaction
94
-
95
- async def build_trade_open_tx_delegate(
96
- self,
97
- trade_input: TradeInput,
98
- trade_input_order_type: TradeInputOrderType,
99
- slippage_percentage: int,
100
- execution_fee: Optional[float] = None,
101
- ):
102
- """
103
- Builds a transaction to open a trade.
104
-
105
- Args:
106
- trade: The trade input object.
107
- trade_input_order_type: The trade input order type.
108
- slippage_percentage: The slippage percentage.
109
-
110
- Returns:
111
- A transaction object.
112
- """
113
- Trading = self.client.contracts.get("Trading")
114
-
115
- if (
116
- trade_input.trader == "0x1234567890123456789012345678901234567890"
117
- and self.client.get_signer() is not None
118
- ):
119
- trade_input.trader = await self.client.get_signer().get_ethereum_address()
120
-
121
- if execution_fee is not None:
122
- execution_fee_wei = int(execution_fee * 10**18)
123
- else:
124
- execution_fee_wei = await self.get_trade_execution_fee()
125
-
126
- if (
127
- trade_input_order_type == TradeInputOrderType.MARKET
128
- or trade_input_order_type == TradeInputOrderType.MARKET_ZERO_FEE
129
- ) and not trade_input.openPrice:
130
- feed_client = self.FeedClient()
131
-
132
- pair_name = await self.client.pairs_cache.get_pair_name_from_index(
133
- trade_input.pairIndex
134
- )
135
- price_data = await feed_client.get_latest_price_updates([pair_name])
136
- price = int(price_data.parsed[0].converted_price * 10**10)
137
- trade_input.openPrice = price
138
-
139
- if (
140
- trade_input_order_type == TradeInputOrderType.LIMIT
141
- or trade_input_order_type == TradeInputOrderType.STOP_LIMIT
142
- ) and not trade_input.openPrice:
143
- raise Exception("Open price is required for LIMIT/STOP LIMIT order type")
144
-
145
- transaction = await Trading.functions.openTrade(
146
- trade_input.model_dump(),
147
- trade_input_order_type.value,
148
- slippage_percentage * 10**10,
149
- ).build_transaction(
150
- {
151
- "from": trade_input.trader,
152
- "value": 0,
153
- "chainId": self.client.chain_id,
154
- "nonce": await self.client.get_transaction_count(trade_input.trader),
155
- }
156
- )
157
-
158
- print("transaction: ", trade_input.trader)
159
-
160
- delegate_transaction = await Trading.functions.delegatedAction(
161
- trade_input.trader, transaction["data"]
162
- ).build_transaction(
163
- {
164
- "from": self.client.get_signer().get_ethereum_address(),
165
- "value": execution_fee_wei,
166
- "chainId": self.client.chain_id,
167
- "nonce": await self.client.get_transaction_count(
168
- self.client.get_signer().get_ethereum_address()
169
- ),
170
- }
171
- )
172
-
173
- return delegate_transaction
174
-
175
- async def get_trade_execution_fee(self):
176
- """
177
- Gets the correct trade execution fee.
178
-
179
- Returns:
180
- The trade execution fee
181
- """
182
- execution_fee = round(0.00035, 18) # default value
183
- execution_fee_wei = int(execution_fee * 10**18)
184
-
185
- try:
186
- feeScalar = 0.001
187
-
188
- estimatedL1Gas = math.floor(22676 * feeScalar)
189
- estimatedL2Gas = math.floor(850000 * 1.1)
190
-
191
- l2GasPrice = await self.client.async_web3.eth.gas_price
192
- estimatedL2GasEth = l2GasPrice * estimatedL2Gas
193
-
194
- l1GasPrice = await self.client.l1_async_web3.eth.gas_price
195
- estimatedL1GasEth = l1GasPrice * estimatedL1Gas
196
-
197
- feeEstimate = estimatedL1GasEth + estimatedL2GasEth
198
- feeEstimate = round(feeEstimate, 18)
199
- return feeEstimate
200
- except Exception as e:
201
- print("Error getting correct trade execution fee. Using fallback: ", e)
202
- return execution_fee_wei
203
-
204
- async def get_trades(self, trader: Optional[str] = None):
205
- """
206
- Gets the trades.
207
-
208
- Args:
209
- trader: The trader's wallet address.
210
-
211
- Returns:
212
- The trades.
213
- """
214
- if trader is None:
215
- trader = self.client.get_signer().get_ethereum_address()
216
-
217
- result = (
218
- await self.client.contracts.get("Multicall")
219
- .functions.getPositions(trader)
220
- .call()
221
- )
222
- trades = []
223
- pendingOpenLimitOrders = []
224
-
225
- for aggregated_trade in result[0]: # Access the list of aggregated trades
226
- (trade, trade_info, margin_fee, liquidation_price) = aggregated_trade
227
-
228
- if trade[7] <= 0:
229
- continue
230
-
231
- # Extract and format the trade data
232
- trade_details = {
233
- "trade": {
234
- "trader": trade[0],
235
- "pairIndex": trade[1],
236
- "index": trade[2],
237
- "initialPosToken": trade[3],
238
- "positionSizeUSDC": trade[4],
239
- "openPrice": trade[5],
240
- "buy": trade[6],
241
- "leverage": trade[7],
242
- "tp": trade[8],
243
- "sl": trade[9],
244
- "timestamp": trade[10],
245
- },
246
- "additional_info": {
247
- "openInterestUSDC": trade_info[0],
248
- "tpLastUpdated": trade_info[1],
249
- "slLastUpdated": trade_info[2],
250
- "beingMarketClosed": trade_info[3],
251
- "lossProtectionPercentage": await self.client.trading_parameters.get_loss_protection_percentage_by_tier(
252
- trade_info[4], trade[1]
253
- ),
254
- },
255
- "margin_fee": margin_fee,
256
- "liquidationPrice": liquidation_price,
257
- }
258
- trades.append(
259
- TradeExtendedResponse(
260
- trade=TradeResponse(**trade_details["trade"]),
261
- additional_info=TradeInfo(**trade_details["additional_info"]),
262
- margin_fee=trade_details["margin_fee"],
263
- liquidation_price=trade_details["liquidationPrice"],
264
- )
265
- )
266
-
267
- for aggregated_order in result[1]: # Access the list of aggregated orders
268
- (order, liquidation_price) = aggregated_order
269
-
270
- if order[5] <= 0:
271
- continue
272
-
273
- # Extract and format the order data
274
- order_details = {
275
- "trader": order[0],
276
- "pairIndex": order[1],
277
- "index": order[2],
278
- "positionSize": order[3],
279
- "buy": order[4],
280
- "leverage": order[5],
281
- "tp": order[6],
282
- "sl": order[7],
283
- "price": order[8],
284
- "slippageP": order[9],
285
- "block": order[10],
286
- # 'executionFee': order[11],
287
- "liquidation_price": liquidation_price,
288
- }
289
- pendingOpenLimitOrders.append(
290
- PendingLimitOrderExtendedResponse(**order_details)
291
- )
292
-
293
- return trades, pendingOpenLimitOrders
294
-
295
- async def build_trade_close_tx(
296
- self,
297
- pair_index: int,
298
- trade_index: int,
299
- collateral_to_close: float,
300
- trader: Optional[str] = None,
301
- ):
302
- """
303
- Builds a transaction to close a trade.
304
-
305
- Args:
306
- pair_index: The pair index.
307
- trade_index: The trade index.
308
- collateral_to_close: The collateral to close.
309
- trader (optional): The trader's wallet address.
310
-
311
- Returns:
312
- A transaction object.
313
- """
314
- Trading = self.client.contracts.get("Trading")
315
-
316
- if trader is None:
317
- trader = self.client.get_signer().get_ethereum_address()
318
-
319
- collateral_to_close = int(collateral_to_close * 10**6)
320
-
321
- execution_fee = await self.get_trade_execution_fee()
322
-
323
- transaction = await Trading.functions.closeTradeMarket(
324
- pair_index,
325
- trade_index,
326
- collateral_to_close,
327
- ).build_transaction(
328
- {
329
- "from": trader,
330
- "chainId": self.client.chain_id,
331
- "nonce": await self.client.get_transaction_count(trader),
332
- "value": execution_fee,
333
- }
334
- )
335
-
336
- return transaction
337
-
338
- async def build_trade_close_tx_delegate(
339
- self,
340
- pair_index: int,
341
- trade_index: int,
342
- collateral_to_close: float,
343
- trader: Optional[str] = None,
344
- ):
345
- """
346
- Builds a transaction to close a trade.
347
-
348
- Args:
349
- pair_index: The pair index.
350
- trade_index: The trade index.
351
- collateral_to_close: The collateral to close.
352
- trader (optional): The trader's wallet address.
353
-
354
- Returns:
355
- A transaction object.
356
- """
357
- Trading = self.client.contracts.get("Trading")
358
-
359
- if trader is None:
360
- trader = self.client.get_signer().get_ethereum_address()
361
-
362
- collateral_to_close = int(collateral_to_close * 10**6)
363
-
364
- execution_fee = await self.get_trade_execution_fee()
365
-
366
- transaction = await Trading.functions.closeTradeMarket(
367
- pair_index,
368
- trade_index,
369
- collateral_to_close,
370
- ).build_transaction(
371
- {
372
- "from": trader,
373
- "chainId": self.client.chain_id,
374
- "nonce": await self.client.get_transaction_count(trader),
375
- "value": 0,
376
- }
377
- )
378
-
379
- delegate_transaction = await Trading.functions.delegatedAction(
380
- trader, transaction["data"]
381
- ).build_transaction(
382
- {
383
- "from": self.client.get_signer().get_ethereum_address(),
384
- "value": execution_fee,
385
- "chainId": self.client.chain_id,
386
- "nonce": await self.client.get_transaction_count(
387
- self.client.get_signer().get_ethereum_address()
388
- ),
389
- }
390
- )
391
-
392
- return delegate_transaction
393
-
394
- async def build_order_cancel_tx(
395
- self, pair_index: int, trade_index: int, trader: Optional[str] = None
396
- ):
397
- """
398
- Builds a transaction to cancel an order.
399
-
400
- Args:
401
- pair_index: The pair index.
402
- trade_index: The trade/order index.
403
- trader (optional): The trader's wallet address.
404
-
405
- Returns:
406
- A transaction object.
407
- """
408
- Trading = self.client.contracts.get("Trading")
409
-
410
- if trader is None:
411
- trader = self.client.get_signer().get_ethereum_address()
412
-
413
- transaction = await Trading.functions.cancelOpenLimitOrder(
414
- pair_index, trade_index
415
- ).build_transaction(
416
- {
417
- "from": trader,
418
- "chainId": self.client.chain_id,
419
- "nonce": await self.client.get_transaction_count(trader),
420
- }
421
- )
422
-
423
- return transaction
424
-
425
- async def build_order_cancel_tx_delegate(
426
- self, pair_index: int, trade_index: int, trader: Optional[str] = None
427
- ):
428
- """
429
- Builds a transaction to cancel an order.
430
-
431
- Args:
432
- pair_index: The pair index.
433
- trade_index: The trade/order index.
434
- trader (optional): The trader's wallet address.
435
-
436
- Returns:
437
- A transaction object.
438
- """
439
- Trading = self.client.contracts.get("Trading")
440
-
441
- if trader is None:
442
- trader = self.client.get_signer().get_ethereum_address()
443
-
444
- transaction = await Trading.functions.cancelOpenLimitOrder(
445
- pair_index, trade_index
446
- ).build_transaction(
447
- {
448
- "from": trader,
449
- "chainId": self.client.chain_id,
450
- "nonce": await self.client.get_transaction_count(trader),
451
- }
452
- )
453
-
454
- delegate_transaction = await Trading.functions.delegatedAction(
455
- trader, transaction["data"]
456
- ).build_transaction(
457
- {
458
- "from": self.client.get_signer().get_ethereum_address(),
459
- "chainId": self.client.chain_id,
460
- "nonce": await self.client.get_transaction_count(
461
- self.client.get_signer().get_ethereum_address()
462
- ),
463
- }
464
- )
465
-
466
- return delegate_transaction
467
-
468
- async def build_trade_margin_update_tx(
469
- self,
470
- pair_index: int,
471
- trade_index: int,
472
- margin_update_type: MarginUpdateType,
473
- collateral_change: float,
474
- trader: Optional[str] = None,
475
- ):
476
- """
477
- Builds a transaction to update the margin of a trade.
478
-
479
- Args:
480
- pair_index: The pair index.
481
- trade_index: The trade index.
482
- margin_update_type: The margin update type.
483
- collateral_change: The collateral change.
484
- trader (optional): The trader's wallet address.
485
- Returns:
486
- A transaction object.
487
- """
488
- Trading = self.client.contracts.get("Trading")
489
-
490
- if trader is None:
491
- trader = self.client.get_signer().get_ethereum_address()
492
-
493
- collateral_change = int(collateral_change * 10**6)
494
-
495
- feed_client = self.FeedClient()
496
-
497
- pair_name = await self.client.pairs_cache.get_pair_name_from_index(pair_index)
498
-
499
- price_data = await feed_client.get_latest_price_updates([pair_name])
500
-
501
- price_update_data = "0x" + price_data.binary.data[0]
502
-
503
- transaction = await Trading.functions.updateMargin(
504
- pair_index,
505
- trade_index,
506
- margin_update_type.value,
507
- collateral_change,
508
- [price_update_data],
509
- ).build_transaction(
510
- {
511
- "from": trader,
512
- "chainId": self.client.chain_id,
513
- "value": 1,
514
- "nonce": await self.client.get_transaction_count(trader),
515
- }
516
- )
517
-
518
- return transaction
519
-
520
- async def build_trade_margin_update_tx_delegate(
521
- self,
522
- pair_index: int,
523
- trade_index: int,
524
- margin_update_type: MarginUpdateType,
525
- collateral_change: float,
526
- trader: Optional[str] = None,
527
- ):
528
- """
529
- Builds a transaction to update the margin of a trade.
530
-
531
- Args:
532
- pair_index: The pair index.
533
- trade_index: The trade index.
534
- margin_update_type: The margin update type.
535
- collateral_change: The collateral change.
536
- trader (optional): The trader's wallet address.
537
- Returns:
538
- A transaction object.
539
- """
540
- Trading = self.client.contracts.get("Trading")
541
-
542
- if trader is None:
543
- trader = self.client.get_signer().get_ethereum_address()
544
-
545
- collateral_change = int(collateral_change * 10**6)
546
-
547
- feed_client = self.FeedClient()
548
-
549
- pair_name = await self.client.pairs_cache.get_pair_name_from_index(pair_index)
550
-
551
- price_data = await feed_client.get_latest_price_updates([pair_name])
552
-
553
- price_update_data = "0x" + price_data.binary.data[0]
554
-
555
- transaction = await Trading.functions.updateMargin(
556
- pair_index,
557
- trade_index,
558
- margin_update_type.value,
559
- collateral_change,
560
- [price_update_data],
561
- ).build_transaction(
562
- {
563
- "from": trader,
564
- "chainId": self.client.chain_id,
565
- "value": 0,
566
- "nonce": await self.client.get_transaction_count(trader),
567
- }
568
- )
569
-
570
- delegate_transaction = await Trading.functions.delegatedAction(
571
- trader, transaction["data"]
572
- ).build_transaction(
573
- {
574
- "from": self.client.get_signer().get_ethereum_address(),
575
- "chainId": self.client.chain_id,
576
- "nonce": await self.client.get_transaction_count(
577
- self.client.get_signer().get_ethereum_address()
578
- ),
579
- "value": 1,
580
- }
581
- )
582
-
583
- return delegate_transaction
584
-
585
- async def build_trade_tp_sl_update_tx(
586
- self,
587
- pair_index: int,
588
- trade_index: int,
589
- take_profit_price: float,
590
- stop_loss_price: float,
591
- trader: str = None,
592
- ):
593
- """
594
- Builds a transaction to update the stop loss and take profit of a trade.
595
-
596
- Args:
597
- pair_index: The pair index.
598
- trade_index: The trade index.
599
- take_profit_price: The take profit price.
600
- stop_loss_price: The stop loss price. Pass 0 if you want to remove the stop loss.
601
- trader (optional): The trader's wallet address.
602
- Returns:
603
- A transaction object.
604
- """
605
- Trading = self.client.contracts.get("Trading")
606
-
607
- if take_profit_price == 0:
608
- raise ValueError("Take profit price cannot be 0")
609
-
610
- if trader is None:
611
- trader = self.client.get_signer().get_ethereum_address()
612
-
613
- feed_client = self.FeedClient()
614
-
615
- pair_name = await self.client.pairs_cache.get_pair_name_from_index(pair_index)
616
-
617
- price_data = await feed_client.get_latest_price_updates([pair_name])
618
-
619
- price_update_data = "0x" + price_data.binary.data[0]
620
-
621
- take_profit_price = int(take_profit_price * 10**10)
622
- stop_loss_price = int(stop_loss_price * 10**10)
623
-
624
- transaction = await Trading.functions.updateTpAndSl(
625
- pair_index,
626
- trade_index,
627
- stop_loss_price,
628
- take_profit_price,
629
- [price_update_data],
630
- ).build_transaction(
631
- {
632
- "from": trader,
633
- "chainId": self.client.chain_id,
634
- "value": 1,
635
- "nonce": await self.client.get_transaction_count(trader),
636
- "gas": 1_000_000,
637
- }
638
- )
639
-
640
- return transaction
641
-
642
- async def build_trade_tp_sl_update_tx_delegate(
643
- self,
644
- pair_index: int,
645
- trade_index: int,
646
- take_profit_price: float,
647
- stop_loss_price: float,
648
- trader: str = None,
649
- ):
650
- """
651
- Builds a transaction to update the stop loss and take profit of a trade.
652
-
653
- Args:
654
- pair_index: The pair index.
655
- trade_index: The trade index.
656
- take_profit_price: The take profit price.
657
- stop_loss_price: The stop loss price. Pass 0 if you want to remove the stop loss.
658
- trader (optional): The trader's wallet address.
659
- Returns:
660
- A transaction object.
661
- """
662
- Trading = self.client.contracts.get("Trading")
663
-
664
- if take_profit_price == 0:
665
- raise ValueError("Take profit price cannot be 0")
666
-
667
- if trader is None:
668
- trader = self.client.get_signer().get_ethereum_address()
669
-
670
- feed_client = self.FeedClient()
671
-
672
- pair_name = await self.client.pairs_cache.get_pair_name_from_index(pair_index)
673
-
674
- price_data = await feed_client.get_latest_price_updates([pair_name])
675
-
676
- price_update_data = "0x" + price_data.binary.data[0]
677
-
678
- take_profit_price = int(take_profit_price * 10**10)
679
- stop_loss_price = int(stop_loss_price * 10**10)
680
-
681
- transaction = await Trading.functions.updateTpAndSl(
682
- pair_index,
683
- trade_index,
684
- stop_loss_price,
685
- take_profit_price,
686
- [price_update_data],
687
- ).build_transaction(
688
- {
689
- "from": trader,
690
- "chainId": self.client.chain_id,
691
- "value": 0,
692
- "nonce": await self.client.get_transaction_count(trader),
693
- "gas": 1_000_000,
694
- }
695
- )
696
-
697
- delegate_transaction = await Trading.functions.delegatedAction(
698
- trader, transaction["data"]
699
- ).build_transaction(
700
- {
701
- "from": self.client.get_signer().get_ethereum_address(),
702
- "chainId": self.client.chain_id,
703
- "nonce": await self.client.get_transaction_count(
704
- self.client.get_signer().get_ethereum_address()
705
- ),
706
- "value": 1,
707
- "gas": 1_000_000,
708
- }
709
- )
710
- return delegate_transaction
1
+ from ..feed.feed_client import FeedClient
2
+ from ..types import (
3
+ TradeInput,
4
+ TradeInputOrderType,
5
+ TradeExtendedResponse,
6
+ TradeResponse,
7
+ TradeInfo,
8
+ PendingLimitOrderExtendedResponse,
9
+ MarginUpdateType,
10
+ )
11
+ from typing import Optional
12
+ import math
13
+
14
+
15
+ class TradeRPC:
16
+ """
17
+ The TradeRPC class contains methods for retrieving trading parameters from the Avantis Protocol.
18
+ """
19
+
20
+ def __init__(self, client, feed_client: FeedClient):
21
+ """
22
+ Constructor for the TradeRPC class.
23
+
24
+ Args:
25
+ client: The TraderClient object.
26
+ feed_client: The FeedClient object.
27
+ """
28
+ self.client = client
29
+ self.feed_client = feed_client
30
+
31
+ async def build_trade_open_tx(
32
+ self,
33
+ trade_input: TradeInput,
34
+ trade_input_order_type: TradeInputOrderType,
35
+ slippage_percentage: int,
36
+ execution_fee: Optional[float] = None,
37
+ ):
38
+ """
39
+ Builds a transaction to open a trade.
40
+
41
+ Args:
42
+ trade: The trade input object.
43
+ trade_input_order_type: The trade input order type.
44
+ slippage_percentage: The slippage percentage.
45
+
46
+ Returns:
47
+ A transaction object.
48
+ """
49
+ Trading = self.client.contracts.get("Trading")
50
+
51
+ if (
52
+ trade_input.trader == "0x1234567890123456789012345678901234567890"
53
+ and self.client.get_signer() is not None
54
+ ):
55
+ trade_input.trader = await self.client.get_signer().get_ethereum_address()
56
+
57
+ if execution_fee is not None:
58
+ execution_fee_wei = int(execution_fee * 10**18)
59
+ else:
60
+ execution_fee_wei = await self.get_trade_execution_fee()
61
+
62
+ if (
63
+ trade_input_order_type == TradeInputOrderType.MARKET
64
+ or trade_input_order_type == TradeInputOrderType.MARKET_ZERO_FEE
65
+ ) and not trade_input.openPrice:
66
+ pair_name = await self.client.pairs_cache.get_pair_name_from_index(
67
+ trade_input.pairIndex
68
+ )
69
+ price_data = await self.feed_client.get_latest_price_updates([pair_name])
70
+ price = int(price_data.parsed[0].converted_price * 10**10)
71
+ trade_input.openPrice = price
72
+
73
+ if (
74
+ trade_input_order_type == TradeInputOrderType.LIMIT
75
+ or trade_input_order_type == TradeInputOrderType.STOP_LIMIT
76
+ ) and not trade_input.openPrice:
77
+ raise Exception("Open price is required for LIMIT/STOP LIMIT order type")
78
+
79
+ transaction = await Trading.functions.openTrade(
80
+ trade_input.model_dump(),
81
+ trade_input_order_type.value,
82
+ slippage_percentage * 10**10,
83
+ ).build_transaction(
84
+ {
85
+ "from": trade_input.trader,
86
+ "value": execution_fee_wei,
87
+ "chainId": self.client.chain_id,
88
+ "nonce": await self.client.get_transaction_count(trade_input.trader),
89
+ }
90
+ )
91
+
92
+ return transaction
93
+
94
+ async def build_trade_open_tx_delegate(
95
+ self,
96
+ trade_input: TradeInput,
97
+ trade_input_order_type: TradeInputOrderType,
98
+ slippage_percentage: int,
99
+ execution_fee: Optional[float] = None,
100
+ ):
101
+ """
102
+ Builds a transaction to open a trade.
103
+
104
+ Args:
105
+ trade: The trade input object.
106
+ trade_input_order_type: The trade input order type.
107
+ slippage_percentage: The slippage percentage.
108
+
109
+ Returns:
110
+ A transaction object.
111
+ """
112
+ Trading = self.client.contracts.get("Trading")
113
+
114
+ if (
115
+ trade_input.trader == "0x1234567890123456789012345678901234567890"
116
+ and self.client.get_signer() is not None
117
+ ):
118
+ trade_input.trader = await self.client.get_signer().get_ethereum_address()
119
+
120
+ if execution_fee is not None:
121
+ execution_fee_wei = int(execution_fee * 10**18)
122
+ else:
123
+ execution_fee_wei = await self.get_trade_execution_fee()
124
+
125
+ if (
126
+ trade_input_order_type == TradeInputOrderType.MARKET
127
+ or trade_input_order_type == TradeInputOrderType.MARKET_ZERO_FEE
128
+ ) and not trade_input.openPrice:
129
+ pair_name = await self.client.pairs_cache.get_pair_name_from_index(
130
+ trade_input.pairIndex
131
+ )
132
+ price_data = await self.feed_client.get_latest_price_updates([pair_name])
133
+ price = int(price_data.parsed[0].converted_price * 10**10)
134
+ trade_input.openPrice = price
135
+
136
+ if (
137
+ trade_input_order_type == TradeInputOrderType.LIMIT
138
+ or trade_input_order_type == TradeInputOrderType.STOP_LIMIT
139
+ ) and not trade_input.openPrice:
140
+ raise Exception("Open price is required for LIMIT/STOP LIMIT order type")
141
+
142
+ transaction = await Trading.functions.openTrade(
143
+ trade_input.model_dump(),
144
+ trade_input_order_type.value,
145
+ slippage_percentage * 10**10,
146
+ ).build_transaction(
147
+ {
148
+ "from": trade_input.trader,
149
+ "value": 0,
150
+ "chainId": self.client.chain_id,
151
+ "nonce": await self.client.get_transaction_count(trade_input.trader),
152
+ }
153
+ )
154
+
155
+ print("transaction: ", trade_input.trader)
156
+
157
+ delegate_transaction = await Trading.functions.delegatedAction(
158
+ trade_input.trader, transaction["data"]
159
+ ).build_transaction(
160
+ {
161
+ "from": self.client.get_signer().get_ethereum_address(),
162
+ "value": execution_fee_wei,
163
+ "chainId": self.client.chain_id,
164
+ "nonce": await self.client.get_transaction_count(
165
+ self.client.get_signer().get_ethereum_address()
166
+ ),
167
+ }
168
+ )
169
+
170
+ return delegate_transaction
171
+
172
+ async def get_trade_execution_fee(self):
173
+ """
174
+ Gets the correct trade execution fee.
175
+
176
+ Returns:
177
+ The trade execution fee
178
+ """
179
+ execution_fee = round(0.00035, 18) # default value
180
+ execution_fee_wei = int(execution_fee * 10**18)
181
+
182
+ try:
183
+ feeScalar = 0.001
184
+
185
+ estimatedL1Gas = math.floor(22676 * feeScalar)
186
+ estimatedL2Gas = math.floor(850000 * 1.1)
187
+
188
+ l2GasPrice = await self.client.async_web3.eth.gas_price
189
+ estimatedL2GasEth = l2GasPrice * estimatedL2Gas
190
+
191
+ l1GasPrice = await self.client.l1_async_web3.eth.gas_price
192
+ estimatedL1GasEth = l1GasPrice * estimatedL1Gas
193
+
194
+ feeEstimate = estimatedL1GasEth + estimatedL2GasEth
195
+ feeEstimate = round(feeEstimate, 18)
196
+ return feeEstimate
197
+ except Exception as e:
198
+ print("Error getting correct trade execution fee. Using fallback: ", e)
199
+ return execution_fee_wei
200
+
201
+ async def get_trades(self, trader: Optional[str] = None):
202
+ """
203
+ Gets the trades.
204
+
205
+ Args:
206
+ trader: The trader's wallet address.
207
+
208
+ Returns:
209
+ The trades.
210
+ """
211
+ if trader is None:
212
+ trader = self.client.get_signer().get_ethereum_address()
213
+
214
+ result = (
215
+ await self.client.contracts.get("Multicall")
216
+ .functions.getPositions(trader)
217
+ .call()
218
+ )
219
+ trades = []
220
+ pendingOpenLimitOrders = []
221
+
222
+ for aggregated_trade in result[0]: # Access the list of aggregated trades
223
+ (trade, trade_info, margin_fee, liquidation_price) = aggregated_trade
224
+
225
+ if trade[7] <= 0:
226
+ continue
227
+
228
+ # Extract and format the trade data
229
+ trade_details = {
230
+ "trade": {
231
+ "trader": trade[0],
232
+ "pairIndex": trade[1],
233
+ "index": trade[2],
234
+ "initialPosToken": trade[3],
235
+ "positionSizeUSDC": trade[4],
236
+ "openPrice": trade[5],
237
+ "buy": trade[6],
238
+ "leverage": trade[7],
239
+ "tp": trade[8],
240
+ "sl": trade[9],
241
+ "timestamp": trade[10],
242
+ },
243
+ "additional_info": {
244
+ "openInterestUSDC": trade_info[0],
245
+ "tpLastUpdated": trade_info[1],
246
+ "slLastUpdated": trade_info[2],
247
+ "beingMarketClosed": trade_info[3],
248
+ "lossProtectionPercentage": await self.client.trading_parameters.get_loss_protection_percentage_by_tier(
249
+ trade_info[4], trade[1]
250
+ ),
251
+ },
252
+ "margin_fee": margin_fee,
253
+ "liquidationPrice": liquidation_price,
254
+ }
255
+ trades.append(
256
+ TradeExtendedResponse(
257
+ trade=TradeResponse(**trade_details["trade"]),
258
+ additional_info=TradeInfo(**trade_details["additional_info"]),
259
+ margin_fee=trade_details["margin_fee"],
260
+ liquidation_price=trade_details["liquidationPrice"],
261
+ )
262
+ )
263
+
264
+ for aggregated_order in result[1]: # Access the list of aggregated orders
265
+ (order, liquidation_price) = aggregated_order
266
+
267
+ if order[5] <= 0:
268
+ continue
269
+
270
+ # Extract and format the order data
271
+ order_details = {
272
+ "trader": order[0],
273
+ "pairIndex": order[1],
274
+ "index": order[2],
275
+ "positionSize": order[3],
276
+ "buy": order[4],
277
+ "leverage": order[5],
278
+ "tp": order[6],
279
+ "sl": order[7],
280
+ "price": order[8],
281
+ "slippageP": order[9],
282
+ "block": order[10],
283
+ # 'executionFee': order[11],
284
+ "liquidation_price": liquidation_price,
285
+ }
286
+ pendingOpenLimitOrders.append(
287
+ PendingLimitOrderExtendedResponse(**order_details)
288
+ )
289
+
290
+ return trades, pendingOpenLimitOrders
291
+
292
+ async def build_trade_close_tx(
293
+ self,
294
+ pair_index: int,
295
+ trade_index: int,
296
+ collateral_to_close: float,
297
+ trader: Optional[str] = None,
298
+ ):
299
+ """
300
+ Builds a transaction to close a trade.
301
+
302
+ Args:
303
+ pair_index: The pair index.
304
+ trade_index: The trade index.
305
+ collateral_to_close: The collateral to close.
306
+ trader (optional): The trader's wallet address.
307
+
308
+ Returns:
309
+ A transaction object.
310
+ """
311
+ Trading = self.client.contracts.get("Trading")
312
+
313
+ if trader is None:
314
+ trader = self.client.get_signer().get_ethereum_address()
315
+
316
+ collateral_to_close = int(collateral_to_close * 10**6)
317
+
318
+ execution_fee = await self.get_trade_execution_fee()
319
+
320
+ transaction = await Trading.functions.closeTradeMarket(
321
+ pair_index,
322
+ trade_index,
323
+ collateral_to_close,
324
+ ).build_transaction(
325
+ {
326
+ "from": trader,
327
+ "chainId": self.client.chain_id,
328
+ "nonce": await self.client.get_transaction_count(trader),
329
+ "value": execution_fee,
330
+ }
331
+ )
332
+
333
+ return transaction
334
+
335
+ async def build_trade_close_tx_delegate(
336
+ self,
337
+ pair_index: int,
338
+ trade_index: int,
339
+ collateral_to_close: float,
340
+ trader: Optional[str] = None,
341
+ ):
342
+ """
343
+ Builds a transaction to close a trade.
344
+
345
+ Args:
346
+ pair_index: The pair index.
347
+ trade_index: The trade index.
348
+ collateral_to_close: The collateral to close.
349
+ trader (optional): The trader's wallet address.
350
+
351
+ Returns:
352
+ A transaction object.
353
+ """
354
+ Trading = self.client.contracts.get("Trading")
355
+
356
+ if trader is None:
357
+ trader = self.client.get_signer().get_ethereum_address()
358
+
359
+ collateral_to_close = int(collateral_to_close * 10**6)
360
+
361
+ execution_fee = await self.get_trade_execution_fee()
362
+
363
+ transaction = await Trading.functions.closeTradeMarket(
364
+ pair_index,
365
+ trade_index,
366
+ collateral_to_close,
367
+ ).build_transaction(
368
+ {
369
+ "from": trader,
370
+ "chainId": self.client.chain_id,
371
+ "nonce": await self.client.get_transaction_count(trader),
372
+ "value": 0,
373
+ }
374
+ )
375
+
376
+ delegate_transaction = await Trading.functions.delegatedAction(
377
+ trader, transaction["data"]
378
+ ).build_transaction(
379
+ {
380
+ "from": self.client.get_signer().get_ethereum_address(),
381
+ "value": execution_fee,
382
+ "chainId": self.client.chain_id,
383
+ "nonce": await self.client.get_transaction_count(
384
+ self.client.get_signer().get_ethereum_address()
385
+ ),
386
+ }
387
+ )
388
+
389
+ return delegate_transaction
390
+
391
+ async def build_order_cancel_tx(
392
+ self, pair_index: int, trade_index: int, trader: Optional[str] = None
393
+ ):
394
+ """
395
+ Builds a transaction to cancel an order.
396
+
397
+ Args:
398
+ pair_index: The pair index.
399
+ trade_index: The trade/order index.
400
+ trader (optional): The trader's wallet address.
401
+
402
+ Returns:
403
+ A transaction object.
404
+ """
405
+ Trading = self.client.contracts.get("Trading")
406
+
407
+ if trader is None:
408
+ trader = self.client.get_signer().get_ethereum_address()
409
+
410
+ transaction = await Trading.functions.cancelOpenLimitOrder(
411
+ pair_index, trade_index
412
+ ).build_transaction(
413
+ {
414
+ "from": trader,
415
+ "chainId": self.client.chain_id,
416
+ "nonce": await self.client.get_transaction_count(trader),
417
+ }
418
+ )
419
+
420
+ return transaction
421
+
422
+ async def build_order_cancel_tx_delegate(
423
+ self, pair_index: int, trade_index: int, trader: Optional[str] = None
424
+ ):
425
+ """
426
+ Builds a transaction to cancel an order.
427
+
428
+ Args:
429
+ pair_index: The pair index.
430
+ trade_index: The trade/order index.
431
+ trader (optional): The trader's wallet address.
432
+
433
+ Returns:
434
+ A transaction object.
435
+ """
436
+ Trading = self.client.contracts.get("Trading")
437
+
438
+ if trader is None:
439
+ trader = self.client.get_signer().get_ethereum_address()
440
+
441
+ transaction = await Trading.functions.cancelOpenLimitOrder(
442
+ pair_index, trade_index
443
+ ).build_transaction(
444
+ {
445
+ "from": trader,
446
+ "chainId": self.client.chain_id,
447
+ "nonce": await self.client.get_transaction_count(trader),
448
+ }
449
+ )
450
+
451
+ delegate_transaction = await Trading.functions.delegatedAction(
452
+ trader, transaction["data"]
453
+ ).build_transaction(
454
+ {
455
+ "from": self.client.get_signer().get_ethereum_address(),
456
+ "chainId": self.client.chain_id,
457
+ "nonce": await self.client.get_transaction_count(
458
+ self.client.get_signer().get_ethereum_address()
459
+ ),
460
+ }
461
+ )
462
+
463
+ return delegate_transaction
464
+
465
+ async def build_trade_margin_update_tx(
466
+ self,
467
+ pair_index: int,
468
+ trade_index: int,
469
+ margin_update_type: MarginUpdateType,
470
+ collateral_change: float,
471
+ trader: Optional[str] = None,
472
+ ):
473
+ """
474
+ Builds a transaction to update the margin of a trade.
475
+
476
+ Args:
477
+ pair_index: The pair index.
478
+ trade_index: The trade index.
479
+ margin_update_type: The margin update type.
480
+ collateral_change: The collateral change.
481
+ trader (optional): The trader's wallet address.
482
+ Returns:
483
+ A transaction object.
484
+ """
485
+ Trading = self.client.contracts.get("Trading")
486
+
487
+ if trader is None:
488
+ trader = self.client.get_signer().get_ethereum_address()
489
+
490
+ collateral_change = int(collateral_change * 10**6)
491
+
492
+ pair_name = await self.client.pairs_cache.get_pair_name_from_index(pair_index)
493
+
494
+ price_data = await self.feed_client.get_latest_price_updates([pair_name])
495
+
496
+ price_update_data = "0x" + price_data.binary.data[0]
497
+
498
+ transaction = await Trading.functions.updateMargin(
499
+ pair_index,
500
+ trade_index,
501
+ margin_update_type.value,
502
+ collateral_change,
503
+ [price_update_data],
504
+ ).build_transaction(
505
+ {
506
+ "from": trader,
507
+ "chainId": self.client.chain_id,
508
+ "value": 1,
509
+ "nonce": await self.client.get_transaction_count(trader),
510
+ }
511
+ )
512
+
513
+ return transaction
514
+
515
+ async def build_trade_margin_update_tx_delegate(
516
+ self,
517
+ pair_index: int,
518
+ trade_index: int,
519
+ margin_update_type: MarginUpdateType,
520
+ collateral_change: float,
521
+ trader: Optional[str] = None,
522
+ ):
523
+ """
524
+ Builds a transaction to update the margin of a trade.
525
+
526
+ Args:
527
+ pair_index: The pair index.
528
+ trade_index: The trade index.
529
+ margin_update_type: The margin update type.
530
+ collateral_change: The collateral change.
531
+ trader (optional): The trader's wallet address.
532
+ Returns:
533
+ A transaction object.
534
+ """
535
+ Trading = self.client.contracts.get("Trading")
536
+
537
+ if trader is None:
538
+ trader = self.client.get_signer().get_ethereum_address()
539
+
540
+ collateral_change = int(collateral_change * 10**6)
541
+
542
+ pair_name = await self.client.pairs_cache.get_pair_name_from_index(pair_index)
543
+
544
+ price_data = await self.feed_client.get_latest_price_updates([pair_name])
545
+
546
+ price_update_data = "0x" + price_data.binary.data[0]
547
+
548
+ transaction = await Trading.functions.updateMargin(
549
+ pair_index,
550
+ trade_index,
551
+ margin_update_type.value,
552
+ collateral_change,
553
+ [price_update_data],
554
+ ).build_transaction(
555
+ {
556
+ "from": trader,
557
+ "chainId": self.client.chain_id,
558
+ "value": 0,
559
+ "nonce": await self.client.get_transaction_count(trader),
560
+ }
561
+ )
562
+
563
+ delegate_transaction = await Trading.functions.delegatedAction(
564
+ trader, transaction["data"]
565
+ ).build_transaction(
566
+ {
567
+ "from": self.client.get_signer().get_ethereum_address(),
568
+ "chainId": self.client.chain_id,
569
+ "nonce": await self.client.get_transaction_count(
570
+ self.client.get_signer().get_ethereum_address()
571
+ ),
572
+ "value": 1,
573
+ }
574
+ )
575
+
576
+ return delegate_transaction
577
+
578
+ async def build_trade_tp_sl_update_tx(
579
+ self,
580
+ pair_index: int,
581
+ trade_index: int,
582
+ take_profit_price: float,
583
+ stop_loss_price: float,
584
+ trader: str = None,
585
+ ):
586
+ """
587
+ Builds a transaction to update the stop loss and take profit of a trade.
588
+
589
+ Args:
590
+ pair_index: The pair index.
591
+ trade_index: The trade index.
592
+ take_profit_price: The take profit price.
593
+ stop_loss_price: The stop loss price. Pass 0 if you want to remove the stop loss.
594
+ trader (optional): The trader's wallet address.
595
+ Returns:
596
+ A transaction object.
597
+ """
598
+ Trading = self.client.contracts.get("Trading")
599
+
600
+ if take_profit_price == 0:
601
+ raise ValueError("Take profit price cannot be 0")
602
+
603
+ if trader is None:
604
+ trader = self.client.get_signer().get_ethereum_address()
605
+
606
+ pair_name = await self.client.pairs_cache.get_pair_name_from_index(pair_index)
607
+
608
+ price_data = await feed_client.get_latest_price_updates([pair_name])
609
+
610
+ price_update_data = "0x" + price_data.binary.data[0]
611
+
612
+ take_profit_price = int(take_profit_price * 10**10)
613
+ stop_loss_price = int(stop_loss_price * 10**10)
614
+
615
+ transaction = await Trading.functions.updateTpAndSl(
616
+ pair_index,
617
+ trade_index,
618
+ stop_loss_price,
619
+ take_profit_price,
620
+ [price_update_data],
621
+ ).build_transaction(
622
+ {
623
+ "from": trader,
624
+ "chainId": self.client.chain_id,
625
+ "value": 1,
626
+ "nonce": await self.client.get_transaction_count(trader),
627
+ "gas": 1_000_000,
628
+ }
629
+ )
630
+
631
+ return transaction
632
+
633
+ async def build_trade_tp_sl_update_tx_delegate(
634
+ self,
635
+ pair_index: int,
636
+ trade_index: int,
637
+ take_profit_price: float,
638
+ stop_loss_price: float,
639
+ trader: str = None,
640
+ ):
641
+ """
642
+ Builds a transaction to update the stop loss and take profit of a trade.
643
+
644
+ Args:
645
+ pair_index: The pair index.
646
+ trade_index: The trade index.
647
+ take_profit_price: The take profit price.
648
+ stop_loss_price: The stop loss price. Pass 0 if you want to remove the stop loss.
649
+ trader (optional): The trader's wallet address.
650
+ Returns:
651
+ A transaction object.
652
+ """
653
+ Trading = self.client.contracts.get("Trading")
654
+
655
+ if take_profit_price == 0:
656
+ raise ValueError("Take profit price cannot be 0")
657
+
658
+ if trader is None:
659
+ trader = self.client.get_signer().get_ethereum_address()
660
+
661
+ feed_client = self.FeedClient()
662
+
663
+ pair_name = await self.client.pairs_cache.get_pair_name_from_index(pair_index)
664
+
665
+ price_data = await self.feed_client.get_latest_price_updates([pair_name])
666
+
667
+ price_update_data = "0x" + price_data.binary.data[0]
668
+
669
+ take_profit_price = int(take_profit_price * 10**10)
670
+ stop_loss_price = int(stop_loss_price * 10**10)
671
+
672
+ transaction = await Trading.functions.updateTpAndSl(
673
+ pair_index,
674
+ trade_index,
675
+ stop_loss_price,
676
+ take_profit_price,
677
+ [price_update_data],
678
+ ).build_transaction(
679
+ {
680
+ "from": trader,
681
+ "chainId": self.client.chain_id,
682
+ "value": 0,
683
+ "nonce": await self.client.get_transaction_count(trader),
684
+ "gas": 1_000_000,
685
+ }
686
+ )
687
+
688
+ delegate_transaction = await Trading.functions.delegatedAction(
689
+ trader, transaction["data"]
690
+ ).build_transaction(
691
+ {
692
+ "from": self.client.get_signer().get_ethereum_address(),
693
+ "chainId": self.client.chain_id,
694
+ "nonce": await self.client.get_transaction_count(
695
+ self.client.get_signer().get_ethereum_address()
696
+ ),
697
+ "value": 1,
698
+ "gas": 1_000_000,
699
+ }
700
+ )
701
+ return delegate_transaction