sol-parser-sdk-python 0.5.5__py3-none-any.whl → 0.5.7__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.
- sol_parser/__init__.py +26 -0
- sol_parser/account_dispatcher.py +2 -0
- sol_parser/account_fillers/meteora.py +15 -0
- sol_parser/account_fillers/pumpfun.py +11 -0
- sol_parser/accounts/__init__.py +61 -0
- sol_parser/accounts/raydium_orca.py +515 -0
- sol_parser/check_migration.py +3 -0
- sol_parser/dex_parsers.py +1067 -64
- sol_parser/event_type_parity.py +129 -0
- sol_parser/event_types.py +291 -0
- sol_parser/grpc_client.py +25 -6
- sol_parser/grpc_instruction_parser.py +21 -20
- sol_parser/grpc_types.py +49 -21
- sol_parser/inner_instruction_parser.py +138 -12
- sol_parser/instructions.py +299 -58
- sol_parser/log_instr_dedup.py +34 -4
- sol_parser/merger.py +115 -41
- sol_parser/parser.py +95 -7
- sol_parser/pumpfun_fee_enrich.py +12 -1
- sol_parser/rpc_parser.py +119 -33
- sol_parser/shredstream_client.py +19 -1
- {sol_parser_sdk_python-0.5.5.dist-info → sol_parser_sdk_python-0.5.7.dist-info}/METADATA +10 -2
- {sol_parser_sdk_python-0.5.5.dist-info → sol_parser_sdk_python-0.5.7.dist-info}/RECORD +25 -23
- {sol_parser_sdk_python-0.5.5.dist-info → sol_parser_sdk_python-0.5.7.dist-info}/WHEEL +1 -1
- {sol_parser_sdk_python-0.5.5.dist-info → sol_parser_sdk_python-0.5.7.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,515 @@
|
|
|
1
|
+
"""Raydium CLMM/CPMM and Orca Whirlpool account parsers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import struct
|
|
6
|
+
from typing import Any, Callable, Optional, TypeVar
|
|
7
|
+
|
|
8
|
+
import base58
|
|
9
|
+
|
|
10
|
+
from ..dex_parsers import DexEvent
|
|
11
|
+
from ..grpc_types import EventMetadata, EventType
|
|
12
|
+
|
|
13
|
+
RAYDIUM_CLMM_PROGRAM_ID = "CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK"
|
|
14
|
+
RAYDIUM_CPMM_PROGRAM_ID = "CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C"
|
|
15
|
+
ORCA_WHIRLPOOL_PROGRAM_ID = "whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc"
|
|
16
|
+
|
|
17
|
+
CLMM_AMM_CONFIG_DISC = bytes([218, 244, 33, 104, 203, 203, 43, 111])
|
|
18
|
+
CLMM_POOL_STATE_DISC = bytes([247, 237, 227, 245, 215, 195, 222, 70])
|
|
19
|
+
CLMM_TICK_ARRAY_STATE_DISC = bytes([192, 155, 85, 205, 49, 249, 129, 42])
|
|
20
|
+
CLMM_AMM_CONFIG_BODY = 109
|
|
21
|
+
CLMM_POOL_STATE_BODY = 1536
|
|
22
|
+
CLMM_TICK_ARRAY_STATE_BODY = 10232
|
|
23
|
+
CLMM_TICK_ARRAY_LEN = 60
|
|
24
|
+
|
|
25
|
+
CPMM_AMM_CONFIG_DISC = CLMM_AMM_CONFIG_DISC
|
|
26
|
+
CPMM_POOL_STATE_DISC = CLMM_POOL_STATE_DISC
|
|
27
|
+
CPMM_AMM_CONFIG_BODY = 228
|
|
28
|
+
CPMM_POOL_STATE_BODY = 629
|
|
29
|
+
|
|
30
|
+
ORCA_WHIRLPOOL_DISC = bytes([63, 149, 209, 12, 225, 128, 99, 9])
|
|
31
|
+
ORCA_POSITION_DISC = bytes([170, 188, 143, 228, 122, 64, 247, 208])
|
|
32
|
+
ORCA_TICK_ARRAY_DISC = bytes([69, 97, 189, 190, 110, 7, 66, 187])
|
|
33
|
+
ORCA_FEE_TIER_DISC = bytes([56, 75, 159, 76, 142, 68, 190, 105])
|
|
34
|
+
ORCA_WHIRLPOOLS_CONFIG_DISC = bytes([157, 20, 49, 224, 217, 87, 193, 254])
|
|
35
|
+
ORCA_WHIRLPOOL_BODY = 645
|
|
36
|
+
ORCA_POSITION_BODY = 208
|
|
37
|
+
ORCA_TICK_ARRAY_BODY = 9980
|
|
38
|
+
ORCA_FEE_TIER_BODY = 36
|
|
39
|
+
ORCA_WHIRLPOOLS_CONFIG_BODY = 98
|
|
40
|
+
ORCA_TICK_ARRAY_LEN = 88
|
|
41
|
+
|
|
42
|
+
T = TypeVar("T")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class Reader:
|
|
46
|
+
def __init__(self, data: bytes):
|
|
47
|
+
self.data = data
|
|
48
|
+
self.offset = 0
|
|
49
|
+
|
|
50
|
+
def _take(self, size: int) -> int:
|
|
51
|
+
if self.offset + size > len(self.data):
|
|
52
|
+
raise ValueError("account data is truncated")
|
|
53
|
+
start = self.offset
|
|
54
|
+
self.offset += size
|
|
55
|
+
return start
|
|
56
|
+
|
|
57
|
+
def u8(self) -> int:
|
|
58
|
+
return self.data[self._take(1)]
|
|
59
|
+
|
|
60
|
+
def bool(self) -> bool:
|
|
61
|
+
return self.u8() != 0
|
|
62
|
+
|
|
63
|
+
def u16(self) -> int:
|
|
64
|
+
return struct.unpack_from("<H", self.data, self._take(2))[0]
|
|
65
|
+
|
|
66
|
+
def u32(self) -> int:
|
|
67
|
+
return struct.unpack_from("<I", self.data, self._take(4))[0]
|
|
68
|
+
|
|
69
|
+
def i32(self) -> int:
|
|
70
|
+
return struct.unpack_from("<i", self.data, self._take(4))[0]
|
|
71
|
+
|
|
72
|
+
def u64(self) -> int:
|
|
73
|
+
return struct.unpack_from("<Q", self.data, self._take(8))[0]
|
|
74
|
+
|
|
75
|
+
def u128(self) -> int:
|
|
76
|
+
start = self._take(16)
|
|
77
|
+
return int.from_bytes(self.data[start : start + 16], "little", signed=False)
|
|
78
|
+
|
|
79
|
+
def i128(self) -> int:
|
|
80
|
+
start = self._take(16)
|
|
81
|
+
return int.from_bytes(self.data[start : start + 16], "little", signed=True)
|
|
82
|
+
|
|
83
|
+
def pubkey(self) -> str:
|
|
84
|
+
start = self._take(32)
|
|
85
|
+
return base58.b58encode(self.data[start : start + 32]).decode("ascii")
|
|
86
|
+
|
|
87
|
+
def bytes(self, length: int) -> list[int]:
|
|
88
|
+
start = self._take(length)
|
|
89
|
+
return list(self.data[start : start + length])
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _event(event_type: EventType, data: dict[str, Any]) -> DexEvent:
|
|
93
|
+
return DexEvent(type=event_type, data=data)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _parse_body(data: bytes, parse: Callable[[Reader], T]) -> Optional[T]:
|
|
97
|
+
try:
|
|
98
|
+
return parse(Reader(data))
|
|
99
|
+
except (IndexError, struct.error, ValueError):
|
|
100
|
+
return None
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _body_after_discriminator(data: bytes, disc: bytes, body_size: int) -> Optional[bytes]:
|
|
104
|
+
if len(data) < 8 + body_size or not data.startswith(disc):
|
|
105
|
+
return None
|
|
106
|
+
return data[8:]
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _array(count: int, read: Callable[[], T]) -> list[T]:
|
|
110
|
+
return [read() for _ in range(count)]
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def parse_raydium_clmm_account(account: Any, metadata: EventMetadata) -> Optional[DexEvent]:
|
|
114
|
+
if account.owner != RAYDIUM_CLMM_PROGRAM_ID:
|
|
115
|
+
return None
|
|
116
|
+
return (
|
|
117
|
+
parse_raydium_clmm_amm_config(account, metadata)
|
|
118
|
+
or parse_raydium_clmm_pool_state(account, metadata)
|
|
119
|
+
or parse_raydium_clmm_tick_array_state(account, metadata)
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def parse_raydium_cpmm_account(account: Any, metadata: EventMetadata) -> Optional[DexEvent]:
|
|
124
|
+
if account.owner != RAYDIUM_CPMM_PROGRAM_ID:
|
|
125
|
+
return None
|
|
126
|
+
return parse_raydium_cpmm_amm_config(account, metadata) or parse_raydium_cpmm_pool_state(
|
|
127
|
+
account, metadata
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def parse_orca_whirlpool_account(account: Any, metadata: EventMetadata) -> Optional[DexEvent]:
|
|
132
|
+
if account.owner != ORCA_WHIRLPOOL_PROGRAM_ID:
|
|
133
|
+
return None
|
|
134
|
+
return (
|
|
135
|
+
parse_orca_whirlpool(account, metadata)
|
|
136
|
+
or parse_orca_position(account, metadata)
|
|
137
|
+
or parse_orca_tick_array(account, metadata)
|
|
138
|
+
or parse_orca_fee_tier(account, metadata)
|
|
139
|
+
or parse_orca_whirlpools_config(account, metadata)
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def parse_raydium_clmm_amm_config(account: Any, metadata: EventMetadata) -> Optional[DexEvent]:
|
|
144
|
+
body = _body_after_discriminator(account.data, CLMM_AMM_CONFIG_DISC, CLMM_AMM_CONFIG_BODY)
|
|
145
|
+
if body is None:
|
|
146
|
+
return None
|
|
147
|
+
amm_config = _parse_body(
|
|
148
|
+
body,
|
|
149
|
+
lambda r: {
|
|
150
|
+
"bump": r.u8(),
|
|
151
|
+
"index": r.u16(),
|
|
152
|
+
"owner": r.pubkey(),
|
|
153
|
+
"protocol_fee_rate": r.u32(),
|
|
154
|
+
"trade_fee_rate": r.u32(),
|
|
155
|
+
"tick_spacing": r.u16(),
|
|
156
|
+
"fund_fee_rate": r.u32(),
|
|
157
|
+
"padding_u32": r.u32(),
|
|
158
|
+
"fund_owner": r.pubkey(),
|
|
159
|
+
"padding": _array(3, r.u64),
|
|
160
|
+
},
|
|
161
|
+
)
|
|
162
|
+
if amm_config is None:
|
|
163
|
+
return None
|
|
164
|
+
return _event(
|
|
165
|
+
EventType.ACCOUNT_RAYDIUM_CLMM_AMM_CONFIG,
|
|
166
|
+
{"metadata": metadata, "pubkey": account.pubkey, "amm_config": amm_config},
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def parse_raydium_clmm_pool_state(account: Any, metadata: EventMetadata) -> Optional[DexEvent]:
|
|
171
|
+
body = _body_after_discriminator(account.data, CLMM_POOL_STATE_DISC, CLMM_POOL_STATE_BODY)
|
|
172
|
+
if body is None:
|
|
173
|
+
return None
|
|
174
|
+
pool_state = _parse_body(body, _read_clmm_pool_state)
|
|
175
|
+
if pool_state is None:
|
|
176
|
+
return None
|
|
177
|
+
return _event(
|
|
178
|
+
EventType.ACCOUNT_RAYDIUM_CLMM_POOL_STATE,
|
|
179
|
+
{"metadata": metadata, "pubkey": account.pubkey, "pool_state": pool_state},
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def _read_clmm_pool_state(r: Reader) -> dict[str, Any]:
|
|
184
|
+
return {
|
|
185
|
+
"bump": [r.u8()],
|
|
186
|
+
"amm_config": r.pubkey(),
|
|
187
|
+
"owner": r.pubkey(),
|
|
188
|
+
"token_mint_0": r.pubkey(),
|
|
189
|
+
"token_mint_1": r.pubkey(),
|
|
190
|
+
"token_vault_0": r.pubkey(),
|
|
191
|
+
"token_vault_1": r.pubkey(),
|
|
192
|
+
"observation_key": r.pubkey(),
|
|
193
|
+
"mint_decimals_0": r.u8(),
|
|
194
|
+
"mint_decimals_1": r.u8(),
|
|
195
|
+
"tick_spacing": r.u16(),
|
|
196
|
+
"liquidity": r.u128(),
|
|
197
|
+
"sqrt_price_x64": r.u128(),
|
|
198
|
+
"tick_current": r.i32(),
|
|
199
|
+
"padding3": r.u16(),
|
|
200
|
+
"padding4": r.u16(),
|
|
201
|
+
"fee_growth_global_0_x64": r.u128(),
|
|
202
|
+
"fee_growth_global_1_x64": r.u128(),
|
|
203
|
+
"protocol_fees_token_0": r.u64(),
|
|
204
|
+
"protocol_fees_token_1": r.u64(),
|
|
205
|
+
"padding5": _array(4, r.u128),
|
|
206
|
+
"status": r.u8(),
|
|
207
|
+
"fee_on": r.u8(),
|
|
208
|
+
"padding": r.bytes(6),
|
|
209
|
+
"reward_infos": _array(3, lambda: _read_clmm_reward_info(r)),
|
|
210
|
+
"tick_array_bitmap": _array(16, r.u64),
|
|
211
|
+
"padding6": _array(4, r.u64),
|
|
212
|
+
"fund_fees_token_0": r.u64(),
|
|
213
|
+
"fund_fees_token_1": r.u64(),
|
|
214
|
+
"open_time": r.u64(),
|
|
215
|
+
"recent_epoch": r.u64(),
|
|
216
|
+
"dynamic_fee_info": _read_clmm_dynamic_fee_info(r),
|
|
217
|
+
"padding1": _array(14, r.u64),
|
|
218
|
+
"padding2": _array(32, r.u64),
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def parse_raydium_clmm_tick_array_state(account: Any, metadata: EventMetadata) -> Optional[DexEvent]:
|
|
223
|
+
body = _body_after_discriminator(account.data, CLMM_TICK_ARRAY_STATE_DISC, CLMM_TICK_ARRAY_STATE_BODY)
|
|
224
|
+
if body is None:
|
|
225
|
+
return None
|
|
226
|
+
tick_array_state = _parse_body(
|
|
227
|
+
body,
|
|
228
|
+
lambda r: {
|
|
229
|
+
"pool_id": r.pubkey(),
|
|
230
|
+
"start_tick_index": r.i32(),
|
|
231
|
+
"ticks": _array(CLMM_TICK_ARRAY_LEN, lambda: _read_clmm_tick(r)),
|
|
232
|
+
"initialized_tick_count": r.u8(),
|
|
233
|
+
"recent_epoch": r.u64(),
|
|
234
|
+
"padding": r.bytes(107),
|
|
235
|
+
},
|
|
236
|
+
)
|
|
237
|
+
if tick_array_state is None:
|
|
238
|
+
return None
|
|
239
|
+
return _event(
|
|
240
|
+
EventType.ACCOUNT_RAYDIUM_CLMM_TICK_ARRAY_STATE,
|
|
241
|
+
{"metadata": metadata, "pubkey": account.pubkey, "tick_array_state": tick_array_state},
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def _read_clmm_reward_info(r: Reader) -> dict[str, Any]:
|
|
246
|
+
return {
|
|
247
|
+
"reward_state": r.u8(),
|
|
248
|
+
"open_time": r.u64(),
|
|
249
|
+
"end_time": r.u64(),
|
|
250
|
+
"last_update_time": r.u64(),
|
|
251
|
+
"emissions_per_second_x64": r.u128(),
|
|
252
|
+
"reward_total_emitted": r.u64(),
|
|
253
|
+
"reward_claimed": r.u64(),
|
|
254
|
+
"token_mint": r.pubkey(),
|
|
255
|
+
"token_vault": r.pubkey(),
|
|
256
|
+
"authority": r.pubkey(),
|
|
257
|
+
"reward_growth_global_x64": r.u128(),
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def _read_clmm_dynamic_fee_info(r: Reader) -> dict[str, Any]:
|
|
262
|
+
return {
|
|
263
|
+
"filter_period": r.u16(),
|
|
264
|
+
"decay_period": r.u16(),
|
|
265
|
+
"reduction_factor": r.u16(),
|
|
266
|
+
"dynamic_fee_control": r.u32(),
|
|
267
|
+
"max_volatility_accumulator": r.u32(),
|
|
268
|
+
"tick_spacing_index_reference": r.i32(),
|
|
269
|
+
"volatility_reference": r.u32(),
|
|
270
|
+
"volatility_accumulator": r.u32(),
|
|
271
|
+
"last_update_timestamp": r.u64(),
|
|
272
|
+
"padding": r.bytes(46),
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def _read_clmm_tick(r: Reader) -> dict[str, Any]:
|
|
277
|
+
return {
|
|
278
|
+
"tick": r.i32(),
|
|
279
|
+
"liquidity_net": r.i128(),
|
|
280
|
+
"liquidity_gross": r.u128(),
|
|
281
|
+
"fee_growth_outside_0_x64": r.u128(),
|
|
282
|
+
"fee_growth_outside_1_x64": r.u128(),
|
|
283
|
+
"reward_growths_outside_x64": _array(3, r.u128),
|
|
284
|
+
"order_phase": r.u64(),
|
|
285
|
+
"orders_amount": r.u64(),
|
|
286
|
+
"part_filled_orders_remaining": r.u64(),
|
|
287
|
+
"unfilled_ratio_x64": r.u128(),
|
|
288
|
+
"padding": _array(3, r.u32),
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def parse_raydium_cpmm_amm_config(account: Any, metadata: EventMetadata) -> Optional[DexEvent]:
|
|
293
|
+
body = _body_after_discriminator(account.data, CPMM_AMM_CONFIG_DISC, CPMM_AMM_CONFIG_BODY)
|
|
294
|
+
if body is None:
|
|
295
|
+
return None
|
|
296
|
+
amm_config = _parse_body(
|
|
297
|
+
body,
|
|
298
|
+
lambda r: {
|
|
299
|
+
"bump": r.u8(),
|
|
300
|
+
"disable_create_pool": r.bool(),
|
|
301
|
+
"index": r.u16(),
|
|
302
|
+
"trade_fee_rate": r.u64(),
|
|
303
|
+
"protocol_fee_rate": r.u64(),
|
|
304
|
+
"fund_fee_rate": r.u64(),
|
|
305
|
+
"create_pool_fee": r.u64(),
|
|
306
|
+
"protocol_owner": r.pubkey(),
|
|
307
|
+
"fund_owner": r.pubkey(),
|
|
308
|
+
"creator_fee_rate": r.u64(),
|
|
309
|
+
"padding": _array(15, r.u64),
|
|
310
|
+
},
|
|
311
|
+
)
|
|
312
|
+
if amm_config is None:
|
|
313
|
+
return None
|
|
314
|
+
return _event(
|
|
315
|
+
EventType.ACCOUNT_RAYDIUM_CPMM_AMM_CONFIG,
|
|
316
|
+
{"metadata": metadata, "pubkey": account.pubkey, "amm_config": amm_config},
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
def parse_raydium_cpmm_pool_state(account: Any, metadata: EventMetadata) -> Optional[DexEvent]:
|
|
321
|
+
body = _body_after_discriminator(account.data, CPMM_POOL_STATE_DISC, CPMM_POOL_STATE_BODY)
|
|
322
|
+
if body is None:
|
|
323
|
+
return None
|
|
324
|
+
pool_state = _parse_body(body, _read_cpmm_pool_state)
|
|
325
|
+
if pool_state is None:
|
|
326
|
+
return None
|
|
327
|
+
return _event(
|
|
328
|
+
EventType.ACCOUNT_RAYDIUM_CPMM_POOL_STATE,
|
|
329
|
+
{"metadata": metadata, "pubkey": account.pubkey, "pool_state": pool_state},
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
def _read_cpmm_pool_state(r: Reader) -> dict[str, Any]:
|
|
334
|
+
return {
|
|
335
|
+
"amm_config": r.pubkey(),
|
|
336
|
+
"pool_creator": r.pubkey(),
|
|
337
|
+
"token_0_vault": r.pubkey(),
|
|
338
|
+
"token_1_vault": r.pubkey(),
|
|
339
|
+
"lp_mint": r.pubkey(),
|
|
340
|
+
"token_0_mint": r.pubkey(),
|
|
341
|
+
"token_1_mint": r.pubkey(),
|
|
342
|
+
"token_0_program": r.pubkey(),
|
|
343
|
+
"token_1_program": r.pubkey(),
|
|
344
|
+
"observation_key": r.pubkey(),
|
|
345
|
+
"auth_bump": r.u8(),
|
|
346
|
+
"status": r.u8(),
|
|
347
|
+
"lp_mint_decimals": r.u8(),
|
|
348
|
+
"mint_0_decimals": r.u8(),
|
|
349
|
+
"mint_1_decimals": r.u8(),
|
|
350
|
+
"lp_supply": r.u64(),
|
|
351
|
+
"protocol_fees_token_0": r.u64(),
|
|
352
|
+
"protocol_fees_token_1": r.u64(),
|
|
353
|
+
"fund_fees_token_0": r.u64(),
|
|
354
|
+
"fund_fees_token_1": r.u64(),
|
|
355
|
+
"open_time": r.u64(),
|
|
356
|
+
"recent_epoch": r.u64(),
|
|
357
|
+
"creator_fee_on": r.u8(),
|
|
358
|
+
"enable_creator_fee": r.bool(),
|
|
359
|
+
"padding1": r.bytes(6),
|
|
360
|
+
"creator_fees_token_0": r.u64(),
|
|
361
|
+
"creator_fees_token_1": r.u64(),
|
|
362
|
+
"padding": _array(28, r.u64),
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
def parse_orca_whirlpool(account: Any, metadata: EventMetadata) -> Optional[DexEvent]:
|
|
367
|
+
body = _body_after_discriminator(account.data, ORCA_WHIRLPOOL_DISC, ORCA_WHIRLPOOL_BODY)
|
|
368
|
+
if body is None:
|
|
369
|
+
return None
|
|
370
|
+
whirlpool = _parse_body(
|
|
371
|
+
body,
|
|
372
|
+
lambda r: {
|
|
373
|
+
"whirlpools_config": r.pubkey(),
|
|
374
|
+
"whirlpool_bump": r.u8(),
|
|
375
|
+
"tick_spacing": r.u16(),
|
|
376
|
+
"tick_spacing_seed": r.bytes(2),
|
|
377
|
+
"fee_rate": r.u16(),
|
|
378
|
+
"protocol_fee_rate": r.u16(),
|
|
379
|
+
"liquidity": r.u128(),
|
|
380
|
+
"sqrt_price": r.u128(),
|
|
381
|
+
"tick_current_index": r.i32(),
|
|
382
|
+
"protocol_fee_owed_a": r.u64(),
|
|
383
|
+
"protocol_fee_owed_b": r.u64(),
|
|
384
|
+
"token_mint_a": r.pubkey(),
|
|
385
|
+
"token_vault_a": r.pubkey(),
|
|
386
|
+
"fee_growth_global_a": r.u128(),
|
|
387
|
+
"token_mint_b": r.pubkey(),
|
|
388
|
+
"token_vault_b": r.pubkey(),
|
|
389
|
+
"fee_growth_global_b": r.u128(),
|
|
390
|
+
"reward_last_updated_timestamp": r.u64(),
|
|
391
|
+
"reward_infos": _array(3, lambda: _read_orca_whirlpool_reward_info(r)),
|
|
392
|
+
},
|
|
393
|
+
)
|
|
394
|
+
if whirlpool is None:
|
|
395
|
+
return None
|
|
396
|
+
return _event(
|
|
397
|
+
EventType.ACCOUNT_ORCA_WHIRLPOOL,
|
|
398
|
+
{"metadata": metadata, "pubkey": account.pubkey, "whirlpool": whirlpool},
|
|
399
|
+
)
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
def parse_orca_position(account: Any, metadata: EventMetadata) -> Optional[DexEvent]:
|
|
403
|
+
body = _body_after_discriminator(account.data, ORCA_POSITION_DISC, ORCA_POSITION_BODY)
|
|
404
|
+
if body is None:
|
|
405
|
+
return None
|
|
406
|
+
position = _parse_body(
|
|
407
|
+
body,
|
|
408
|
+
lambda r: {
|
|
409
|
+
"whirlpool": r.pubkey(),
|
|
410
|
+
"position_mint": r.pubkey(),
|
|
411
|
+
"liquidity": r.u128(),
|
|
412
|
+
"tick_lower_index": r.i32(),
|
|
413
|
+
"tick_upper_index": r.i32(),
|
|
414
|
+
"fee_growth_checkpoint_a": r.u128(),
|
|
415
|
+
"fee_owed_a": r.u64(),
|
|
416
|
+
"fee_growth_checkpoint_b": r.u128(),
|
|
417
|
+
"fee_owed_b": r.u64(),
|
|
418
|
+
"reward_infos": _array(3, lambda: _read_orca_position_reward_info(r)),
|
|
419
|
+
},
|
|
420
|
+
)
|
|
421
|
+
if position is None:
|
|
422
|
+
return None
|
|
423
|
+
return _event(
|
|
424
|
+
EventType.ACCOUNT_ORCA_POSITION,
|
|
425
|
+
{"metadata": metadata, "pubkey": account.pubkey, "position": position},
|
|
426
|
+
)
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
def parse_orca_tick_array(account: Any, metadata: EventMetadata) -> Optional[DexEvent]:
|
|
430
|
+
body = _body_after_discriminator(account.data, ORCA_TICK_ARRAY_DISC, ORCA_TICK_ARRAY_BODY)
|
|
431
|
+
if body is None:
|
|
432
|
+
return None
|
|
433
|
+
tick_array = _parse_body(
|
|
434
|
+
body,
|
|
435
|
+
lambda r: {
|
|
436
|
+
"start_tick_index": r.i32(),
|
|
437
|
+
"ticks": _array(ORCA_TICK_ARRAY_LEN, lambda: _read_orca_tick(r)),
|
|
438
|
+
"whirlpool": r.pubkey(),
|
|
439
|
+
},
|
|
440
|
+
)
|
|
441
|
+
if tick_array is None:
|
|
442
|
+
return None
|
|
443
|
+
return _event(
|
|
444
|
+
EventType.ACCOUNT_ORCA_TICK_ARRAY,
|
|
445
|
+
{"metadata": metadata, "pubkey": account.pubkey, "tick_array": tick_array},
|
|
446
|
+
)
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
def parse_orca_fee_tier(account: Any, metadata: EventMetadata) -> Optional[DexEvent]:
|
|
450
|
+
body = _body_after_discriminator(account.data, ORCA_FEE_TIER_DISC, ORCA_FEE_TIER_BODY)
|
|
451
|
+
if body is None:
|
|
452
|
+
return None
|
|
453
|
+
fee_tier = _parse_body(
|
|
454
|
+
body,
|
|
455
|
+
lambda r: {
|
|
456
|
+
"whirlpools_config": r.pubkey(),
|
|
457
|
+
"tick_spacing": r.u16(),
|
|
458
|
+
"default_fee_rate": r.u16(),
|
|
459
|
+
},
|
|
460
|
+
)
|
|
461
|
+
if fee_tier is None:
|
|
462
|
+
return None
|
|
463
|
+
return _event(
|
|
464
|
+
EventType.ACCOUNT_ORCA_FEE_TIER,
|
|
465
|
+
{"metadata": metadata, "pubkey": account.pubkey, "fee_tier": fee_tier},
|
|
466
|
+
)
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
def parse_orca_whirlpools_config(account: Any, metadata: EventMetadata) -> Optional[DexEvent]:
|
|
470
|
+
body = _body_after_discriminator(account.data, ORCA_WHIRLPOOLS_CONFIG_DISC, ORCA_WHIRLPOOLS_CONFIG_BODY)
|
|
471
|
+
if body is None:
|
|
472
|
+
return None
|
|
473
|
+
config = _parse_body(
|
|
474
|
+
body,
|
|
475
|
+
lambda r: {
|
|
476
|
+
"fee_authority": r.pubkey(),
|
|
477
|
+
"collect_protocol_fees_authority": r.pubkey(),
|
|
478
|
+
"reward_emissions_super_authority": r.pubkey(),
|
|
479
|
+
"default_protocol_fee_rate": r.u16(),
|
|
480
|
+
},
|
|
481
|
+
)
|
|
482
|
+
if config is None:
|
|
483
|
+
return None
|
|
484
|
+
return _event(
|
|
485
|
+
EventType.ACCOUNT_ORCA_WHIRLPOOLS_CONFIG,
|
|
486
|
+
{"metadata": metadata, "pubkey": account.pubkey, "config": config},
|
|
487
|
+
)
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
def _read_orca_whirlpool_reward_info(r: Reader) -> dict[str, Any]:
|
|
491
|
+
return {
|
|
492
|
+
"mint": r.pubkey(),
|
|
493
|
+
"vault": r.pubkey(),
|
|
494
|
+
"authority": r.pubkey(),
|
|
495
|
+
"emissions_per_second_x64": r.u128(),
|
|
496
|
+
"growth_global_x64": r.u128(),
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
def _read_orca_position_reward_info(r: Reader) -> dict[str, Any]:
|
|
501
|
+
return {
|
|
502
|
+
"growth_inside_checkpoint": r.u128(),
|
|
503
|
+
"amount_owed": r.u64(),
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
def _read_orca_tick(r: Reader) -> dict[str, Any]:
|
|
508
|
+
return {
|
|
509
|
+
"initialized": r.bool(),
|
|
510
|
+
"liquidity_net": r.i128(),
|
|
511
|
+
"liquidity_gross": r.u128(),
|
|
512
|
+
"fee_growth_outside_a": r.u128(),
|
|
513
|
+
"fee_growth_outside_b": r.u128(),
|
|
514
|
+
"reward_growths_outside": _array(3, r.u128),
|
|
515
|
+
}
|
sol_parser/check_migration.py
CHANGED
|
@@ -6,11 +6,14 @@ import sys
|
|
|
6
6
|
|
|
7
7
|
from .u128_parity import run_all_u128_checks
|
|
8
8
|
from .verify_discriminators import main as _verify_main
|
|
9
|
+
from .event_type_parity import run_event_type_parity_check
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
def main() -> None:
|
|
12
13
|
if _verify_main() != 0:
|
|
13
14
|
sys.exit(1)
|
|
15
|
+
if run_event_type_parity_check() != 0:
|
|
16
|
+
sys.exit(1)
|
|
14
17
|
sys.exit(run_all_u128_checks())
|
|
15
18
|
|
|
16
19
|
|