nado-protocol 0.1.0__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 (78) hide show
  1. nado_protocol/__init__.py +0 -0
  2. nado_protocol/client/__init__.py +200 -0
  3. nado_protocol/client/apis/__init__.py +26 -0
  4. nado_protocol/client/apis/base.py +42 -0
  5. nado_protocol/client/apis/market/__init__.py +23 -0
  6. nado_protocol/client/apis/market/execute.py +192 -0
  7. nado_protocol/client/apis/market/query.py +310 -0
  8. nado_protocol/client/apis/perp/__init__.py +18 -0
  9. nado_protocol/client/apis/perp/query.py +30 -0
  10. nado_protocol/client/apis/rewards/__init__.py +6 -0
  11. nado_protocol/client/apis/rewards/execute.py +131 -0
  12. nado_protocol/client/apis/rewards/query.py +12 -0
  13. nado_protocol/client/apis/spot/__init__.py +23 -0
  14. nado_protocol/client/apis/spot/base.py +32 -0
  15. nado_protocol/client/apis/spot/execute.py +117 -0
  16. nado_protocol/client/apis/spot/query.py +79 -0
  17. nado_protocol/client/apis/subaccount/__init__.py +24 -0
  18. nado_protocol/client/apis/subaccount/execute.py +54 -0
  19. nado_protocol/client/apis/subaccount/query.py +145 -0
  20. nado_protocol/client/context.py +90 -0
  21. nado_protocol/contracts/__init__.py +377 -0
  22. nado_protocol/contracts/abis/Endpoint.json +636 -0
  23. nado_protocol/contracts/abis/FQuerier.json +1909 -0
  24. nado_protocol/contracts/abis/IClearinghouse.json +876 -0
  25. nado_protocol/contracts/abis/IERC20.json +185 -0
  26. nado_protocol/contracts/abis/IEndpoint.json +250 -0
  27. nado_protocol/contracts/abis/IFoundationRewardsAirdrop.json +76 -0
  28. nado_protocol/contracts/abis/IOffchainBook.json +536 -0
  29. nado_protocol/contracts/abis/IPerpEngine.json +931 -0
  30. nado_protocol/contracts/abis/IProductEngine.json +352 -0
  31. nado_protocol/contracts/abis/ISpotEngine.json +813 -0
  32. nado_protocol/contracts/abis/IStaking.json +288 -0
  33. nado_protocol/contracts/abis/IVrtxAirdrop.json +138 -0
  34. nado_protocol/contracts/abis/MockERC20.json +311 -0
  35. nado_protocol/contracts/deployments/deployment.test.json +18 -0
  36. nado_protocol/contracts/eip712/__init__.py +16 -0
  37. nado_protocol/contracts/eip712/domain.py +36 -0
  38. nado_protocol/contracts/eip712/sign.py +79 -0
  39. nado_protocol/contracts/eip712/types.py +154 -0
  40. nado_protocol/contracts/loader.py +55 -0
  41. nado_protocol/contracts/types.py +141 -0
  42. nado_protocol/engine_client/__init__.py +35 -0
  43. nado_protocol/engine_client/execute.py +416 -0
  44. nado_protocol/engine_client/query.py +481 -0
  45. nado_protocol/engine_client/types/__init__.py +113 -0
  46. nado_protocol/engine_client/types/execute.py +680 -0
  47. nado_protocol/engine_client/types/models.py +247 -0
  48. nado_protocol/engine_client/types/query.py +516 -0
  49. nado_protocol/engine_client/types/stream.py +6 -0
  50. nado_protocol/indexer_client/__init__.py +28 -0
  51. nado_protocol/indexer_client/query.py +466 -0
  52. nado_protocol/indexer_client/types/__init__.py +122 -0
  53. nado_protocol/indexer_client/types/models.py +364 -0
  54. nado_protocol/indexer_client/types/query.py +819 -0
  55. nado_protocol/trigger_client/__init__.py +17 -0
  56. nado_protocol/trigger_client/execute.py +118 -0
  57. nado_protocol/trigger_client/query.py +61 -0
  58. nado_protocol/trigger_client/types/__init__.py +7 -0
  59. nado_protocol/trigger_client/types/execute.py +89 -0
  60. nado_protocol/trigger_client/types/models.py +44 -0
  61. nado_protocol/trigger_client/types/query.py +77 -0
  62. nado_protocol/utils/__init__.py +37 -0
  63. nado_protocol/utils/backend.py +111 -0
  64. nado_protocol/utils/bytes32.py +159 -0
  65. nado_protocol/utils/enum.py +6 -0
  66. nado_protocol/utils/exceptions.py +58 -0
  67. nado_protocol/utils/execute.py +403 -0
  68. nado_protocol/utils/expiration.py +45 -0
  69. nado_protocol/utils/interest.py +66 -0
  70. nado_protocol/utils/math.py +67 -0
  71. nado_protocol/utils/model.py +79 -0
  72. nado_protocol/utils/nonce.py +33 -0
  73. nado_protocol/utils/subaccount.py +18 -0
  74. nado_protocol/utils/time.py +21 -0
  75. nado_protocol-0.1.0.dist-info/METADATA +157 -0
  76. nado_protocol-0.1.0.dist-info/RECORD +78 -0
  77. nado_protocol-0.1.0.dist-info/WHEEL +4 -0
  78. nado_protocol-0.1.0.dist-info/entry_points.txt +11 -0
@@ -0,0 +1,310 @@
1
+ from typing import Optional
2
+ from nado_protocol.client.apis.base import NadoBaseAPI
3
+ from nado_protocol.engine_client.types.query import (
4
+ AllProductsData,
5
+ MarketLiquidityData,
6
+ MarketPriceData,
7
+ MaxLpMintableData,
8
+ MaxOrderSizeData,
9
+ ProductSymbolsData,
10
+ SubaccountOpenOrdersData,
11
+ SubaccountMultiProductsOpenOrdersData,
12
+ QueryMaxOrderSizeParams,
13
+ IsolatedPositionsData,
14
+ )
15
+ from nado_protocol.indexer_client.types.query import (
16
+ IndexerCandlesticksData,
17
+ IndexerCandlesticksParams,
18
+ IndexerFundingRateData,
19
+ IndexerFundingRatesData,
20
+ IndexerHistoricalOrdersData,
21
+ IndexerSubaccountHistoricalOrdersParams,
22
+ IndexerProductSnapshotsData,
23
+ IndexerProductSnapshotsParams,
24
+ IndexerMarketSnapshotsParams,
25
+ IndexerMarketSnapshotsData,
26
+ )
27
+ from nado_protocol.trigger_client.types.query import (
28
+ ListTriggerOrdersParams,
29
+ TriggerQueryResponse,
30
+ )
31
+ from nado_protocol.utils.exceptions import MissingTriggerClient
32
+
33
+
34
+ class MarketQueryAPI(NadoBaseAPI):
35
+ """
36
+ The MarketQueryAPI class provides methods to interact with the Nado's market querying APIs.
37
+
38
+ This class provides functionality for querying various details about the market including fetching
39
+ information about order books, fetching historical orders, and retrieving market matches, among others.
40
+
41
+ Attributes:
42
+ context (NadoClientContext): The context that provides connectivity configuration for NadoClient.
43
+
44
+ Note:
45
+ This class should not be instantiated directly, it is designed to be used through a NadoClient instance.
46
+ """
47
+
48
+ def get_all_engine_markets(self) -> AllProductsData:
49
+ """
50
+ Retrieves all market states from the off-chain engine.
51
+
52
+ Returns:
53
+ AllProductsData: A data class object containing information about all products in the engine.
54
+ """
55
+ return self.context.engine_client.get_all_products()
56
+
57
+ def get_all_product_symbols(self) -> ProductSymbolsData:
58
+ """
59
+ Retrieves all product symbols from the off-chain engine
60
+
61
+ Returns:
62
+ ProductSymbolsData: A list of all products with corresponding symbol.
63
+ """
64
+ return self.context.engine_client.get_product_symbols()
65
+
66
+ def get_market_liquidity(self, product_id: int, depth: int) -> MarketLiquidityData:
67
+ """
68
+ Retrieves liquidity per price tick from the engine.
69
+
70
+ The engine will skip price levels that have no liquidity,
71
+ so it is not guaranteed that the bids/asks are evenly spaced
72
+
73
+ Parameters:
74
+ product_id (int): The product ID for which liquidity is to be fetched.
75
+ depth (int): The depth of the order book to retrieve liquidity from.
76
+
77
+ Returns:
78
+ MarketLiquidityData: A data class object containing liquidity information for the specified product.
79
+ """
80
+ return self.context.engine_client.get_market_liquidity(product_id, depth)
81
+
82
+ def get_latest_market_price(self, product_id: int) -> MarketPriceData:
83
+ """
84
+ Retrieves the latest off-chain orderbook price from the engine for a specific product.
85
+
86
+ Args:
87
+ product_id (int): The identifier for the product to retrieve the latest market price.
88
+
89
+ Returns:
90
+ MarketPriceData: A data class object containing information about the latest market price for the given product.
91
+ """
92
+ return self.context.engine_client.get_market_price(product_id)
93
+
94
+ def get_subaccount_open_orders(
95
+ self, product_id: int, sender: str
96
+ ) -> SubaccountOpenOrdersData:
97
+ """
98
+ Queries the off-chain engine to retrieve the status of any open orders for a given subaccount.
99
+
100
+ This function fetches any open orders that a specific subaccount might have
101
+ for a specific product from the off-chain engine. The orders are returned as
102
+ an SubaccountOpenOrdersData object.
103
+
104
+ Args:
105
+ product_id (int): The identifier for the product to fetch open orders.
106
+
107
+ sender (str): The address and subaccount identifier as a bytes32 hex string.
108
+
109
+ Returns:
110
+ SubaccountOpenOrdersData: A data class object containing information about the open orders of a subaccount.
111
+ """
112
+ return self.context.engine_client.get_subaccount_open_orders(product_id, sender)
113
+
114
+ def get_subaccount_multi_products_open_orders(
115
+ self, product_ids: list[int], sender: str
116
+ ) -> SubaccountMultiProductsOpenOrdersData:
117
+ """
118
+ Queries the off-chain engine to retrieve the status of any open orders for a given subaccount across multiple products.
119
+
120
+ This function fetches any open orders that a specific subaccount might have
121
+ for products product from the off-chain engine. The orders are returned as
122
+ an SubaccountMultiProductsOpenOrdersData object.
123
+
124
+ Args:
125
+ product_ids (list[int]): List of product ids to fetch open orders for.
126
+
127
+ sender (str): The address and subaccount identifier as a bytes32 hex string.
128
+
129
+ Returns:
130
+ SubaccountMultiProductsOpenOrdersData: A data class object containing information about the open orders of a subaccount.
131
+ """
132
+ return self.context.engine_client.get_subaccount_multi_products_open_orders(
133
+ product_ids, sender
134
+ )
135
+
136
+ def get_subaccount_historical_orders(
137
+ self, params: IndexerSubaccountHistoricalOrdersParams
138
+ ) -> IndexerHistoricalOrdersData:
139
+ """
140
+ Queries the indexer to fetch historical orders of a specific subaccount.
141
+
142
+ This function retrieves a list of historical orders that a specific subaccount has placed.
143
+ The order data can be filtered using various parameters provided in the
144
+ IndexerSubaccountHistoricalOrdersParams object. The fetched historical orders data
145
+ is returned as an IndexerHistoricalOrdersData object.
146
+
147
+ Args:
148
+ params (IndexerSubaccountHistoricalOrdersParams): Parameters to filter the historical orders data:
149
+ - subaccount (str): The address and subaccount identifier as a bytes32 hex string.
150
+ - product_ids (list[int], optional): A list of identifiers for the products to fetch orders for. If provided, the function will return orders related to these products.
151
+ - idx (int, optional): Submission index. If provided, the function will return orders submitted before this index.
152
+ - max_time (int, optional): Maximum timestamp for the orders. The function will return orders submitted before this time.
153
+ - limit (int, optional): Maximum number of orders to return. If provided, the function will return at most 'limit' number of orders.
154
+
155
+ Returns:
156
+ IndexerHistoricalOrdersData: A data class object containing information about the historical orders of a subaccount.
157
+ """
158
+ return self.context.indexer_client.get_subaccount_historical_orders(params)
159
+
160
+ def get_historical_orders_by_digest(
161
+ self, digests: list[str]
162
+ ) -> IndexerHistoricalOrdersData:
163
+ """
164
+ Queries the indexer to fetch historical orders based on a list of provided digests.
165
+
166
+ This function retrieves historical order data for a given list of order digests.
167
+ Each digest represents a unique order. The returned object includes the historical
168
+ order data for each digest in the provided list.
169
+
170
+ Args:
171
+ digests (list[str]): List of order digests. An order digest is a unique identifier for each order.
172
+
173
+ Returns:
174
+ IndexerHistoricalOrdersData: A data class object containing information about the historical orders associated with the provided digests.
175
+ """
176
+ return self.context.indexer_client.get_historical_orders_by_digest(digests)
177
+
178
+ def get_max_order_size(self, params: QueryMaxOrderSizeParams) -> MaxOrderSizeData:
179
+ """
180
+ Queries the engine to determine the maximum order size that can be submitted within
181
+ health requirements.
182
+
183
+ Args:
184
+ params (QueryMaxOrderSizeParams):
185
+ - sender (str): The address and subaccount identifier in a bytes32 hex string.
186
+ - product_id (int): The identifier for the spot/perp product.
187
+ - price_x18 (str): The price of the order in x18 format as a string.
188
+ - direction (MaxOrderSizeDirection): 'long' for max bid or 'short' for max ask.
189
+ - spot_leverage (Optional[bool]): If False, calculates max size without borrowing. Defaults to True.
190
+
191
+ Returns:
192
+ MaxOrderSizeData: The maximum size of the order that can be placed.
193
+ """
194
+ return self.context.engine_client.get_max_order_size(params)
195
+
196
+ def get_max_lp_mintable(
197
+ self, product_id: int, sender: str, spot_leverage: Optional[bool] = None
198
+ ) -> MaxLpMintableData:
199
+ """
200
+ Queries the engine to determine the maximum base amount that can be contributed for minting LPs.
201
+
202
+ Args:
203
+ product_id (int): The identifier for the spot/perp product.
204
+
205
+ sender (str): The address and subaccount identifier in a bytes32 hex string.
206
+
207
+ spot_leverage (Optional[bool]): If False, calculates max amount without considering leverage. Defaults to True.
208
+
209
+ Returns:
210
+ MaxLpMintableData: Maximum base amount that can be contributed for minting LPs, in string format.
211
+ """
212
+ return self.context.engine_client.get_max_lp_mintable(
213
+ product_id, sender, spot_leverage
214
+ )
215
+
216
+ def get_candlesticks(
217
+ self, params: IndexerCandlesticksParams
218
+ ) -> IndexerCandlesticksData:
219
+ """
220
+ Fetches historical candlestick data for a specific product using the indexer.
221
+
222
+ Args:
223
+ params (IndexerCandlesticksParams): Parameters for the query, which include:
224
+ - product_id (int): The identifier for the product.
225
+ - granularity (IndexerCandlesticksGranularity): Duration for each candlestick in seconds.
226
+
227
+ Returns:
228
+ IndexerCandlesticksData: Contains a list of historical candlestick data (IndexerCandlestick)
229
+ for the specified product at the specified granularity.
230
+
231
+ Note:
232
+ For obtaining the latest orderbook prices, consider using the 'get_latest_market_price()' method.
233
+ """
234
+
235
+ return self.context.indexer_client.get_candlesticks(params)
236
+
237
+ def get_perp_funding_rate(self, product_id: int) -> IndexerFundingRateData:
238
+ """
239
+ Fetches the latest funding rate for a specific perp product.
240
+
241
+ Args:
242
+ product_id (int): Identifier for the perp product.
243
+
244
+ Returns:
245
+ IndexerFundingRateData: Contains the latest funding rate and related details for the given perp product.
246
+ """
247
+ return self.context.indexer_client.get_perp_funding_rate(product_id)
248
+
249
+ def get_perp_funding_rates(self, product_ids: list) -> IndexerFundingRatesData:
250
+ """
251
+ Fetches the latest funding rates for a list of perp products.
252
+
253
+ Args:
254
+ product_ids (list): List of identifiers for the perp products.
255
+
256
+ Returns:
257
+ dict: A dictionary mapping each product_id to its latest funding rate and related details.
258
+ """
259
+ return self.context.indexer_client.get_perp_funding_rates(product_ids)
260
+
261
+ def get_product_snapshots(
262
+ self, params: IndexerProductSnapshotsParams
263
+ ) -> IndexerProductSnapshotsData:
264
+ """
265
+ Fetches the historical snapshots for a specific product from the indexer.
266
+
267
+ Args:
268
+ params (IndexerProductSnapshotsParams): Query parameters consisting of:
269
+ - product_id (int): Identifier for the product.
270
+ - idx (int, optional): Submission index to filter the returned snapshots.
271
+ - max_time (int, optional): Maximum timestamp to filter the returned snapshots.
272
+ - limit (int, optional): Maximum number of snapshots to return.
273
+
274
+ Returns:
275
+ IndexerProductSnapshotsData: Object containing lists of product snapshots and related transaction data.
276
+ """
277
+ return self.context.indexer_client.get_product_snapshots(params)
278
+
279
+ def get_market_snapshots(
280
+ self, params: IndexerMarketSnapshotsParams
281
+ ) -> IndexerMarketSnapshotsData:
282
+ """
283
+ Fetches the historical market snapshots from the indexer.
284
+
285
+ Args:
286
+ params (IndexerMarketSnapshotsParams): Parameters specifying the historical market snapshot request.
287
+
288
+ Returns:
289
+ IndexerMarketSnapshotsData: The market snapshot data corresponding to the provided parameters.
290
+ """
291
+ return self.context.indexer_client.get_market_snapshots(params)
292
+
293
+ def get_trigger_orders(
294
+ self, params: ListTriggerOrdersParams
295
+ ) -> TriggerQueryResponse:
296
+ if self.context.trigger_client is None:
297
+ raise MissingTriggerClient()
298
+ return self.context.trigger_client.list_trigger_orders(params)
299
+
300
+ def get_isolated_positions(self, subaccount: str) -> IsolatedPositionsData:
301
+ """
302
+ Retrieve isolated positions for a specific subaccount.
303
+
304
+ Args:
305
+ subaccount (str): Unique identifier for the subaccount.
306
+
307
+ Returns:
308
+ IsolatedPositionsData: A data class object containing information about the isolated positions for the specified subaccount.
309
+ """
310
+ return self.context.engine_client.get_isolated_positions(subaccount)
@@ -0,0 +1,18 @@
1
+ from nado_protocol.client.apis.perp.query import PerpQueryAPI
2
+
3
+
4
+ class PerpAPI(PerpQueryAPI):
5
+ """
6
+ A unified interface for Perpetual (Perp) operations in the Nado Protocol.
7
+
8
+ This class extends functionalities from PerpQueryAPI into a single interface, providing a simpler and more consistent way to perform Perp operations.
9
+ Currently, it allows for querying (data retrieval) operations for Perp products.
10
+
11
+ Inheritance:
12
+ PerpQueryAPI: This provides functionalities to retrieve various kinds of information related to Perp products.
13
+ These include operations like retrieving the latest index and mark price for a specific Perp product.
14
+
15
+ Attributes and Methods: Inherited from PerpQueryAPI.
16
+ """
17
+
18
+ pass
@@ -0,0 +1,30 @@
1
+ from nado_protocol.client.apis.base import NadoBaseAPI
2
+ from nado_protocol.indexer_client.types.query import IndexerPerpPricesData
3
+
4
+
5
+ class PerpQueryAPI(NadoBaseAPI):
6
+ """
7
+ Provides functionalities for querying data related to Perpetual (Perp) products in the Nado Protocol.
8
+
9
+ Inherits from NadoBaseAPI, which provides a basic context setup for accessing Nado.
10
+ This class extends the base class to provide specific functionalities for querying data related to Perp products.
11
+
12
+ Attributes:
13
+ context (NadoClientContext): Provides connectivity details for accessing Nado APIs.
14
+ """
15
+
16
+ def get_prices(self, product_id: int) -> IndexerPerpPricesData:
17
+ """
18
+ Retrieves the latest index and mark price for a specific perp product from the indexer.
19
+
20
+ Args:
21
+ product_id (int): The identifier for the perp product.
22
+
23
+ Returns:
24
+ IndexerPerpPricesData: An object containing the latest index and mark price for the specified product.
25
+ - product_id (int): The identifier for the perp product.
26
+ - index_price_x18 (str): The latest index price for the product, scaled by 1e18.
27
+ - mark_price_x18 (str): The latest mark price for the product, scaled by 1e18.
28
+ - update_time (str): The timestamp of the last price update.
29
+ """
30
+ return self.context.indexer_client.get_perp_prices(product_id)
@@ -0,0 +1,6 @@
1
+ from nado_protocol.client.apis.rewards.execute import RewardsExecuteAPI
2
+ from nado_protocol.client.apis.rewards.query import RewardsQueryAPI
3
+
4
+
5
+ class RewardsAPI(RewardsExecuteAPI, RewardsQueryAPI):
6
+ pass
@@ -0,0 +1,131 @@
1
+ from typing import Optional
2
+ from nado_protocol.contracts.types import (
3
+ ClaimFoundationRewardsContractParams,
4
+ ClaimFoundationRewardsProofStruct,
5
+ ClaimVrtxContractParams,
6
+ ClaimVrtxParams,
7
+ )
8
+ from nado_protocol.client.apis.base import NadoBaseAPI
9
+ from eth_account.signers.local import LocalAccount
10
+
11
+ from nado_protocol.utils.exceptions import InvalidVrtxClaimParams
12
+
13
+
14
+ class RewardsExecuteAPI(NadoBaseAPI):
15
+ def _validate_claim_params(self, params: ClaimVrtxParams):
16
+ p = ClaimVrtxParams.parse_obj(params)
17
+ if p.amount is None and p.claim_all is None:
18
+ raise InvalidVrtxClaimParams()
19
+
20
+ def claim_vrtx(
21
+ self, params: ClaimVrtxParams, signer: Optional[LocalAccount] = None
22
+ ) -> str:
23
+ self._validate_claim_params(params)
24
+ signer = self._get_signer(signer)
25
+ claim_params = self._get_claim_vrtx_contract_params(params, signer)
26
+ return self.context.contracts.claim_vrtx(
27
+ claim_params.epoch,
28
+ claim_params.amount_to_claim,
29
+ claim_params.total_claimable_amount,
30
+ claim_params.merkle_proof,
31
+ signer,
32
+ )
33
+
34
+ def claim_and_stake_vrtx(
35
+ self, params: ClaimVrtxParams, signer: Optional[LocalAccount] = None
36
+ ) -> str:
37
+ self._validate_claim_params(params)
38
+ signer = self._get_signer(signer)
39
+ claim_params = self._get_claim_vrtx_contract_params(params, signer)
40
+ return self.context.contracts.claim_and_stake_vrtx(
41
+ claim_params.epoch,
42
+ claim_params.amount_to_claim,
43
+ claim_params.total_claimable_amount,
44
+ claim_params.merkle_proof,
45
+ signer,
46
+ )
47
+
48
+ def stake_vrtx(self, amount: int, signer: Optional[LocalAccount] = None) -> str:
49
+ signer = self._get_signer(signer)
50
+ return self.context.contracts.stake_vrtx(amount, signer)
51
+
52
+ def unstake_vrtx(self, amount: int, signer: Optional[LocalAccount] = None) -> str:
53
+ signer = self._get_signer(signer)
54
+ return self.context.contracts.unstake_vrtx(amount, signer)
55
+
56
+ def withdraw_unstaked_vrtx(self, signer: Optional[LocalAccount] = None):
57
+ signer = self._get_signer(signer)
58
+ return self.context.contracts.withdraw_unstaked_vrtx(signer)
59
+
60
+ def claim_usdc_rewards(self, signer: Optional[LocalAccount] = None):
61
+ signer = self._get_signer(signer)
62
+ return self.context.contracts.claim_usdc_rewards(signer)
63
+
64
+ def claim_and_stake_usdc_rewards(self, signer: Optional[LocalAccount] = None):
65
+ signer = self._get_signer(signer)
66
+ return self.context.contracts.claim_and_stake_usdc_rewards(signer)
67
+
68
+ def claim_foundation_rewards(self, signer: Optional[LocalAccount] = None):
69
+ """
70
+ Claims all available foundation rewards. Foundation rewards are tokens associated with the chain. For example, ARB on Arbitrum.
71
+ """
72
+ signer = self._get_signer(signer)
73
+ claim_params = self._get_claim_foundation_rewards_contract_params(signer)
74
+ return self.context.contracts.claim_foundation_rewards(
75
+ claim_params.claim_proofs, signer
76
+ )
77
+
78
+ def _get_claim_vrtx_contract_params(
79
+ self, params: ClaimVrtxParams, signer: LocalAccount
80
+ ) -> ClaimVrtxContractParams:
81
+ epoch_merkle_proofs = self.context.indexer_client.get_vrtx_merkle_proofs(
82
+ signer.address
83
+ ).merkle_proofs[params.epoch]
84
+ total_claimable_amount = int(epoch_merkle_proofs.total_amount)
85
+ if params.amount is not None:
86
+ amount_to_claim = params.amount
87
+ else:
88
+ assert self.context.contracts.vrtx_airdrop is not None
89
+ amount_claimed = self.context.contracts.vrtx_airdrop.functions.getClaimed(
90
+ signer.address
91
+ ).call()
92
+ amount_to_claim = total_claimable_amount - amount_claimed[params.epoch]
93
+ return ClaimVrtxContractParams(
94
+ epoch=params.epoch,
95
+ amount_to_claim=amount_to_claim,
96
+ total_claimable_amount=total_claimable_amount,
97
+ merkle_proof=epoch_merkle_proofs.proof,
98
+ )
99
+
100
+ def _get_claim_foundation_rewards_contract_params(
101
+ self, signer: LocalAccount
102
+ ) -> ClaimFoundationRewardsContractParams:
103
+ assert self.context.contracts.foundation_rewards_airdrop is not None
104
+ claimed = (
105
+ self.context.contracts.foundation_rewards_airdrop.functions.getClaimed(
106
+ signer.address
107
+ ).call()
108
+ )
109
+ merkle_proofs = (
110
+ self.context.indexer_client.get_foundation_rewards_merkle_proofs(
111
+ signer.address
112
+ )
113
+ )
114
+ claim_proofs = []
115
+
116
+ for idx, proof in enumerate(merkle_proofs.merkle_proofs):
117
+ if idx == 0:
118
+ # week 0 is invalid
119
+ continue
120
+
121
+ total_amount = int(proof.total_amount)
122
+
123
+ # There's no partial claim, so find weeks where there's a claimable amount and amt claimed is zero
124
+ if total_amount > 0 and int(claimed[idx]) == 0:
125
+ claim_proofs.append(
126
+ ClaimFoundationRewardsProofStruct(
127
+ totalAmount=total_amount, week=idx, proof=proof.proof
128
+ )
129
+ )
130
+
131
+ return ClaimFoundationRewardsContractParams(claim_proofs=claim_proofs)
@@ -0,0 +1,12 @@
1
+ from nado_protocol.client.apis.base import NadoBaseAPI
2
+
3
+
4
+ class RewardsQueryAPI(NadoBaseAPI):
5
+ def get_claim_and_stake_estimated_vrtx(self, wallet: str) -> int:
6
+ """
7
+ Estimates the amount of USDC -> VRTX swap when claiming + staking USDC rewards
8
+ """
9
+ assert self.context.contracts.vrtx_staking is not None
10
+ return self.context.contracts.vrtx_staking.functions.getEstimatedVrtxToStake(
11
+ wallet
12
+ ).call()
@@ -0,0 +1,23 @@
1
+ from nado_protocol.client.apis.spot.execute import SpotExecuteAPI
2
+ from nado_protocol.client.apis.spot.query import SpotQueryAPI
3
+
4
+
5
+ class SpotAPI(SpotExecuteAPI, SpotQueryAPI):
6
+ """
7
+ A unified interface for spot operations in the Nado Protocol.
8
+
9
+ This class combines functionalities from both SpotExecuteAPI and SpotQueryAPI
10
+ into a single interface, providing a simpler and more consistent way to perform spot operations.
11
+ It allows for both query (data retrieval) and execution (transaction) operations for spot products.
12
+
13
+ Inheritance:
14
+ SpotExecuteAPI: This provides functionalities to execute various operations related to spot products,
15
+ such as depositing a specified amount into a spot product.
16
+
17
+ SpotQueryAPI: This provides functionalities to retrieve various kinds of information related to spot products,
18
+ such as getting the wallet token balance of a given spot product.
19
+
20
+ Attributes and Methods: Inherited from SpotExecuteAPI and SpotQueryAPI.
21
+ """
22
+
23
+ pass
@@ -0,0 +1,32 @@
1
+ from web3.contract import Contract
2
+ from nado_protocol.client.apis.base import NadoBaseAPI
3
+
4
+
5
+ class BaseSpotAPI(NadoBaseAPI):
6
+ """
7
+ Base class for Spot operations in the Nado Protocol.
8
+
9
+ This class provides basic functionality for retrieving product-specific information
10
+ from the spot market of the Nado Protocol, such as the associated ERC20 token contract for a given spot product.
11
+
12
+ Attributes:
13
+ context (NadoClientContext): Provides connectivity details for accessing Nado APIs.
14
+
15
+ Methods:
16
+ get_token_contract_for_product: Retrieves the associated ERC20 token contract for a given spot product.
17
+ """
18
+
19
+ def get_token_contract_for_product(self, product_id: int) -> Contract:
20
+ """
21
+ Retrieves the associated ERC20 token contract for a given spot product.
22
+
23
+ Args:
24
+ product_id (int): The identifier for the spot product.
25
+
26
+ Returns:
27
+ Contract: The associated ERC20 token contract for the specified spot product.
28
+
29
+ Raises:
30
+ InvalidProductId: If the provided product ID is not valid.
31
+ """
32
+ return self.context.contracts.get_token_contract_for_product(product_id)