avantis-trader-sdk 0.8.2__py3-none-any.whl → 0.8.4__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 (40) 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/Trading.sol/Trading.json +1 -1
  7. avantis_trader_sdk/abis/USDC.sol/USDC.dbg.json +4 -4
  8. avantis_trader_sdk/abis/interfaces/ICallbacks.sol/ICallbacks.json +2637 -2637
  9. avantis_trader_sdk/abis/interfaces/IExecute.sol/IExecute.json +1628 -1628
  10. avantis_trader_sdk/abis/interfaces/IPairInfos.sol/IPairInfos.json +2781 -2781
  11. avantis_trader_sdk/abis/interfaces/IPairStorage.sol/IPairStorage.json +3729 -3729
  12. avantis_trader_sdk/abis/interfaces/IPriceAggregator.sol/IPriceAggregator.json +2330 -2330
  13. avantis_trader_sdk/abis/interfaces/IReferral.sol/IReferral.json +1890 -1890
  14. avantis_trader_sdk/abis/interfaces/ITradingStorage.sol/ITradingStorage.json +7022 -7022
  15. avantis_trader_sdk/abis/interfaces/ITranche.sol/ITranche.json +1283 -1283
  16. avantis_trader_sdk/abis/interfaces/IVaultManager.sol/IVaultManager.json +2424 -2424
  17. avantis_trader_sdk/abis/interfaces/IVeTranche.sol/IVeTranche.json +855 -855
  18. avantis_trader_sdk/abis/library/PositionMath.sol/PositionMath.dbg.json +4 -4
  19. avantis_trader_sdk/abis/library/PositionMath.sol/PositionMath.json +10 -10
  20. avantis_trader_sdk/abis/testnet/USDC.sol/USDC.dbg.json +4 -4
  21. avantis_trader_sdk/abis/testnet/USDC.sol/USDC.json +320 -320
  22. avantis_trader_sdk/client.py +369 -367
  23. avantis_trader_sdk/config.py +14 -14
  24. avantis_trader_sdk/feed/feed_client.py +263 -261
  25. avantis_trader_sdk/rpc/asset_parameters.py +499 -499
  26. avantis_trader_sdk/rpc/blended.py +71 -71
  27. avantis_trader_sdk/rpc/category_parameters.py +216 -216
  28. avantis_trader_sdk/rpc/fee_parameters.py +237 -237
  29. avantis_trader_sdk/rpc/pairs_cache.py +130 -130
  30. avantis_trader_sdk/rpc/rpc_helpers.py +8 -8
  31. avantis_trader_sdk/rpc/snapshot.py +142 -142
  32. avantis_trader_sdk/rpc/trade.py +701 -710
  33. avantis_trader_sdk/rpc/trading_parameters.py +139 -139
  34. avantis_trader_sdk/types.py +462 -462
  35. avantis_trader_sdk/utils.py +78 -78
  36. {avantis_trader_sdk-0.8.2.dist-info → avantis_trader_sdk-0.8.4.dist-info}/METADATA +124 -113
  37. {avantis_trader_sdk-0.8.2.dist-info → avantis_trader_sdk-0.8.4.dist-info}/RECORD +39 -40
  38. {avantis_trader_sdk-0.8.2.dist-info → avantis_trader_sdk-0.8.4.dist-info}/WHEEL +1 -1
  39. avantis_trader_sdk/feed/feedIds.json +0 -214
  40. {avantis_trader_sdk-0.8.2.dist-info → avantis_trader_sdk-0.8.4.dist-info}/top_level.txt +0 -0
@@ -1,14 +1,14 @@
1
- MAINNET_ADDRESSES = {
2
- "TradingStorage": "0x8a311D7048c35985aa31C131B9A13e03a5f7422d",
3
- "PairStorage": "0x5db3772136e5557EFE028Db05EE95C84D76faEC4",
4
- "PairInfos": "0x81F22d0Cc22977c91bEfE648C9fddf1f2bd977e5",
5
- "PriceAggregator": "0x64e2625621970F8cfA17B294670d61CB883dA511",
6
- "USDC": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
7
- "Trading": "0x44914408af82bC9983bbb330e3578E1105e11d4e",
8
- "Multicall": "0x7A829c5C97A2Bf8BeFB4b01d96A282E4763848d8",
9
- "Referral": "0x1A110bBA13A1f16cCa4b79758BD39290f29De82D",
10
- }
11
-
12
- AVANTIS_SOCKET_API = "https://socket-api.avantisfi.com/v1/data"
13
-
14
- CONTRACT_ADDRESSES = MAINNET_ADDRESSES
1
+ MAINNET_ADDRESSES = {
2
+ "TradingStorage": "0x8a311D7048c35985aa31C131B9A13e03a5f7422d",
3
+ "PairStorage": "0x5db3772136e5557EFE028Db05EE95C84D76faEC4",
4
+ "PairInfos": "0x81F22d0Cc22977c91bEfE648C9fddf1f2bd977e5",
5
+ "PriceAggregator": "0x64e2625621970F8cfA17B294670d61CB883dA511",
6
+ "USDC": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
7
+ "Trading": "0x44914408af82bC9983bbb330e3578E1105e11d4e",
8
+ "Multicall": "0x7A829c5C97A2Bf8BeFB4b01d96A282E4763848d8",
9
+ "Referral": "0x1A110bBA13A1f16cCa4b79758BD39290f29De82D",
10
+ }
11
+
12
+ AVANTIS_SOCKET_API = "https://socket-api.avantisfi.com/v1/data"
13
+
14
+ CONTRACT_ADDRESSES = MAINNET_ADDRESSES
@@ -1,261 +1,263 @@
1
- import json
2
- import websockets
3
- from ..types import PriceFeedResponse, PriceFeedUpdatesResponse, PairInfoFeed
4
- from typing import List, Callable
5
- import requests
6
- from pydantic import ValidationError
7
- from ..config import AVANTIS_SOCKET_API
8
- import asyncio
9
- from concurrent.futures import ThreadPoolExecutor
10
-
11
-
12
- class FeedClient:
13
- """
14
- Client for interacting with the Pyth price feed websocket.
15
- """
16
-
17
- def __init__(
18
- self,
19
- ws_url="wss://hermes.pyth.network/ws",
20
- on_error=None,
21
- on_close=None,
22
- hermes_url="https://hermes.pyth.network/v2/updates/price/latest",
23
- pair_fetcher: Callable = None,
24
- ):
25
- """
26
- Constructor for the FeedClient class.
27
-
28
- Args:
29
- ws_url: Optional - The websocket URL to connect to.
30
- on_error: Optional callback for handling websocket errors.
31
- on_close: Optional callback for handling websocket close events.
32
- """
33
- if (
34
- ws_url is not None
35
- and not ws_url.startswith("ws://")
36
- and not ws_url.startswith("wss://")
37
- ):
38
- raise ValueError("ws_url must start with ws:// or wss://")
39
-
40
- self.ws_url = ws_url
41
- self.hermes_url = hermes_url
42
- self.pair_feeds = {}
43
- self.feed_pairs = {}
44
- self.price_feed_callbacks = {}
45
- self._socket = None
46
- self._connected = False
47
- self._on_error = on_error
48
- self._on_close = on_close
49
- self.pair_fetcher = pair_fetcher or self.default_pair_fetcher
50
- self._load_pair_feeds()
51
-
52
- async def listen_for_price_updates(self):
53
- """
54
- Listens for price updates from the Pyth price feed websocket.
55
- When a price update is received, the registered callbacks will
56
- be called with the updated price feed data.
57
-
58
- Raises:
59
- Exception: If an error occurs while listening for price updates.
60
- """
61
- try:
62
- async with websockets.connect(self.ws_url) as websocket:
63
- self._socket = websocket
64
- self._connected = True
65
- await websocket.send(
66
- json.dumps(
67
- {
68
- "type": "subscribe",
69
- "ids": list(self.price_feed_callbacks.keys()),
70
- }
71
- )
72
- )
73
- while True:
74
- try:
75
- message = await websocket.recv()
76
- data = json.loads(message)
77
- if data["type"] == "price_update":
78
- price_feed_id = data["price_feed"]["id"]
79
- if price_feed_id in self.price_feed_callbacks:
80
- pair_string = self.get_pair_from_feed_id(price_feed_id)
81
- data["price_feed"]["pair"] = pair_string
82
- for callback in self.price_feed_callbacks[
83
- price_feed_id
84
- ]:
85
- callback(PriceFeedResponse(**data["price_feed"]))
86
- except websockets.exceptions.ConnectionClosed as e:
87
- if self._on_close:
88
- self._on_close(e)
89
- else:
90
- print(f"Connection closed with error: {e}")
91
- break
92
- except Exception as e:
93
- if self._on_error:
94
- self._on_error(e)
95
- else:
96
- raise e
97
- except Exception as e:
98
- if self._on_error:
99
- self._on_error(e)
100
- else:
101
- raise e
102
-
103
- async def default_pair_fetcher(self) -> List[dict]:
104
- """
105
- Default pair fetcher that retrieves data from the Avantis API.
106
- Returns:
107
- A list of validated trading pairs.
108
- Raises:
109
- ValueError if API response is invalid.
110
- """
111
- if not AVANTIS_SOCKET_API:
112
- raise ValueError("AVANTIS_SOCKET_API is not set")
113
- try:
114
- response = requests.get(AVANTIS_SOCKET_API)
115
- response.raise_for_status()
116
-
117
- result = response.json()
118
- pairs = result["data"]["pairInfos"].values()
119
-
120
- return pairs
121
- except (requests.RequestException, ValidationError) as e:
122
- print(f"Error fetching pair feeds: {e}")
123
- return []
124
-
125
- def _load_pair_feeds(self):
126
- """
127
- Loads the pair feeds dynamically using the provided pair_fetcher function.
128
- """
129
-
130
- try:
131
- try:
132
- asyncio.get_running_loop()
133
- except RuntimeError:
134
- asyncio.set_event_loop(asyncio.new_event_loop())
135
-
136
- with ThreadPoolExecutor() as executor:
137
- future = executor.submit(lambda: asyncio.run(self.pair_fetcher()))
138
- pairs = future.result()
139
-
140
- if not pairs:
141
- raise ValueError("Fetched pair feed data is empty or invalid.")
142
-
143
- if isinstance(pairs, dict):
144
- pairs = list(pairs.values())
145
- else:
146
- pairs = list(pairs)
147
-
148
- if hasattr(pairs[0], "model_dump_json"):
149
- pairs = [json.loads(pair.model_dump_json()) for pair in pairs]
150
-
151
- validated_pairs = [PairInfoFeed.model_validate(pair) for pair in pairs]
152
-
153
- self.pair_feeds = {
154
- f"{pair.from_}/{pair.to}": {"id": pair.feed.feed_id}
155
- for pair in validated_pairs
156
- }
157
- self.feed_pairs = {
158
- pair.feed.feed_id: f"{pair.from_}/{pair.to}" for pair in validated_pairs
159
- }
160
- except Exception as e:
161
- print(f"Failed to load pair feeds: {e}")
162
-
163
- def get_pair_from_feed_id(self, feed_id):
164
- """
165
- Retrieves the pair string from the feed id.
166
-
167
- Args:
168
- feed_id: The feed id to retrieve the pair string for.
169
-
170
- Returns:
171
- The pair string.
172
- """
173
- if not feed_id.startswith("0x"):
174
- feed_id = "0x" + feed_id
175
- return self.feed_pairs.get(feed_id)
176
-
177
- def register_price_feed_callback(self, identifier, callback):
178
- """
179
- Registers a callback for price feed updates.
180
-
181
- Args:
182
- identifier: The identifier of the price feed to register the callback for.
183
- callback: The callback to register.
184
-
185
- Raises:
186
- ValueError: If the identifier is unknown.
187
- """
188
- if identifier in self.pair_feeds:
189
- price_feed_id = self.pair_feeds[identifier]["id"]
190
- elif identifier in self.feed_pairs:
191
- price_feed_id = identifier
192
- elif identifier in self.price_feed_callbacks:
193
- price_feed_id = identifier
194
- else:
195
- raise ValueError(f"Unknown identifier: {identifier}")
196
-
197
- if price_feed_id.startswith("0x"):
198
- price_feed_id = price_feed_id[2:]
199
-
200
- if price_feed_id not in self.price_feed_callbacks:
201
- self.price_feed_callbacks[price_feed_id] = []
202
- self.price_feed_callbacks[price_feed_id].append(callback)
203
-
204
- def unregister_price_feed_callback(self, identifier, callback):
205
- """
206
- Unregisters a callback for price feed updates.
207
-
208
- Args:
209
- identifier: The identifier of the price feed to unregister the callback for.
210
- callback: The callback to unregister.
211
- """
212
- if identifier in self.pair_feeds:
213
- price_feed_id = self.pair_feeds[identifier]["id"]
214
- else:
215
- price_feed_id = identifier
216
-
217
- if price_feed_id in self.price_feed_callbacks:
218
- self.price_feed_callbacks[price_feed_id].remove(callback)
219
- if not self.price_feed_callbacks[price_feed_id]:
220
- del self.price_feed_callbacks[price_feed_id]
221
-
222
- async def get_latest_price_updates(self, identifiers: List[str]):
223
- """
224
- Retrieves the latest price updates for the specified feed ids.
225
-
226
- Args:
227
- feedIds: The list of feed ids to retrieve the latest price updates for.
228
-
229
- Returns:
230
- A PriceFeedUpdatesResponse object containing the latest price updates.
231
- """
232
- url = self.hermes_url
233
-
234
- feedIds = []
235
-
236
- for identifier in identifiers:
237
- if identifier in self.pair_feeds:
238
- price_feed_id = self.pair_feeds[identifier]["id"]
239
- elif identifier in self.feed_pairs:
240
- price_feed_id = identifier
241
- else:
242
- raise ValueError(f"Unknown identifier: {identifier}")
243
-
244
- if price_feed_id.startswith("0x"):
245
- price_feed_id = price_feed_id[2:]
246
-
247
- feedIds.append(price_feed_id)
248
-
249
- params = {"ids[]": feedIds}
250
-
251
- response = requests.get(url, params=params)
252
-
253
- if response.status_code == 200:
254
- data = response.json()
255
-
256
- for i in range(len(data["parsed"])):
257
- data["parsed"][i] = PriceFeedResponse(**data["parsed"][i])
258
-
259
- return PriceFeedUpdatesResponse(**data)
260
- else:
261
- response.raise_for_status()
1
+ import json
2
+ import websockets
3
+ from ..types import PriceFeedResponse, PriceFeedUpdatesResponse, PairInfoFeed
4
+ from typing import List, Callable
5
+ import requests
6
+ from pydantic import ValidationError
7
+ from ..config import AVANTIS_SOCKET_API
8
+ import asyncio
9
+ from concurrent.futures import ThreadPoolExecutor
10
+
11
+
12
+ class FeedClient:
13
+ """
14
+ Client for interacting with the Pyth price feed websocket.
15
+ """
16
+
17
+ def __init__(
18
+ self,
19
+ ws_url="wss://hermes.pyth.network/ws",
20
+ on_error=None,
21
+ on_close=None,
22
+ hermes_url="https://hermes.pyth.network/v2/updates/price/latest",
23
+ socket_api: str = AVANTIS_SOCKET_API,
24
+ pair_fetcher: Callable = None,
25
+ ):
26
+ """
27
+ Constructor for the FeedClient class.
28
+
29
+ Args:
30
+ ws_url: Optional - The websocket URL to connect to.
31
+ on_error: Optional callback for handling websocket errors.
32
+ on_close: Optional callback for handling websocket close events.
33
+ """
34
+ if (
35
+ ws_url is not None
36
+ and not ws_url.startswith("ws://")
37
+ and not ws_url.startswith("wss://")
38
+ ):
39
+ raise ValueError("ws_url must start with ws:// or wss://")
40
+
41
+ self.ws_url = ws_url
42
+ self.hermes_url = hermes_url
43
+ self.pair_feeds = {}
44
+ self.feed_pairs = {}
45
+ self.price_feed_callbacks = {}
46
+ self._socket = None
47
+ self._connected = False
48
+ self._on_error = on_error
49
+ self._on_close = on_close
50
+ self.socket_api = socket_api
51
+ self.pair_fetcher = pair_fetcher or self.default_pair_fetcher
52
+ self.load_pair_feeds()
53
+
54
+ async def listen_for_price_updates(self):
55
+ """
56
+ Listens for price updates from the Pyth price feed websocket.
57
+ When a price update is received, the registered callbacks will
58
+ be called with the updated price feed data.
59
+
60
+ Raises:
61
+ Exception: If an error occurs while listening for price updates.
62
+ """
63
+ try:
64
+ async with websockets.connect(self.ws_url) as websocket:
65
+ self._socket = websocket
66
+ self._connected = True
67
+ await websocket.send(
68
+ json.dumps(
69
+ {
70
+ "type": "subscribe",
71
+ "ids": list(self.price_feed_callbacks.keys()),
72
+ }
73
+ )
74
+ )
75
+ while True:
76
+ try:
77
+ message = await websocket.recv()
78
+ data = json.loads(message)
79
+ if data["type"] == "price_update":
80
+ price_feed_id = data["price_feed"]["id"]
81
+ if price_feed_id in self.price_feed_callbacks:
82
+ pair_string = self.get_pair_from_feed_id(price_feed_id)
83
+ data["price_feed"]["pair"] = pair_string
84
+ for callback in self.price_feed_callbacks[
85
+ price_feed_id
86
+ ]:
87
+ callback(PriceFeedResponse(**data["price_feed"]))
88
+ except websockets.exceptions.ConnectionClosed as e:
89
+ if self._on_close:
90
+ self._on_close(e)
91
+ else:
92
+ print(f"Connection closed with error: {e}")
93
+ break
94
+ except Exception as e:
95
+ if self._on_error:
96
+ self._on_error(e)
97
+ else:
98
+ raise e
99
+ except Exception as e:
100
+ if self._on_error:
101
+ self._on_error(e)
102
+ else:
103
+ raise e
104
+
105
+ async def default_pair_fetcher(self) -> List[dict]:
106
+ """
107
+ Default pair fetcher that retrieves data from the Avantis API.
108
+ Returns:
109
+ A list of validated trading pairs.
110
+ Raises:
111
+ ValueError if API response is invalid.
112
+ """
113
+ if not self.socket_api:
114
+ raise ValueError("socket_api is not set")
115
+ try:
116
+ response = requests.get(self.socket_api)
117
+ response.raise_for_status()
118
+
119
+ result = response.json()
120
+ pairs = result["data"]["pairInfos"].values()
121
+
122
+ return pairs
123
+ except (requests.RequestException, ValidationError) as e:
124
+ print(f"Error fetching pair feeds: {e}")
125
+ return []
126
+
127
+ def load_pair_feeds(self):
128
+ """
129
+ Loads the pair feeds dynamically using the provided pair_fetcher function.
130
+ """
131
+
132
+ try:
133
+ try:
134
+ asyncio.get_running_loop()
135
+ except RuntimeError:
136
+ asyncio.set_event_loop(asyncio.new_event_loop())
137
+
138
+ with ThreadPoolExecutor() as executor:
139
+ future = executor.submit(lambda: asyncio.run(self.pair_fetcher()))
140
+ pairs = future.result()
141
+
142
+ if not pairs:
143
+ raise ValueError("Fetched pair feed data is empty or invalid.")
144
+
145
+ if isinstance(pairs, dict):
146
+ pairs = list(pairs.values())
147
+ else:
148
+ pairs = list(pairs)
149
+
150
+ if hasattr(pairs[0], "model_dump_json"):
151
+ pairs = [json.loads(pair.model_dump_json()) for pair in pairs]
152
+
153
+ validated_pairs = [PairInfoFeed.model_validate(pair) for pair in pairs]
154
+
155
+ self.pair_feeds = {
156
+ f"{pair.from_}/{pair.to}": {"id": pair.feed.feed_id}
157
+ for pair in validated_pairs
158
+ }
159
+ self.feed_pairs = {
160
+ pair.feed.feed_id: f"{pair.from_}/{pair.to}" for pair in validated_pairs
161
+ }
162
+ except Exception as e:
163
+ print(f"Failed to load pair feeds: {e}")
164
+
165
+ def get_pair_from_feed_id(self, feed_id):
166
+ """
167
+ Retrieves the pair string from the feed id.
168
+
169
+ Args:
170
+ feed_id: The feed id to retrieve the pair string for.
171
+
172
+ Returns:
173
+ The pair string.
174
+ """
175
+ if not feed_id.startswith("0x"):
176
+ feed_id = "0x" + feed_id
177
+ return self.feed_pairs.get(feed_id)
178
+
179
+ def register_price_feed_callback(self, identifier, callback):
180
+ """
181
+ Registers a callback for price feed updates.
182
+
183
+ Args:
184
+ identifier: The identifier of the price feed to register the callback for.
185
+ callback: The callback to register.
186
+
187
+ Raises:
188
+ ValueError: If the identifier is unknown.
189
+ """
190
+ if identifier in self.pair_feeds:
191
+ price_feed_id = self.pair_feeds[identifier]["id"]
192
+ elif identifier in self.feed_pairs:
193
+ price_feed_id = identifier
194
+ elif identifier in self.price_feed_callbacks:
195
+ price_feed_id = identifier
196
+ else:
197
+ raise ValueError(f"Unknown identifier: {identifier}")
198
+
199
+ if price_feed_id.startswith("0x"):
200
+ price_feed_id = price_feed_id[2:]
201
+
202
+ if price_feed_id not in self.price_feed_callbacks:
203
+ self.price_feed_callbacks[price_feed_id] = []
204
+ self.price_feed_callbacks[price_feed_id].append(callback)
205
+
206
+ def unregister_price_feed_callback(self, identifier, callback):
207
+ """
208
+ Unregisters a callback for price feed updates.
209
+
210
+ Args:
211
+ identifier: The identifier of the price feed to unregister the callback for.
212
+ callback: The callback to unregister.
213
+ """
214
+ if identifier in self.pair_feeds:
215
+ price_feed_id = self.pair_feeds[identifier]["id"]
216
+ else:
217
+ price_feed_id = identifier
218
+
219
+ if price_feed_id in self.price_feed_callbacks:
220
+ self.price_feed_callbacks[price_feed_id].remove(callback)
221
+ if not self.price_feed_callbacks[price_feed_id]:
222
+ del self.price_feed_callbacks[price_feed_id]
223
+
224
+ async def get_latest_price_updates(self, identifiers: List[str]):
225
+ """
226
+ Retrieves the latest price updates for the specified feed ids.
227
+
228
+ Args:
229
+ feedIds: The list of feed ids to retrieve the latest price updates for.
230
+
231
+ Returns:
232
+ A PriceFeedUpdatesResponse object containing the latest price updates.
233
+ """
234
+ url = self.hermes_url
235
+
236
+ feedIds = []
237
+
238
+ for identifier in identifiers:
239
+ if identifier in self.pair_feeds:
240
+ price_feed_id = self.pair_feeds[identifier]["id"]
241
+ elif identifier in self.feed_pairs:
242
+ price_feed_id = identifier
243
+ else:
244
+ raise ValueError(f"Unknown identifier: {identifier}")
245
+
246
+ if price_feed_id.startswith("0x"):
247
+ price_feed_id = price_feed_id[2:]
248
+
249
+ feedIds.append(price_feed_id)
250
+
251
+ params = {"ids[]": feedIds}
252
+
253
+ response = requests.get(url, params=params)
254
+
255
+ if response.status_code == 200:
256
+ data = response.json()
257
+
258
+ for i in range(len(data["parsed"])):
259
+ data["parsed"][i] = PriceFeedResponse(**data["parsed"][i])
260
+
261
+ return PriceFeedUpdatesResponse(**data)
262
+ else:
263
+ response.raise_for_status()