sol-parser-sdk-python 0.4.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 (54) hide show
  1. sol_parser/__init__.py +400 -0
  2. sol_parser/account_dispatcher.py +209 -0
  3. sol_parser/account_fillers/__init__.py +5 -0
  4. sol_parser/account_fillers/bonk.py +30 -0
  5. sol_parser/account_fillers/meteora.py +51 -0
  6. sol_parser/account_fillers/orca.py +40 -0
  7. sol_parser/account_fillers/pumpfun.py +97 -0
  8. sol_parser/account_fillers/pumpswap.py +93 -0
  9. sol_parser/account_fillers/raydium.py +119 -0
  10. sol_parser/accounts/__init__.py +461 -0
  11. sol_parser/accounts/rpc_wallet.py +64 -0
  12. sol_parser/accounts/utils.py +71 -0
  13. sol_parser/check_migration.py +18 -0
  14. sol_parser/clock.py +10 -0
  15. sol_parser/common/__init__.py +27 -0
  16. sol_parser/dex_parsers.py +2576 -0
  17. sol_parser/entries_decode.py +186 -0
  18. sol_parser/env_config.py +215 -0
  19. sol_parser/event_types.py +1750 -0
  20. sol_parser/geyser_pb2.py +148 -0
  21. sol_parser/geyser_pb2_grpc.py +398 -0
  22. sol_parser/grpc/__init__.py +61 -0
  23. sol_parser/grpc/geyser_connect.py +42 -0
  24. sol_parser/grpc/subscribe_builder.py +133 -0
  25. sol_parser/grpc/transaction_meta.py +183 -0
  26. sol_parser/grpc_client.py +870 -0
  27. sol_parser/grpc_instruction_parser.py +318 -0
  28. sol_parser/grpc_types.py +919 -0
  29. sol_parser/inner_instruction_parser.py +281 -0
  30. sol_parser/instr/__init__.py +15 -0
  31. sol_parser/instr_account_utils.py +58 -0
  32. sol_parser/instructions.py +1026 -0
  33. sol_parser/json_util.py +41 -0
  34. sol_parser/log_instr_dedup.py +284 -0
  35. sol_parser/logs/__init__.py +15 -0
  36. sol_parser/merger.py +233 -0
  37. sol_parser/order_buffer.py +171 -0
  38. sol_parser/parser.py +300 -0
  39. sol_parser/pumpfun_fee_enrich.py +75 -0
  40. sol_parser/rpc_parser.py +655 -0
  41. sol_parser/rust_api_inventory.py +42 -0
  42. sol_parser/rust_event_json.py +50 -0
  43. sol_parser/shredstream_client.py +191 -0
  44. sol_parser/shredstream_pb2.py +40 -0
  45. sol_parser/shredstream_pb2_grpc.py +81 -0
  46. sol_parser/shredstream_pumpfun.py +296 -0
  47. sol_parser/solana_storage_pb2.py +75 -0
  48. sol_parser/solana_storage_pb2_grpc.py +24 -0
  49. sol_parser/u128_parity.py +115 -0
  50. sol_parser/verify_discriminators.py +85 -0
  51. sol_parser_sdk_python-0.4.4.dist-info/METADATA +14 -0
  52. sol_parser_sdk_python-0.4.4.dist-info/RECORD +54 -0
  53. sol_parser_sdk_python-0.4.4.dist-info/WHEEL +4 -0
  54. sol_parser_sdk_python-0.4.4.dist-info/entry_points.txt +4 -0
@@ -0,0 +1,281 @@
1
+ """Inner instruction 解析(16 字节 discriminator),对齐 Rust ``grpc/instruction_parser::parse_inner_instruction``。"""
2
+
3
+ from __future__ import annotations
4
+
5
+ import struct
6
+ from typing import Optional
7
+
8
+ from .dex_parsers import (
9
+ _parse_bonk_trade,
10
+ parse_amm_deposit_from_data,
11
+ parse_amm_swap_in_from_data,
12
+ parse_amm_swap_out_from_data,
13
+ parse_amm_withdraw_from_data,
14
+ parse_clmm_collect_from_data,
15
+ parse_clmm_create_from_data,
16
+ parse_clmm_dec_from_data,
17
+ parse_clmm_inc_from_data,
18
+ parse_clmm_swap_from_data,
19
+ parse_cpmm_deposit_from_data,
20
+ parse_cpmm_swap_in_from_data,
21
+ parse_cpmm_swap_out_from_data,
22
+ parse_cpmm_withdraw_from_data,
23
+ parse_dlmm_from_program_data,
24
+ parse_meteora_damm_from_buf,
25
+ parse_orca_liq_dec_from_data,
26
+ parse_orca_liq_inc_from_data,
27
+ parse_orca_traded_from_data,
28
+ parse_ps_add_liq_from_data,
29
+ parse_ps_buy_from_data,
30
+ parse_ps_create_pool_from_data,
31
+ parse_ps_remove_liq_from_data,
32
+ parse_ps_sell_from_data,
33
+ parse_create_from_data,
34
+ parse_migrate_from_data,
35
+ parse_trade_from_data,
36
+ _make_meta,
37
+ )
38
+ from .event_types import (
39
+ DexEvent,
40
+ MeteoraPoolsAddLiquidityEvent,
41
+ MeteoraPoolsRemoveLiquidityEvent,
42
+ MeteoraPoolsSwapEvent,
43
+ )
44
+ from .grpc_types import EventType, EventTypeFilter, IncludeOnlyFilter
45
+ from .grpc_types import (
46
+ event_type_filter_includes_meteora_damm_v2,
47
+ event_type_filter_includes_pumpfun,
48
+ event_type_filter_includes_pumpswap,
49
+ )
50
+ from .instructions import (
51
+ BONK_LAUNCHPAD_PROGRAM_ID,
52
+ METEORA_DAMM_V2_PROGRAM_ID,
53
+ METEORA_DLMM_PROGRAM_ID,
54
+ METEORA_POOLS_PROGRAM_ID,
55
+ ORCA_WHIRLPOOL_PROGRAM_ID,
56
+ PUMPFUN_PROGRAM_ID,
57
+ PUMPSWAP_PROGRAM_ID,
58
+ RAYDIUM_AMM_V4_PROGRAM_ID,
59
+ RAYDIUM_CLMM_PROGRAM_ID,
60
+ RAYDIUM_CPMM_PROGRAM_ID,
61
+ )
62
+ # PumpFun inner(Rust pump_inner::discriminators)
63
+ _PUMPFUN_INNER_TRADE = bytes([189, 219, 127, 211, 78, 230, 97, 238, 155, 167, 108, 32, 122, 76, 173, 64])
64
+ _PUMPFUN_INNER_CREATE = bytes([27, 114, 169, 77, 222, 235, 99, 118, 155, 167, 108, 32, 122, 76, 173, 64])
65
+ _PUMPFUN_INNER_MIGRATE = bytes([189, 233, 93, 185, 92, 148, 234, 148, 155, 167, 108, 32, 122, 76, 173, 64])
66
+
67
+ # PumpSwap AMM(Rust pump_amm_inner::discriminators)
68
+ _PS_BUY = bytes([228, 69, 165, 46, 81, 203, 154, 29, 103, 244, 82, 31, 44, 245, 119, 119])
69
+ _PS_SELL = bytes([228, 69, 165, 46, 81, 203, 154, 29, 62, 47, 55, 10, 165, 3, 220, 42])
70
+ _PS_CREATE_POOL = bytes([228, 69, 165, 46, 81, 203, 154, 29, 177, 49, 12, 210, 160, 118, 167, 116])
71
+ _PS_ADD_LIQ = bytes([228, 69, 165, 46, 81, 203, 154, 29, 120, 248, 61, 83, 31, 142, 107, 144])
72
+ _PS_REMOVE_LIQ = bytes([228, 69, 165, 46, 81, 203, 154, 29, 22, 9, 133, 26, 160, 44, 71, 192])
73
+
74
+ # Raydium CLMM(raydium_clmm_inner::discriminators)
75
+ _CLMM_SWAP = bytes([248, 198, 158, 145, 225, 117, 135, 200, 155, 167, 108, 32, 122, 76, 173, 64])
76
+ _CLMM_INC = bytes([133, 29, 89, 223, 69, 238, 176, 10, 155, 167, 108, 32, 122, 76, 173, 64])
77
+ _CLMM_DEC = bytes([160, 38, 208, 111, 104, 91, 44, 1, 155, 167, 108, 32, 122, 76, 173, 64])
78
+ _CLMM_CREATE_POOL = bytes([233, 146, 209, 142, 207, 104, 64, 188, 155, 167, 108, 32, 122, 76, 173, 64])
79
+ _CLMM_COLLECT_FEE = bytes([164, 152, 207, 99, 187, 104, 171, 119, 155, 167, 108, 32, 122, 76, 173, 64])
80
+
81
+ # Raydium CPMM(all_inner::raydium_cpmm::discriminators)
82
+ _CPMM_SWAP_IN = bytes([143, 190, 90, 218, 196, 30, 51, 222, 155, 167, 108, 32, 122, 76, 173, 64])
83
+ _CPMM_SWAP_OUT = bytes([55, 217, 98, 86, 163, 74, 180, 173, 155, 167, 108, 32, 122, 76, 173, 64])
84
+ _CPMM_DEP = bytes([242, 35, 198, 137, 82, 225, 242, 182, 155, 167, 108, 32, 122, 76, 173, 64])
85
+ _CPMM_WIT = bytes([183, 18, 70, 156, 148, 109, 161, 34, 155, 167, 108, 32, 122, 76, 173, 64])
86
+
87
+ # Raydium AMM V4
88
+ _AMM_SWAP_IN = bytes([0, 0, 0, 0, 0, 0, 0, 9, 155, 167, 108, 32, 122, 76, 173, 64])
89
+ _AMM_SWAP_OUT = bytes([0, 0, 0, 0, 0, 0, 0, 11, 155, 167, 108, 32, 122, 76, 173, 64])
90
+ _AMM_DEP = bytes([0, 0, 0, 0, 0, 0, 0, 3, 155, 167, 108, 32, 122, 76, 173, 64])
91
+ _AMM_WIT = bytes([0, 0, 0, 0, 0, 0, 0, 4, 155, 167, 108, 32, 122, 76, 173, 64])
92
+
93
+ # Orca
94
+ _ORCA_TRADED = bytes([225, 202, 73, 175, 147, 43, 160, 150, 155, 167, 108, 32, 122, 76, 173, 64])
95
+ _ORCA_LIQ_INC = bytes([30, 7, 144, 181, 102, 254, 155, 161, 155, 167, 108, 32, 122, 76, 173, 64])
96
+ _ORCA_LIQ_DEC = bytes([166, 1, 36, 71, 112, 202, 181, 171, 155, 167, 108, 32, 122, 76, 173, 64])
97
+
98
+ # Meteora Pools AMM
99
+ _MP_SWAP = bytes([81, 108, 227, 190, 205, 208, 10, 196, 155, 167, 108, 32, 122, 76, 173, 64])
100
+ _MP_ADD = bytes([31, 94, 125, 90, 227, 52, 61, 186, 155, 167, 108, 32, 122, 76, 173, 64])
101
+ _MP_REM = bytes([116, 244, 97, 232, 103, 31, 152, 58, 155, 167, 108, 32, 122, 76, 173, 64])
102
+
103
+ # Meteora DAMM V2(inner 16 字节:magic + 8 字节 event disc,与 ``parse_meteora_damm_from_buf`` 的 disc 一致)
104
+ def _damm_buf_from_inner(disc16: bytes, inner: bytes) -> bytes:
105
+ return disc16[8:16] + inner
106
+
107
+ # Bonk inner
108
+ _BONK_TRADE = bytes([80, 120, 100, 200, 150, 75, 60, 40, 155, 167, 108, 32, 122, 76, 173, 64])
109
+
110
+ # DLMM(8 字节 event disc + payload)
111
+ def _dlmm_buf_from_inner(disc16: bytes, inner: bytes) -> bytes:
112
+ return disc16[8:16] + inner
113
+
114
+
115
+ def _meteora_pools_swap_inner(data: bytes, meta_d: dict) -> Optional[DexEvent]:
116
+ if len(data) < 16:
117
+ return None
118
+ ia = struct.unpack_from("<Q", data, 0)[0]
119
+ oa = struct.unpack_from("<Q", data, 8)[0]
120
+ return DexEvent(
121
+ type=EventType.METEORA_POOLS_SWAP,
122
+ data=MeteoraPoolsSwapEvent(
123
+ metadata=_make_meta(meta_d),
124
+ in_amount=ia,
125
+ out_amount=oa,
126
+ trade_fee=0,
127
+ admin_fee=0,
128
+ host_fee=0,
129
+ ),
130
+ )
131
+
132
+
133
+ def _meteora_pools_add_inner(data: bytes, meta_d: dict) -> Optional[DexEvent]:
134
+ if len(data) < 24:
135
+ return None
136
+ lp = struct.unpack_from("<Q", data, 0)[0]
137
+ ta = struct.unpack_from("<Q", data, 8)[0]
138
+ tb = struct.unpack_from("<Q", data, 16)[0]
139
+ return DexEvent(
140
+ type=EventType.METEORA_POOLS_ADD_LIQUIDITY,
141
+ data=MeteoraPoolsAddLiquidityEvent(
142
+ metadata=_make_meta(meta_d),
143
+ lp_mint_amount=lp,
144
+ token_a_amount=ta,
145
+ token_b_amount=tb,
146
+ ),
147
+ )
148
+
149
+
150
+ def _meteora_pools_rem_inner(data: bytes, meta_d: dict) -> Optional[DexEvent]:
151
+ if len(data) < 24:
152
+ return None
153
+ lp = struct.unpack_from("<Q", data, 0)[0]
154
+ ta = struct.unpack_from("<Q", data, 8)[0]
155
+ tb = struct.unpack_from("<Q", data, 16)[0]
156
+ return DexEvent(
157
+ type=EventType.METEORA_POOLS_REMOVE_LIQUIDITY,
158
+ data=MeteoraPoolsRemoveLiquidityEvent(
159
+ metadata=_make_meta(meta_d),
160
+ lp_unmint_amount=lp,
161
+ token_a_out_amount=ta,
162
+ token_b_out_amount=tb,
163
+ ),
164
+ )
165
+
166
+
167
+ def _bonk_trade_inner(data: bytes, meta_d: dict) -> Optional[DexEvent]:
168
+ if len(data) < 81:
169
+ return None
170
+ return _parse_bonk_trade(data, meta_d)
171
+
172
+
173
+ def parse_inner_instruction(
174
+ data: bytes,
175
+ program_id_b58: str,
176
+ meta_d: dict,
177
+ filter: Optional[EventTypeFilter],
178
+ is_created_buy: bool,
179
+ ) -> Optional[DexEvent]:
180
+ if len(data) < 16:
181
+ return None
182
+ disc16 = bytes(data[:16])
183
+ inner = data[16:]
184
+ f: EventTypeFilter = filter if filter is not None else IncludeOnlyFilter([])
185
+
186
+ if program_id_b58 == PUMPFUN_PROGRAM_ID:
187
+ if not event_type_filter_includes_pumpfun(f):
188
+ return None
189
+ if disc16 == _PUMPFUN_INNER_TRADE:
190
+ ev = parse_trade_from_data(inner, meta_d, is_created_buy)
191
+ return ev if ev.is_valid() else None
192
+ if disc16 == _PUMPFUN_INNER_CREATE:
193
+ ev = parse_create_from_data(inner, meta_d)
194
+ return ev if ev.is_valid() else None
195
+ if disc16 == _PUMPFUN_INNER_MIGRATE:
196
+ ev = parse_migrate_from_data(inner, meta_d)
197
+ return ev if ev.is_valid() else None
198
+ return None
199
+
200
+ if program_id_b58 == PUMPSWAP_PROGRAM_ID:
201
+ if not event_type_filter_includes_pumpswap(f):
202
+ return None
203
+ if disc16 == _PS_BUY:
204
+ return parse_ps_buy_from_data(inner, meta_d)
205
+ if disc16 == _PS_SELL:
206
+ return parse_ps_sell_from_data(inner, meta_d)
207
+ if disc16 == _PS_CREATE_POOL:
208
+ return parse_ps_create_pool_from_data(inner, meta_d)
209
+ if disc16 == _PS_ADD_LIQ:
210
+ return parse_ps_add_liq_from_data(inner, meta_d)
211
+ if disc16 == _PS_REMOVE_LIQ:
212
+ return parse_ps_remove_liq_from_data(inner, meta_d)
213
+ return None
214
+
215
+ if program_id_b58 == RAYDIUM_CLMM_PROGRAM_ID:
216
+ if disc16 == _CLMM_SWAP:
217
+ return parse_clmm_swap_from_data(inner, meta_d)
218
+ if disc16 == _CLMM_INC:
219
+ return parse_clmm_inc_from_data(inner, meta_d)
220
+ if disc16 == _CLMM_DEC:
221
+ return parse_clmm_dec_from_data(inner, meta_d)
222
+ if disc16 == _CLMM_CREATE_POOL:
223
+ return parse_clmm_create_from_data(inner, meta_d)
224
+ if disc16 == _CLMM_COLLECT_FEE:
225
+ return parse_clmm_collect_from_data(inner, meta_d)
226
+ return None
227
+
228
+ if program_id_b58 == RAYDIUM_CPMM_PROGRAM_ID:
229
+ if disc16 == _CPMM_SWAP_IN:
230
+ return parse_cpmm_swap_in_from_data(inner, meta_d)
231
+ if disc16 == _CPMM_SWAP_OUT:
232
+ return parse_cpmm_swap_out_from_data(inner, meta_d)
233
+ if disc16 == _CPMM_DEP:
234
+ return parse_cpmm_deposit_from_data(inner, meta_d)
235
+ if disc16 == _CPMM_WIT:
236
+ return parse_cpmm_withdraw_from_data(inner, meta_d)
237
+ return None
238
+
239
+ if program_id_b58 == RAYDIUM_AMM_V4_PROGRAM_ID:
240
+ if disc16 == _AMM_SWAP_IN:
241
+ return parse_amm_swap_in_from_data(inner, meta_d)
242
+ if disc16 == _AMM_SWAP_OUT:
243
+ return parse_amm_swap_out_from_data(inner, meta_d)
244
+ if disc16 == _AMM_DEP:
245
+ return parse_amm_deposit_from_data(inner, meta_d)
246
+ if disc16 == _AMM_WIT:
247
+ return parse_amm_withdraw_from_data(inner, meta_d)
248
+ return None
249
+
250
+ if program_id_b58 == ORCA_WHIRLPOOL_PROGRAM_ID:
251
+ if disc16 == _ORCA_TRADED:
252
+ return parse_orca_traded_from_data(inner, meta_d)
253
+ if disc16 == _ORCA_LIQ_INC:
254
+ return parse_orca_liq_inc_from_data(inner, meta_d)
255
+ if disc16 == _ORCA_LIQ_DEC:
256
+ return parse_orca_liq_dec_from_data(inner, meta_d)
257
+ return None
258
+
259
+ if program_id_b58 == METEORA_POOLS_PROGRAM_ID:
260
+ if disc16 == _MP_SWAP:
261
+ return _meteora_pools_swap_inner(inner, meta_d)
262
+ if disc16 == _MP_ADD:
263
+ return _meteora_pools_add_inner(inner, meta_d)
264
+ if disc16 == _MP_REM:
265
+ return _meteora_pools_rem_inner(inner, meta_d)
266
+ return None
267
+
268
+ if program_id_b58 == METEORA_DAMM_V2_PROGRAM_ID:
269
+ if not event_type_filter_includes_meteora_damm_v2(f):
270
+ return None
271
+ return parse_meteora_damm_from_buf(_damm_buf_from_inner(disc16, inner), meta_d)
272
+
273
+ if program_id_b58 == BONK_LAUNCHPAD_PROGRAM_ID:
274
+ if disc16 == _BONK_TRADE:
275
+ return _bonk_trade_inner(inner, meta_d)
276
+ return None
277
+
278
+ if program_id_b58 == METEORA_DLMM_PROGRAM_ID:
279
+ return parse_dlmm_from_program_data(_dlmm_buf_from_inner(disc16, inner), meta_d)
280
+
281
+ return None
@@ -0,0 +1,15 @@
1
+ """对齐 Rust ``instr`` 模块。"""
2
+
3
+ from ..instructions import (
4
+ parse_instruction_unified,
5
+ parse_meteora_damm_instruction,
6
+ parse_pumpfun_instruction,
7
+ parse_pumpswap_instruction,
8
+ )
9
+
10
+ __all__ = [
11
+ "parse_instruction_unified",
12
+ "parse_pumpfun_instruction",
13
+ "parse_pumpswap_instruction",
14
+ "parse_meteora_damm_instruction",
15
+ ]
@@ -0,0 +1,58 @@
1
+ """对齐 Rust ``instr/utils::get_instruction_account_getter``:从 meta + transaction 解析某条指令的账户 getter。"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, Callable, List, Optional, Tuple
6
+
7
+ import base58
8
+
9
+
10
+ def _read_pk(raw: Optional[bytes]) -> str:
11
+ if raw is None or len(raw) != 32:
12
+ return "11111111111111111111111111111111"
13
+ return base58.b58encode(raw).decode("ascii")
14
+
15
+
16
+ def get_instruction_account_getter(
17
+ meta_pb: Any,
18
+ transaction_pb: Any,
19
+ account_keys: Optional[List[bytes]],
20
+ loaded_writable_addresses: List[bytes],
21
+ loaded_readonly_addresses: List[bytes],
22
+ index: Tuple[int, int],
23
+ ) -> Optional[Callable[[int], str]]:
24
+ """``index`` 为 ``(outer_index, inner_index)``,inner 为 ``-1`` 表示外层指令。"""
25
+ outer_i, inner_i = index
26
+ accounts_idx: bytes
27
+ if inner_i >= 0:
28
+ grp = None
29
+ for inn in meta_pb.inner_instructions:
30
+ if int(inn.index) == int(outer_i):
31
+ grp = inn
32
+ break
33
+ if grp is None or inner_i >= len(grp.instructions):
34
+ return None
35
+ accounts_idx = bytes(grp.instructions[inner_i].accounts)
36
+ else:
37
+ msg = transaction_pb.message
38
+ if outer_i >= len(msg.instructions):
39
+ return None
40
+ accounts_idx = bytes(msg.instructions[outer_i].accounts)
41
+
42
+ keys = account_keys or []
43
+
44
+ def getter(acc_i: int) -> str:
45
+ if acc_i >= len(accounts_idx):
46
+ return "11111111111111111111111111111111"
47
+ ai = accounts_idx[acc_i]
48
+ if ai < len(keys):
49
+ return _read_pk(bytes(keys[ai]))
50
+ j = ai - len(keys)
51
+ if j < len(loaded_writable_addresses):
52
+ return _read_pk(bytes(loaded_writable_addresses[j]))
53
+ j2 = j - len(loaded_writable_addresses)
54
+ if j2 < len(loaded_readonly_addresses):
55
+ return _read_pk(bytes(loaded_readonly_addresses[j2]))
56
+ return "11111111111111111111111111111111"
57
+
58
+ return getter