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.
- sol_parser/__init__.py +400 -0
- sol_parser/account_dispatcher.py +209 -0
- sol_parser/account_fillers/__init__.py +5 -0
- sol_parser/account_fillers/bonk.py +30 -0
- sol_parser/account_fillers/meteora.py +51 -0
- sol_parser/account_fillers/orca.py +40 -0
- sol_parser/account_fillers/pumpfun.py +97 -0
- sol_parser/account_fillers/pumpswap.py +93 -0
- sol_parser/account_fillers/raydium.py +119 -0
- sol_parser/accounts/__init__.py +461 -0
- sol_parser/accounts/rpc_wallet.py +64 -0
- sol_parser/accounts/utils.py +71 -0
- sol_parser/check_migration.py +18 -0
- sol_parser/clock.py +10 -0
- sol_parser/common/__init__.py +27 -0
- sol_parser/dex_parsers.py +2576 -0
- sol_parser/entries_decode.py +186 -0
- sol_parser/env_config.py +215 -0
- sol_parser/event_types.py +1750 -0
- sol_parser/geyser_pb2.py +148 -0
- sol_parser/geyser_pb2_grpc.py +398 -0
- sol_parser/grpc/__init__.py +61 -0
- sol_parser/grpc/geyser_connect.py +42 -0
- sol_parser/grpc/subscribe_builder.py +133 -0
- sol_parser/grpc/transaction_meta.py +183 -0
- sol_parser/grpc_client.py +870 -0
- sol_parser/grpc_instruction_parser.py +318 -0
- sol_parser/grpc_types.py +919 -0
- sol_parser/inner_instruction_parser.py +281 -0
- sol_parser/instr/__init__.py +15 -0
- sol_parser/instr_account_utils.py +58 -0
- sol_parser/instructions.py +1026 -0
- sol_parser/json_util.py +41 -0
- sol_parser/log_instr_dedup.py +284 -0
- sol_parser/logs/__init__.py +15 -0
- sol_parser/merger.py +233 -0
- sol_parser/order_buffer.py +171 -0
- sol_parser/parser.py +300 -0
- sol_parser/pumpfun_fee_enrich.py +75 -0
- sol_parser/rpc_parser.py +655 -0
- sol_parser/rust_api_inventory.py +42 -0
- sol_parser/rust_event_json.py +50 -0
- sol_parser/shredstream_client.py +191 -0
- sol_parser/shredstream_pb2.py +40 -0
- sol_parser/shredstream_pb2_grpc.py +81 -0
- sol_parser/shredstream_pumpfun.py +296 -0
- sol_parser/solana_storage_pb2.py +75 -0
- sol_parser/solana_storage_pb2_grpc.py +24 -0
- sol_parser/u128_parity.py +115 -0
- sol_parser/verify_discriminators.py +85 -0
- sol_parser_sdk_python-0.4.4.dist-info/METADATA +14 -0
- sol_parser_sdk_python-0.4.4.dist-info/RECORD +54 -0
- sol_parser_sdk_python-0.4.4.dist-info/WHEEL +4 -0
- 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
|