sol-parser-sdk-python 0.5.7__py3-none-any.whl → 0.5.8__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 +10 -0
- sol_parser/account_dispatcher.py +79 -0
- sol_parser/account_fillers/meteora.py +10 -2
- sol_parser/account_fillers/raydium.py +3 -2
- sol_parser/account_fillers/raydium_launchlab.py +50 -0
- sol_parser/accounts/__init__.py +47 -2
- sol_parser/dex_parsers.py +648 -68
- sol_parser/event_type_parity.py +4 -0
- sol_parser/event_types.py +221 -3
- sol_parser/grpc_instruction_parser.py +85 -26
- sol_parser/grpc_types.py +12 -0
- sol_parser/inner_instruction_parser.py +5 -7
- sol_parser/instructions.py +213 -49
- sol_parser/log_instr_dedup.py +56 -12
- sol_parser/merger.py +73 -85
- sol_parser/parser.py +11 -0
- sol_parser/pumpfun_fee_enrich.py +2 -0
- sol_parser/rpc_parser.py +30 -4
- {sol_parser_sdk_python-0.5.7.dist-info → sol_parser_sdk_python-0.5.8.dist-info}/METADATA +26 -9
- {sol_parser_sdk_python-0.5.7.dist-info → sol_parser_sdk_python-0.5.8.dist-info}/RECORD +22 -22
- {sol_parser_sdk_python-0.5.7.dist-info → sol_parser_sdk_python-0.5.8.dist-info}/WHEEL +1 -1
- {sol_parser_sdk_python-0.5.7.dist-info → sol_parser_sdk_python-0.5.8.dist-info}/entry_points.txt +0 -0
sol_parser/__init__.py
CHANGED
|
@@ -152,6 +152,11 @@ from .event_types import (
|
|
|
152
152
|
MeteoraDammV2AddLiquidityEvent,
|
|
153
153
|
MeteoraDammV2RemoveLiquidityEvent,
|
|
154
154
|
MeteoraDammV2InitializePoolEvent,
|
|
155
|
+
MeteoraDammV2DynamicFeeParameters,
|
|
156
|
+
MeteoraDammV2UpdateDelegatePermissionEvent,
|
|
157
|
+
MeteoraDammV2WithdrawDeadLiquidityRewardEvent,
|
|
158
|
+
MeteoraDammV2CreateConfigEvent,
|
|
159
|
+
MeteoraDammV2CreateDynamicConfigEvent,
|
|
155
160
|
MeteoraDbcCurveCompleteEvent,
|
|
156
161
|
MeteoraDbcInitializePoolEvent,
|
|
157
162
|
MeteoraDbcSwapEvent,
|
|
@@ -432,6 +437,11 @@ __all__ = [
|
|
|
432
437
|
"MeteoraDammV2AddLiquidityEvent",
|
|
433
438
|
"MeteoraDammV2RemoveLiquidityEvent",
|
|
434
439
|
"MeteoraDammV2InitializePoolEvent",
|
|
440
|
+
"MeteoraDammV2DynamicFeeParameters",
|
|
441
|
+
"MeteoraDammV2UpdateDelegatePermissionEvent",
|
|
442
|
+
"MeteoraDammV2WithdrawDeadLiquidityRewardEvent",
|
|
443
|
+
"MeteoraDammV2CreateConfigEvent",
|
|
444
|
+
"MeteoraDammV2CreateDynamicConfigEvent",
|
|
435
445
|
"MeteoraDbcCurveCompleteEvent",
|
|
436
446
|
"MeteoraDbcInitializePoolEvent",
|
|
437
447
|
"MeteoraDbcSwapEvent",
|
sol_parser/account_dispatcher.py
CHANGED
|
@@ -209,3 +209,82 @@ def fill_data(
|
|
|
209
209
|
return
|
|
210
210
|
is_pump = raw[9] != 0
|
|
211
211
|
setattr(data, "is_pump_pool", is_pump)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def _account_index(transaction_pb: Any, meta_pb: Any, account: str) -> Optional[int]:
|
|
215
|
+
if not account or account == "11111111111111111111111111111111":
|
|
216
|
+
return None
|
|
217
|
+
msg = getattr(transaction_pb, "message", None)
|
|
218
|
+
if msg is None:
|
|
219
|
+
return None
|
|
220
|
+
keys: List[str] = []
|
|
221
|
+
for b in getattr(msg, "account_keys", []) or []:
|
|
222
|
+
raw = bytes(b) if not isinstance(b, (bytes, bytearray)) else bytes(b)
|
|
223
|
+
if len(raw) == 32:
|
|
224
|
+
keys.append(base58.b58encode(raw).decode("ascii"))
|
|
225
|
+
for b in getattr(meta_pb, "loaded_writable_addresses", []) or []:
|
|
226
|
+
raw = bytes(b) if not isinstance(b, (bytes, bytearray)) else bytes(b)
|
|
227
|
+
if len(raw) == 32:
|
|
228
|
+
keys.append(base58.b58encode(raw).decode("ascii"))
|
|
229
|
+
for b in getattr(meta_pb, "loaded_readonly_addresses", []) or []:
|
|
230
|
+
raw = bytes(b) if not isinstance(b, (bytes, bytearray)) else bytes(b)
|
|
231
|
+
if len(raw) == 32:
|
|
232
|
+
keys.append(base58.b58encode(raw).decode("ascii"))
|
|
233
|
+
try:
|
|
234
|
+
return keys.index(account)
|
|
235
|
+
except ValueError:
|
|
236
|
+
return None
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def _token_balance_raw(t: Any) -> int:
|
|
240
|
+
ui = getattr(t, "ui_token_amount", None)
|
|
241
|
+
if ui is None:
|
|
242
|
+
return 0
|
|
243
|
+
amt = getattr(ui, "amount", None)
|
|
244
|
+
if amt is None:
|
|
245
|
+
return 0
|
|
246
|
+
try:
|
|
247
|
+
return int(str(amt))
|
|
248
|
+
except Exception:
|
|
249
|
+
return 0
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def fill_token_balances(event: DexEvent, meta_pb: Any, transaction_pb: Any) -> None:
|
|
253
|
+
"""对齐 Rust ``common_filler::fill_token_balances``(PumpFun trade 用户余额)。"""
|
|
254
|
+
if meta_pb is None or transaction_pb is None:
|
|
255
|
+
return
|
|
256
|
+
if event.type not in (
|
|
257
|
+
EventType.PUMP_FUN_TRADE,
|
|
258
|
+
EventType.PUMP_FUN_BUY,
|
|
259
|
+
EventType.PUMP_FUN_SELL,
|
|
260
|
+
EventType.PUMP_FUN_BUY_EXACT_SOL_IN,
|
|
261
|
+
):
|
|
262
|
+
return
|
|
263
|
+
trade = event.data
|
|
264
|
+
user = getattr(trade, "user", "") or ""
|
|
265
|
+
associated_user = getattr(trade, "associated_user", "") or ""
|
|
266
|
+
user_idx = _account_index(transaction_pb, meta_pb, user)
|
|
267
|
+
if user_idx is not None:
|
|
268
|
+
pre_balances = list(getattr(meta_pb, "pre_balances", []) or [])
|
|
269
|
+
post_balances = list(getattr(meta_pb, "post_balances", []) or [])
|
|
270
|
+
if user_idx < len(pre_balances):
|
|
271
|
+
trade.pre_sol_balance = int(pre_balances[user_idx])
|
|
272
|
+
if user_idx < len(post_balances):
|
|
273
|
+
trade.post_sol_balance = int(post_balances[user_idx])
|
|
274
|
+
token_idx = _account_index(transaction_pb, meta_pb, associated_user)
|
|
275
|
+
if token_idx is None:
|
|
276
|
+
return
|
|
277
|
+
token_idx_u32 = token_idx
|
|
278
|
+
pre = None
|
|
279
|
+
post = None
|
|
280
|
+
for bal in getattr(meta_pb, "pre_token_balances", []) or []:
|
|
281
|
+
if int(getattr(bal, "account_index", -1)) == token_idx_u32:
|
|
282
|
+
pre = _token_balance_raw(bal)
|
|
283
|
+
break
|
|
284
|
+
for bal in getattr(meta_pb, "post_token_balances", []) or []:
|
|
285
|
+
if int(getattr(bal, "account_index", -1)) == token_idx_u32:
|
|
286
|
+
post = _token_balance_raw(bal)
|
|
287
|
+
break
|
|
288
|
+
if pre is not None or post is not None:
|
|
289
|
+
trade.pre_token_balance = pre if pre is not None else 0
|
|
290
|
+
trade.post_token_balance = post if post is not None else 0
|
|
@@ -54,8 +54,16 @@ def fill_pools_remove_liquidity_accounts(_e: Any, _get: AccountGetter) -> None:
|
|
|
54
54
|
pass
|
|
55
55
|
|
|
56
56
|
|
|
57
|
-
def fill_dlmm_swap_accounts(
|
|
58
|
-
|
|
57
|
+
def fill_dlmm_swap_accounts(e: Any, get: AccountGetter) -> None:
|
|
58
|
+
z = "11111111111111111111111111111111"
|
|
59
|
+
if not getattr(e, "user_token_in", "") or e.user_token_in == z:
|
|
60
|
+
e.user_token_in = get(4)
|
|
61
|
+
if not getattr(e, "user_token_out", "") or e.user_token_out == z:
|
|
62
|
+
e.user_token_out = get(5)
|
|
63
|
+
if not getattr(e, "token_x_mint", "") or e.token_x_mint == z:
|
|
64
|
+
e.token_x_mint = get(6)
|
|
65
|
+
if not getattr(e, "token_y_mint", "") or e.token_y_mint == z:
|
|
66
|
+
e.token_y_mint = get(7)
|
|
59
67
|
|
|
60
68
|
|
|
61
69
|
def fill_dlmm_add_liquidity_accounts(_e: Any, _get: AccountGetter) -> None:
|
|
@@ -77,8 +77,9 @@ def fill_clmm_close_position_accounts(e: RaydiumClmmClosePositionEvent, get: Acc
|
|
|
77
77
|
e.position_nft_mint = get(1)
|
|
78
78
|
|
|
79
79
|
|
|
80
|
-
def fill_cpmm_swap_accounts(
|
|
81
|
-
|
|
80
|
+
def fill_cpmm_swap_accounts(e: RaydiumCpmmSwapEvent, get: AccountGetter) -> None:
|
|
81
|
+
if _empty(e.pool_id):
|
|
82
|
+
e.pool_id = get(3)
|
|
82
83
|
|
|
83
84
|
|
|
84
85
|
def fill_cpmm_deposit_accounts(e: RaydiumCpmmDepositEvent, get: AccountGetter) -> None:
|
|
@@ -7,6 +7,7 @@ from typing import Callable
|
|
|
7
7
|
from ..event_types import RaydiumLaunchlabPoolCreateEvent, RaydiumLaunchlabTradeEvent
|
|
8
8
|
|
|
9
9
|
Z = "11111111111111111111111111111111"
|
|
10
|
+
RAYDIUM_LAUNCHLAB_PROGRAM_ID = "LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj"
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
def _empty(s: str) -> bool:
|
|
@@ -21,6 +22,26 @@ def fill_trade_accounts(e: RaydiumLaunchlabTradeEvent, get: AccountGetter) -> No
|
|
|
21
22
|
e.user = get(0)
|
|
22
23
|
if _empty(e.pool_state):
|
|
23
24
|
e.pool_state = get(4)
|
|
25
|
+
if _empty(e.global_config):
|
|
26
|
+
e.global_config = get(2)
|
|
27
|
+
if _empty(e.platform_config):
|
|
28
|
+
e.platform_config = get(3)
|
|
29
|
+
if _empty(e.user_base_token):
|
|
30
|
+
e.user_base_token = get(5)
|
|
31
|
+
if _empty(e.user_quote_token):
|
|
32
|
+
e.user_quote_token = get(6)
|
|
33
|
+
if _empty(e.base_vault):
|
|
34
|
+
e.base_vault = get(7)
|
|
35
|
+
if _empty(e.quote_vault):
|
|
36
|
+
e.quote_vault = get(8)
|
|
37
|
+
if _empty(e.base_mint):
|
|
38
|
+
e.base_mint = get(9)
|
|
39
|
+
if _empty(e.quote_mint):
|
|
40
|
+
e.quote_mint = get(10)
|
|
41
|
+
if _empty(e.base_token_program):
|
|
42
|
+
e.base_token_program = get(11)
|
|
43
|
+
if _empty(e.quote_token_program):
|
|
44
|
+
e.quote_token_program = get(12)
|
|
24
45
|
|
|
25
46
|
|
|
26
47
|
def fill_pool_create_accounts(e: RaydiumLaunchlabPoolCreateEvent, get: AccountGetter) -> None:
|
|
@@ -28,3 +49,32 @@ def fill_pool_create_accounts(e: RaydiumLaunchlabPoolCreateEvent, get: AccountGe
|
|
|
28
49
|
e.pool_state = get(5)
|
|
29
50
|
if _empty(e.creator):
|
|
30
51
|
e.creator = get(1)
|
|
52
|
+
if _empty(e.payer):
|
|
53
|
+
e.payer = get(0)
|
|
54
|
+
if _empty(e.global_config):
|
|
55
|
+
e.global_config = get(2)
|
|
56
|
+
if _empty(e.platform_config):
|
|
57
|
+
e.platform_config = get(3)
|
|
58
|
+
if _empty(e.base_mint):
|
|
59
|
+
e.base_mint = get(6)
|
|
60
|
+
if _empty(e.quote_mint):
|
|
61
|
+
e.quote_mint = get(7)
|
|
62
|
+
if _empty(e.base_vault):
|
|
63
|
+
e.base_vault = get(8)
|
|
64
|
+
if _empty(e.quote_vault):
|
|
65
|
+
e.quote_vault = get(9)
|
|
66
|
+
# initialize / initialize_v2 use token-program indices 11-12;
|
|
67
|
+
# initialize_with_token_2022 uses 10-11 (detect via program id at end).
|
|
68
|
+
try:
|
|
69
|
+
if get(17) == RAYDIUM_LAUNCHLAB_PROGRAM_ID:
|
|
70
|
+
bi, qi = 11, 12
|
|
71
|
+
elif get(14) == RAYDIUM_LAUNCHLAB_PROGRAM_ID:
|
|
72
|
+
bi, qi = 10, 11
|
|
73
|
+
else:
|
|
74
|
+
return
|
|
75
|
+
except Exception:
|
|
76
|
+
return
|
|
77
|
+
if _empty(e.base_token_program):
|
|
78
|
+
e.base_token_program = get(bi)
|
|
79
|
+
if _empty(e.quote_token_program):
|
|
80
|
+
e.quote_token_program = get(qi)
|
sol_parser/accounts/__init__.py
CHANGED
|
@@ -42,10 +42,15 @@ TOKEN_ACCOUNT_SIZE = 165
|
|
|
42
42
|
NONCE_ACCOUNT_SIZE = 80
|
|
43
43
|
PUMPFUN_GLOBAL_BODY = 1037
|
|
44
44
|
PUMPFUN_BONDING_CURVE_BODY = 107
|
|
45
|
+
PUMPFUN_BONDING_CURVE_CREATOR_FEE_BODY = 116
|
|
46
|
+
PUMPFUN_BONDING_CURVE_HOLDER_REWARD_BODY = 117
|
|
45
47
|
PUMPFUN_GLOBAL_VOLUME_ACCUMULATOR_BODY = 536
|
|
46
48
|
PUMPFUN_USER_VOLUME_ACCUMULATOR_BODY = 98
|
|
47
49
|
GLOBAL_CONFIG_BODY = 634
|
|
48
|
-
|
|
50
|
+
POOL_LEGACY_BODY = 244
|
|
51
|
+
POOL_BOOST_BODY = 253
|
|
52
|
+
POOL_CREATOR_FEE_BODY = 262
|
|
53
|
+
POOL_BODY = 263
|
|
49
54
|
MAX_PUMPFUN_FEE_TIERS = 64
|
|
50
55
|
MAX_PUMPFUN_SHAREHOLDERS = 64
|
|
51
56
|
|
|
@@ -483,6 +488,12 @@ def _parse_pumpfun_bonding_curve_fast(
|
|
|
483
488
|
is_cashback_coin = data[o] != 0
|
|
484
489
|
o += 1
|
|
485
490
|
quote_mint = read_pubkey_fast(data, o)
|
|
491
|
+
o += 32
|
|
492
|
+
creator_fee_bps = read_u64_fast(data, o) if o + 8 <= len(data) else 0
|
|
493
|
+
o += 8
|
|
494
|
+
can_edit_creator_fee = data[o] != 0 if o < len(data) else False
|
|
495
|
+
o += 1
|
|
496
|
+
is_holder_reward = data[o] != 0 if o < len(data) else False
|
|
486
497
|
return _account_event(
|
|
487
498
|
EventType.ACCOUNT_PUMP_FUN_BONDING_CURVE,
|
|
488
499
|
{
|
|
@@ -499,6 +510,9 @@ def _parse_pumpfun_bonding_curve_fast(
|
|
|
499
510
|
"is_mayhem_mode": is_mayhem_mode,
|
|
500
511
|
"is_cashback_coin": is_cashback_coin,
|
|
501
512
|
"quote_mint": quote_mint,
|
|
513
|
+
"creator_fee_bps": creator_fee_bps,
|
|
514
|
+
"can_edit_creator_fee": can_edit_creator_fee,
|
|
515
|
+
"is_holder_reward": is_holder_reward,
|
|
502
516
|
},
|
|
503
517
|
},
|
|
504
518
|
)
|
|
@@ -752,6 +766,18 @@ def _parse_pumpswap_pool_fast(account: AccountData, metadata: EventMetadata) ->
|
|
|
752
766
|
o += 32
|
|
753
767
|
is_mayhem = data[o] != 0
|
|
754
768
|
is_cashback = data[o + 1] != 0
|
|
769
|
+
o += 2
|
|
770
|
+
virtual_quote_reserves = (
|
|
771
|
+
int.from_bytes(data[o : o + 16], "little", signed=True)
|
|
772
|
+
if len(data) >= POOL_BOOST_BODY
|
|
773
|
+
else 0
|
|
774
|
+
)
|
|
775
|
+
o += 16
|
|
776
|
+
creator_fee_bps = read_u64_fast(data, o) if o + 8 <= len(data) else 0
|
|
777
|
+
o += 8
|
|
778
|
+
can_edit_creator_fee = data[o] != 0 if o < len(data) else False
|
|
779
|
+
o += 1
|
|
780
|
+
is_holder_reward = data[o] != 0 if o < len(data) else False
|
|
755
781
|
return _account_event(
|
|
756
782
|
EventType.ACCOUNT_PUMP_SWAP_POOL,
|
|
757
783
|
{
|
|
@@ -770,6 +796,10 @@ def _parse_pumpswap_pool_fast(account: AccountData, metadata: EventMetadata) ->
|
|
|
770
796
|
"coin_creator": coin_creator,
|
|
771
797
|
"is_mayhem_mode": is_mayhem,
|
|
772
798
|
"is_cashback_coin": is_cashback,
|
|
799
|
+
"virtual_quote_reserves": virtual_quote_reserves,
|
|
800
|
+
"creator_fee_bps": creator_fee_bps,
|
|
801
|
+
"can_edit_creator_fee": can_edit_creator_fee,
|
|
802
|
+
"is_holder_reward": is_holder_reward,
|
|
773
803
|
},
|
|
774
804
|
},
|
|
775
805
|
)
|
|
@@ -807,6 +837,13 @@ def parse_pumpfun_bonding_curve(
|
|
|
807
837
|
) -> Optional[DexEvent]:
|
|
808
838
|
if len(account.data) < 8 + PUMPFUN_BONDING_CURVE_BODY:
|
|
809
839
|
return None
|
|
840
|
+
body_len = len(account.data) - 8
|
|
841
|
+
if (
|
|
842
|
+
body_len != PUMPFUN_BONDING_CURVE_BODY
|
|
843
|
+
and body_len != PUMPFUN_BONDING_CURVE_CREATOR_FEE_BODY
|
|
844
|
+
and body_len < PUMPFUN_BONDING_CURVE_HOLDER_REWARD_BODY
|
|
845
|
+
):
|
|
846
|
+
return None
|
|
810
847
|
if not has_discriminator(account.data, _DISC_PUMPFUN_BONDING_CURVE):
|
|
811
848
|
return None
|
|
812
849
|
return _parse_pumpfun_bonding_curve_fast(account, metadata)
|
|
@@ -861,7 +898,15 @@ def parse_pumpswap_global_config(account: AccountData, metadata: EventMetadata)
|
|
|
861
898
|
|
|
862
899
|
|
|
863
900
|
def parse_pumpswap_pool(account: AccountData, metadata: EventMetadata) -> Optional[DexEvent]:
|
|
864
|
-
if len(account.data) < 8 +
|
|
901
|
+
if len(account.data) < 8 + POOL_LEGACY_BODY:
|
|
902
|
+
return None
|
|
903
|
+
body_len = len(account.data) - 8
|
|
904
|
+
if (
|
|
905
|
+
body_len != POOL_LEGACY_BODY
|
|
906
|
+
and body_len != POOL_BOOST_BODY
|
|
907
|
+
and body_len != POOL_CREATOR_FEE_BODY
|
|
908
|
+
and body_len < POOL_BODY
|
|
909
|
+
):
|
|
865
910
|
return None
|
|
866
911
|
if not has_discriminator(account.data, _DISC_POOL):
|
|
867
912
|
return None
|