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.
- avantis_trader_sdk/__init__.py +5 -5
- avantis_trader_sdk/abis/AggregatorV3Interface.json +606 -606
- avantis_trader_sdk/abis/IPyth.sol/IPyth.dbg.json +4 -4
- avantis_trader_sdk/abis/Referral.sol/ReferralStorage.json +7132 -7132
- avantis_trader_sdk/abis/Sanctions.json +190 -190
- avantis_trader_sdk/abis/Trading.sol/Trading.json +1 -1
- avantis_trader_sdk/abis/USDC.sol/USDC.dbg.json +4 -4
- avantis_trader_sdk/abis/interfaces/ICallbacks.sol/ICallbacks.json +2637 -2637
- avantis_trader_sdk/abis/interfaces/IExecute.sol/IExecute.json +1628 -1628
- avantis_trader_sdk/abis/interfaces/IPairInfos.sol/IPairInfos.json +2781 -2781
- avantis_trader_sdk/abis/interfaces/IPairStorage.sol/IPairStorage.json +3729 -3729
- avantis_trader_sdk/abis/interfaces/IPriceAggregator.sol/IPriceAggregator.json +2330 -2330
- avantis_trader_sdk/abis/interfaces/IReferral.sol/IReferral.json +1890 -1890
- avantis_trader_sdk/abis/interfaces/ITradingStorage.sol/ITradingStorage.json +7022 -7022
- avantis_trader_sdk/abis/interfaces/ITranche.sol/ITranche.json +1283 -1283
- avantis_trader_sdk/abis/interfaces/IVaultManager.sol/IVaultManager.json +2424 -2424
- avantis_trader_sdk/abis/interfaces/IVeTranche.sol/IVeTranche.json +855 -855
- avantis_trader_sdk/abis/library/PositionMath.sol/PositionMath.dbg.json +4 -4
- avantis_trader_sdk/abis/library/PositionMath.sol/PositionMath.json +10 -10
- avantis_trader_sdk/abis/testnet/USDC.sol/USDC.dbg.json +4 -4
- avantis_trader_sdk/abis/testnet/USDC.sol/USDC.json +320 -320
- avantis_trader_sdk/client.py +369 -367
- avantis_trader_sdk/config.py +14 -14
- avantis_trader_sdk/feed/feed_client.py +263 -261
- avantis_trader_sdk/rpc/asset_parameters.py +499 -499
- avantis_trader_sdk/rpc/blended.py +71 -71
- avantis_trader_sdk/rpc/category_parameters.py +216 -216
- avantis_trader_sdk/rpc/fee_parameters.py +237 -237
- avantis_trader_sdk/rpc/pairs_cache.py +130 -130
- avantis_trader_sdk/rpc/rpc_helpers.py +8 -8
- avantis_trader_sdk/rpc/snapshot.py +142 -142
- avantis_trader_sdk/rpc/trade.py +701 -710
- avantis_trader_sdk/rpc/trading_parameters.py +139 -139
- avantis_trader_sdk/types.py +462 -462
- avantis_trader_sdk/utils.py +78 -78
- {avantis_trader_sdk-0.8.2.dist-info → avantis_trader_sdk-0.8.4.dist-info}/METADATA +124 -113
- {avantis_trader_sdk-0.8.2.dist-info → avantis_trader_sdk-0.8.4.dist-info}/RECORD +39 -40
- {avantis_trader_sdk-0.8.2.dist-info → avantis_trader_sdk-0.8.4.dist-info}/WHEEL +1 -1
- avantis_trader_sdk/feed/feedIds.json +0 -214
- {avantis_trader_sdk-0.8.2.dist-info → avantis_trader_sdk-0.8.4.dist-info}/top_level.txt +0 -0
avantis_trader_sdk/config.py
CHANGED
|
@@ -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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
and not ws_url.startswith("
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
self.
|
|
42
|
-
self.
|
|
43
|
-
self.
|
|
44
|
-
self.
|
|
45
|
-
self.
|
|
46
|
-
self.
|
|
47
|
-
self.
|
|
48
|
-
self.
|
|
49
|
-
self.
|
|
50
|
-
self.
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
"""
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
asyncio.
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
pairs = list(pairs)
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
price_feed_id = identifier
|
|
192
|
-
elif identifier in self.
|
|
193
|
-
price_feed_id = identifier
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
self.price_feed_callbacks
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
price_feed_id = identifier
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
price_feed_id = identifier
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
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()
|