sol-parser-sdk-python 0.5.8__py3-none-any.whl → 0.5.10__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 +24 -0
- sol_parser/account_dispatcher.py +46 -6
- sol_parser/account_fillers/pumpfun.py +6 -15
- sol_parser/account_fillers/raydium.py +6 -2
- sol_parser/account_fillers/raydium_launchlab.py +4 -0
- sol_parser/accounts/__init__.py +5 -0
- sol_parser/block_meta.py +29 -0
- sol_parser/dex_parsers.py +18 -1
- sol_parser/entries_decode.py +6 -80
- sol_parser/event_types.py +62 -0
- sol_parser/grpc/subscribe_builder.py +8 -0
- sol_parser/grpc_client.py +118 -20
- sol_parser/grpc_instruction_parser.py +11 -1
- sol_parser/grpc_types.py +19 -0
- sol_parser/instructions.py +54 -12
- sol_parser/json_util.py +15 -1
- sol_parser/liquidity_snapshot.py +101 -0
- sol_parser/rpc_parser.py +11 -0
- sol_parser/simulation_route.py +233 -0
- sol_parser/stonkfun_registry.py +139 -0
- sol_parser/transaction_route.py +510 -0
- sol_parser/wire_transaction.py +172 -0
- {sol_parser_sdk_python-0.5.8.dist-info → sol_parser_sdk_python-0.5.10.dist-info}/METADATA +27 -2
- {sol_parser_sdk_python-0.5.8.dist-info → sol_parser_sdk_python-0.5.10.dist-info}/RECORD +26 -20
- {sol_parser_sdk_python-0.5.8.dist-info → sol_parser_sdk_python-0.5.10.dist-info}/WHEEL +1 -1
- {sol_parser_sdk_python-0.5.8.dist-info → sol_parser_sdk_python-0.5.10.dist-info}/entry_points.txt +0 -0
sol_parser/__init__.py
CHANGED
|
@@ -466,3 +466,27 @@ __all__ = [
|
|
|
466
466
|
"ShredStreamClient",
|
|
467
467
|
"ShredStreamConfig",
|
|
468
468
|
]
|
|
469
|
+
|
|
470
|
+
# Native route and subscription state APIs aligned with Rust 0.7.7.
|
|
471
|
+
from .transaction_route import (analyze_rpc_transaction_routes, TransactionRoute, RouteSwapLeg,
|
|
472
|
+
RouteTokenTransfer, RouteUnknownInvocation, RouteNativeTokenAction, InstructionPosition,
|
|
473
|
+
stonkfun_mode_from_platform_config)
|
|
474
|
+
from .stonkfun_registry import StonkFunPoolRegistry, StonkFunGraduatedPool
|
|
475
|
+
from .liquidity_snapshot import RawAccountSnapshotEvent, LiquidityAccountSnapshotEvent, parse_liquidity_account
|
|
476
|
+
from .wire_transaction import decode_wire_transaction
|
|
477
|
+
|
|
478
|
+
from .simulation_route import analyze_simulation_routes
|
|
479
|
+
|
|
480
|
+
__all__.append("analyze_simulation_routes")
|
|
481
|
+
|
|
482
|
+
from .block_meta import BlockMetaEvent, parse_block_meta_update
|
|
483
|
+
from .grpc.subscribe_builder import build_subscribe_request_with_event_filter
|
|
484
|
+
|
|
485
|
+
from .event_types import (
|
|
486
|
+
LaunchLabPoolCreateEvent, StonkFunPoolCreateEvent,
|
|
487
|
+
LaunchLabTradeEvent, StonkFunTradeEvent,
|
|
488
|
+
)
|
|
489
|
+
__all__ += ["LaunchLabPoolCreateEvent", "StonkFunPoolCreateEvent", "LaunchLabTradeEvent", "StonkFunTradeEvent"]
|
|
490
|
+
|
|
491
|
+
from .grpc_client import DexEventQueue, GrpcStreamStatus
|
|
492
|
+
__all__ += ["DexEventQueue", "GrpcStreamStatus"]
|
sol_parser/account_dispatcher.py
CHANGED
|
@@ -82,11 +82,26 @@ def fill_accounts_with_owned_keys(
|
|
|
82
82
|
w = [bytes(x) for x in meta_pb.loaded_writable_addresses]
|
|
83
83
|
r = [bytes(x) for x in meta_pb.loaded_readonly_addresses]
|
|
84
84
|
|
|
85
|
-
def run(program_b58: str, filler) -> None:
|
|
85
|
+
def run(program_b58: str, filler, anchor=None, unambiguous=False) -> None:
|
|
86
86
|
pid = base58.b58decode(program_b58)
|
|
87
87
|
inv = invokes.get(pid)
|
|
88
88
|
if not inv:
|
|
89
89
|
return
|
|
90
|
+
if anchor is not None or unambiguous:
|
|
91
|
+
pool, index = anchor or (None,1)
|
|
92
|
+
has_anchor=pool and pool != "11111111111111111111111111111111"
|
|
93
|
+
if not has_anchor and not unambiguous:return
|
|
94
|
+
selected = None
|
|
95
|
+
for invocation in inv:
|
|
96
|
+
candidate = get_instruction_account_getter(meta_pb, transaction_pb, static_keys, w, r, invocation)
|
|
97
|
+
if candidate is None or (has_anchor and candidate(index) != pool):
|
|
98
|
+
continue
|
|
99
|
+
if selected is not None and any(selected(i) != candidate(i) for i in range(18)):
|
|
100
|
+
return # Same pool, conflicting wallet/account context: do not guess.
|
|
101
|
+
selected = candidate
|
|
102
|
+
if selected is not None:
|
|
103
|
+
filler(selected)
|
|
104
|
+
return
|
|
90
105
|
ix = find_instruction_invoke(inv, meta_pb, transaction_pb)
|
|
91
106
|
if ix is None:
|
|
92
107
|
return
|
|
@@ -95,6 +110,31 @@ def fill_accounts_with_owned_keys(
|
|
|
95
110
|
return
|
|
96
111
|
filler(get)
|
|
97
112
|
|
|
113
|
+
def fill_create(v2_only=False):
|
|
114
|
+
selected = None
|
|
115
|
+
for ix in invokes.get(base58.b58decode(PUMPFUN_PROGRAM_ID), []):
|
|
116
|
+
raw = get_instruction_data(meta_pb, transaction_pb, ix)
|
|
117
|
+
if raw is None:
|
|
118
|
+
continue
|
|
119
|
+
v2 = raw[:8] == bytes([214,144,76,236,95,139,49,180])
|
|
120
|
+
legacy = raw[:8] == bytes([24,30,200,40,5,28,7,119])
|
|
121
|
+
if not v2 and (v2_only or not legacy):
|
|
122
|
+
continue
|
|
123
|
+
get = get_instruction_account_getter(meta_pb, transaction_pb, static_keys, w, r, ix)
|
|
124
|
+
oi, ii = ix
|
|
125
|
+
instruction = (transaction_pb.message.instructions[oi] if ii < 0 else
|
|
126
|
+
next(g for g in meta_pb.inner_instructions if g.index == oi).instructions[ii])
|
|
127
|
+
if len(instruction.accounts) < (16 if v2 else 14) or get is None:
|
|
128
|
+
continue
|
|
129
|
+
if data.mint and data.mint != "11111111111111111111111111111111" and get(0) != data.mint:
|
|
130
|
+
continue
|
|
131
|
+
if selected is not None:
|
|
132
|
+
return # Multiple matching creates: do not guess.
|
|
133
|
+
selected = (get, v2)
|
|
134
|
+
if selected:
|
|
135
|
+
get, v2 = selected
|
|
136
|
+
(pumpfun.fill_create_v2_accounts if v2 else pumpfun.fill_create_accounts)(data, get)
|
|
137
|
+
|
|
98
138
|
et = event.type
|
|
99
139
|
data = event.data
|
|
100
140
|
|
|
@@ -106,9 +146,9 @@ def fill_accounts_with_owned_keys(
|
|
|
106
146
|
):
|
|
107
147
|
run(PUMPFUN_PROGRAM_ID, lambda g: pumpfun.fill_trade_accounts(data, g))
|
|
108
148
|
elif et == EventType.PUMP_FUN_CREATE:
|
|
109
|
-
|
|
149
|
+
fill_create()
|
|
110
150
|
elif et == EventType.PUMP_FUN_CREATE_V2:
|
|
111
|
-
|
|
151
|
+
fill_create(True)
|
|
112
152
|
elif et == EventType.PUMP_FUN_MIGRATE:
|
|
113
153
|
run(PUMPFUN_PROGRAM_ID, lambda g: pumpfun.fill_migrate_accounts(data, g))
|
|
114
154
|
elif et == EventType.PUMP_SWAP_BUY:
|
|
@@ -146,7 +186,7 @@ def fill_accounts_with_owned_keys(
|
|
|
146
186
|
elif et == EventType.RAYDIUM_CPMM_INITIALIZE:
|
|
147
187
|
run(RAYDIUM_CPMM_PROGRAM_ID, lambda g: raydium.fill_cpmm_initialize_accounts(data, g))
|
|
148
188
|
elif et == EventType.RAYDIUM_AMM_V4_SWAP:
|
|
149
|
-
run(RAYDIUM_AMM_V4_PROGRAM_ID, lambda g: raydium.fill_amm_v4_swap_accounts(data, g))
|
|
189
|
+
run(RAYDIUM_AMM_V4_PROGRAM_ID, lambda g: raydium.fill_amm_v4_swap_accounts(data, g), (data.amm,1), True)
|
|
150
190
|
elif et == EventType.RAYDIUM_AMM_V4_DEPOSIT:
|
|
151
191
|
run(RAYDIUM_AMM_V4_PROGRAM_ID, lambda g: raydium.fill_amm_v4_deposit_accounts(data, g))
|
|
152
192
|
elif et == EventType.RAYDIUM_AMM_V4_WITHDRAW:
|
|
@@ -182,9 +222,9 @@ def fill_accounts_with_owned_keys(
|
|
|
182
222
|
elif et == EventType.METEORA_DLMM_REMOVE_LIQUIDITY:
|
|
183
223
|
run(METEORA_DLMM_PROGRAM_ID, lambda g: meteora.fill_dlmm_remove_liquidity_accounts(data, g))
|
|
184
224
|
elif et == EventType.RAYDIUM_LAUNCHLAB_TRADE:
|
|
185
|
-
run(RAYDIUM_LAUNCHLAB_PROGRAM_ID, lambda g: raydium_launchlab.fill_trade_accounts(data, g))
|
|
225
|
+
run(RAYDIUM_LAUNCHLAB_PROGRAM_ID, lambda g: raydium_launchlab.fill_trade_accounts(data, g), (data.pool_state,4))
|
|
186
226
|
elif et == EventType.RAYDIUM_LAUNCHLAB_POOL_CREATE:
|
|
187
|
-
run(RAYDIUM_LAUNCHLAB_PROGRAM_ID, lambda g: raydium_launchlab.fill_pool_create_accounts(data, g))
|
|
227
|
+
run(RAYDIUM_LAUNCHLAB_PROGRAM_ID, lambda g: raydium_launchlab.fill_pool_create_accounts(data, g), (data.pool_state,5))
|
|
188
228
|
|
|
189
229
|
|
|
190
230
|
def fill_data(
|
|
@@ -113,15 +113,12 @@ def fill_trade_accounts(e: PumpFunTradeEvent, get: AccountGetter) -> None:
|
|
|
113
113
|
|
|
114
114
|
|
|
115
115
|
def fill_create_accounts(e: PumpFunCreateEvent, get: AccountGetter) -> None:
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
e
|
|
121
|
-
|
|
122
|
-
e.bonding_curve = get(2)
|
|
123
|
-
if _empty(e.user):
|
|
124
|
-
e.user = get(7)
|
|
116
|
+
for field, index in (("mint",0),("mint_authority",1),("bonding_curve",2),
|
|
117
|
+
("associated_bonding_curve",3),("global_account",4),("user",7),
|
|
118
|
+
("system_program",8),("token_program",9),("associated_token_program",10),
|
|
119
|
+
("event_authority",12),("program",13)):
|
|
120
|
+
if _empty(getattr(e, field, "")):
|
|
121
|
+
setattr(e, field, get(index))
|
|
125
122
|
|
|
126
123
|
|
|
127
124
|
def fill_create_v2_accounts(e: PumpFunCreateV2TokenEvent, get: AccountGetter) -> None:
|
|
@@ -157,12 +154,6 @@ def fill_create_v2_accounts(e: PumpFunCreateV2TokenEvent, get: AccountGetter) ->
|
|
|
157
154
|
e.event_authority = get(14)
|
|
158
155
|
if _empty(e.program):
|
|
159
156
|
e.program = get(15)
|
|
160
|
-
if _empty(e.quote_mint) or e.quote_mint == "So11111111111111111111111111111111111111111":
|
|
161
|
-
e.quote_mint = get(16)
|
|
162
|
-
if _empty(e.quote_vault):
|
|
163
|
-
e.quote_vault = get(17)
|
|
164
|
-
if _empty(e.quote_token_program):
|
|
165
|
-
e.quote_token_program = get(18)
|
|
166
157
|
if getattr(e, "ix_name", "") in ("", "create"):
|
|
167
158
|
e.ix_name = "create_v2"
|
|
168
159
|
|
|
@@ -100,8 +100,12 @@ def fill_cpmm_initialize_accounts(e: RaydiumCpmmInitializeEvent, get: AccountGet
|
|
|
100
100
|
|
|
101
101
|
|
|
102
102
|
def fill_amm_v4_swap_accounts(e: RaydiumAmmV4SwapEvent, get: AccountGetter) -> None:
|
|
103
|
-
if _empty(e.amm):
|
|
104
|
-
|
|
103
|
+
if _empty(e.amm):e.amm=get(1)
|
|
104
|
+
modern=_empty(get(8)) and not _empty(get(7))
|
|
105
|
+
if modern:
|
|
106
|
+
for field,index in [('token_program',0),('amm_authority',2),('pool_coin_token_account',3),('pool_pc_token_account',4),('user_source_token_account',5),('user_destination_token_account',6),('user_source_owner',7)]:
|
|
107
|
+
if _empty(getattr(e,field)):setattr(e,field,get(index))
|
|
108
|
+
elif _empty(e.user_source_owner):e.user_source_owner=get(16) if _empty(get(17)) else get(17)
|
|
105
109
|
|
|
106
110
|
|
|
107
111
|
def fill_amm_v4_deposit_accounts(e: RaydiumAmmV4DepositEvent, get: AccountGetter) -> None:
|
|
@@ -43,6 +43,10 @@ def fill_trade_accounts(e: RaydiumLaunchlabTradeEvent, get: AccountGetter) -> No
|
|
|
43
43
|
if _empty(e.quote_token_program):
|
|
44
44
|
e.quote_token_program = get(12)
|
|
45
45
|
|
|
46
|
+
for name, index in [("system_program", 15), ("platform_associated_account", 16), ("creator_associated_account", 17)]:
|
|
47
|
+
if _empty(getattr(e,name,"")):
|
|
48
|
+
setattr(e,name,get(index))
|
|
49
|
+
|
|
46
50
|
|
|
47
51
|
def fill_pool_create_accounts(e: RaydiumLaunchlabPoolCreateEvent, get: AccountGetter) -> None:
|
|
48
52
|
if _empty(e.pool_state):
|
sol_parser/accounts/__init__.py
CHANGED
|
@@ -206,6 +206,11 @@ def parse_account_unified(
|
|
|
206
206
|
event_type_filter: Optional[EventTypeFilter] = None,
|
|
207
207
|
) -> Optional[DexEvent]:
|
|
208
208
|
"""对齐 Rust ``parse_account_unified``(含 ``Option<EventTypeFilter>`` 语义)。"""
|
|
209
|
+
from ..liquidity_snapshot import parse_liquidity_account
|
|
210
|
+
if event_type_filter is None or event_type_filter.should_include(EventType.ACCOUNT_LIQUIDITY_SNAPSHOT):
|
|
211
|
+
snapshot = parse_liquidity_account(account, metadata)
|
|
212
|
+
if snapshot is not None:
|
|
213
|
+
return DexEvent(type=EventType.ACCOUNT_LIQUIDITY_SNAPSHOT, data=snapshot)
|
|
209
214
|
data = account.data
|
|
210
215
|
if not data:
|
|
211
216
|
return None
|
sol_parser/block_meta.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Local BlockMeta adapter, matching Rust's saturated timestamp conversion."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from .grpc_types import EventType, EventMetadata
|
|
5
|
+
from .event_types import DexEvent
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class BlockMetaEvent:
|
|
10
|
+
metadata: EventMetadata
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def parse_block_meta_update(meta, grpc_recv_us, fallback_block_us=None):
|
|
14
|
+
block_us = fallback_block_us or 0
|
|
15
|
+
if meta.block_time is not None:
|
|
16
|
+
block_us = max(-(1 << 63), min((1 << 63) - 1, meta.block_time * 1_000_000))
|
|
17
|
+
return DexEvent(
|
|
18
|
+
EventType.BLOCK_META,
|
|
19
|
+
BlockMetaEvent(
|
|
20
|
+
EventMetadata(
|
|
21
|
+
signature="1" * 64,
|
|
22
|
+
slot=meta.slot,
|
|
23
|
+
tx_index=0,
|
|
24
|
+
block_time_us=block_us,
|
|
25
|
+
grpc_recv_us=grpc_recv_us,
|
|
26
|
+
recent_blockhash=meta.blockhash,
|
|
27
|
+
)
|
|
28
|
+
),
|
|
29
|
+
)
|
sol_parser/dex_parsers.py
CHANGED
|
@@ -324,6 +324,10 @@ def parse_create_from_data(data: bytes, meta: dict) -> DexEvent:
|
|
|
324
324
|
uri, o = _borsh_str(data, o)
|
|
325
325
|
except Exception:
|
|
326
326
|
return DexEvent()
|
|
327
|
+
if len(data) - o == 96:
|
|
328
|
+
return DexEvent(type=EventType.PUMP_FUN_CREATE, data=PumpFunCreateEvent(
|
|
329
|
+
metadata=_make_meta(meta), name=name, symbol=sym, uri=uri,
|
|
330
|
+
mint=_pub(data, o), bonding_curve=_pub(data, o + 32), user=_pub(data, o + 64)))
|
|
327
331
|
if len(data) < o + 32 * 4 + 8 * 5 + 32 + 1:
|
|
328
332
|
return DexEvent()
|
|
329
333
|
mint = _pub(data, o)
|
|
@@ -2727,7 +2731,7 @@ def parse_raydium_launchlab_from_discriminator(disc: int, data: bytes, meta: dic
|
|
|
2727
2731
|
|
|
2728
2732
|
|
|
2729
2733
|
def _parse_raydium_launchlab_trade(data: bytes, meta: dict) -> Optional[DexEvent]:
|
|
2730
|
-
if len(data)
|
|
2734
|
+
if len(data) != 139 or data[136] > 1 or data[137] > 2 or data[138] > 1:
|
|
2731
2735
|
return None
|
|
2732
2736
|
pool = _pub(data, 0)
|
|
2733
2737
|
ai = _u64le(data, 88)
|
|
@@ -2746,6 +2750,19 @@ def _parse_raydium_launchlab_trade(data: bytes, meta: dict) -> Optional[DexEvent
|
|
|
2746
2750
|
is_buy=is_buy,
|
|
2747
2751
|
trade_direction=d,
|
|
2748
2752
|
exact_in=ex_in,
|
|
2753
|
+
pool_status=("Fund","Migrate","Trade")[data[137]],
|
|
2754
|
+
total_base_sell=_u64le(data,32),
|
|
2755
|
+
virtual_base=_u64le(data,40),
|
|
2756
|
+
virtual_quote=_u64le(data,48),
|
|
2757
|
+
real_base_before=_u64le(data,56),
|
|
2758
|
+
real_quote_before=_u64le(data,64),
|
|
2759
|
+
real_base_after=_u64le(data,72),
|
|
2760
|
+
real_quote_after=_u64le(data,80),
|
|
2761
|
+
protocol_fee=_u64le(data,104),
|
|
2762
|
+
platform_fee=_u64le(data,112),
|
|
2763
|
+
creator_fee=_u64le(data,120),
|
|
2764
|
+
share_fee=_u64le(data,128),
|
|
2765
|
+
|
|
2749
2766
|
),
|
|
2750
2767
|
)
|
|
2751
2768
|
|
sol_parser/entries_decode.py
CHANGED
|
@@ -46,87 +46,13 @@ class _ParsedTx:
|
|
|
46
46
|
|
|
47
47
|
|
|
48
48
|
def parse_transaction_wire(buf: bytes, pos: int) -> Optional[_ParsedTx]:
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
p = pos + sig_count_enc[1]
|
|
56
|
-
sig_count = sig_count_enc[0]
|
|
57
|
-
sigs_end = p + sig_count * 64
|
|
58
|
-
if sigs_end > len(buf):
|
|
59
|
-
return None
|
|
60
|
-
sigs: List[bytes] = []
|
|
61
|
-
for _ in range(sig_count):
|
|
62
|
-
sigs.append(buf[p : p + 64])
|
|
63
|
-
p += 64
|
|
64
|
-
if p >= len(buf):
|
|
65
|
-
return None
|
|
66
|
-
msg_first = buf[p]
|
|
67
|
-
is_v0 = msg_first >= 0x80
|
|
68
|
-
if is_v0:
|
|
69
|
-
p += 1
|
|
70
|
-
p += 3
|
|
71
|
-
if p > len(buf):
|
|
72
|
-
return None
|
|
73
|
-
acct_enc = decode_compact_u16(buf, p)
|
|
74
|
-
if not acct_enc:
|
|
75
|
-
return None
|
|
76
|
-
p += acct_enc[1]
|
|
77
|
-
p += acct_enc[0] * 32
|
|
78
|
-
if p > len(buf):
|
|
79
|
-
return None
|
|
80
|
-
ix_count_enc = decode_compact_u16(buf, p)
|
|
81
|
-
if not ix_count_enc:
|
|
49
|
+
from .wire_transaction import decode_wire_transaction
|
|
50
|
+
import base58
|
|
51
|
+
try:
|
|
52
|
+
transaction, length = decode_wire_transaction(buf, pos, require_complete=False)
|
|
53
|
+
return _ParsedTx(length, [base58.b58decode(s) for s in transaction['signatures']])
|
|
54
|
+
except (ValueError, IndexError):
|
|
82
55
|
return None
|
|
83
|
-
p += ix_count_enc[1]
|
|
84
|
-
ix_count = ix_count_enc[0]
|
|
85
|
-
for _ in range(ix_count):
|
|
86
|
-
p += 1
|
|
87
|
-
if p > len(buf):
|
|
88
|
-
return None
|
|
89
|
-
acct_len_enc = decode_compact_u16(buf, p)
|
|
90
|
-
if not acct_len_enc:
|
|
91
|
-
return None
|
|
92
|
-
p += acct_len_enc[1]
|
|
93
|
-
p += acct_len_enc[0]
|
|
94
|
-
if p > len(buf):
|
|
95
|
-
return None
|
|
96
|
-
data_len_enc = decode_compact_u16(buf, p)
|
|
97
|
-
if not data_len_enc:
|
|
98
|
-
return None
|
|
99
|
-
p += data_len_enc[1]
|
|
100
|
-
p += data_len_enc[0]
|
|
101
|
-
if p > len(buf):
|
|
102
|
-
return None
|
|
103
|
-
if is_v0:
|
|
104
|
-
if p >= len(buf):
|
|
105
|
-
return None
|
|
106
|
-
atl_count_enc = decode_compact_u16(buf, p)
|
|
107
|
-
if not atl_count_enc:
|
|
108
|
-
return None
|
|
109
|
-
p += atl_count_enc[1]
|
|
110
|
-
atl_count = atl_count_enc[0]
|
|
111
|
-
for _ in range(atl_count):
|
|
112
|
-
p += 32
|
|
113
|
-
if p > len(buf):
|
|
114
|
-
return None
|
|
115
|
-
w_len_enc = decode_compact_u16(buf, p)
|
|
116
|
-
if not w_len_enc:
|
|
117
|
-
return None
|
|
118
|
-
p += w_len_enc[1]
|
|
119
|
-
p += w_len_enc[0]
|
|
120
|
-
if p > len(buf):
|
|
121
|
-
return None
|
|
122
|
-
r_len_enc = decode_compact_u16(buf, p)
|
|
123
|
-
if not r_len_enc:
|
|
124
|
-
return None
|
|
125
|
-
p += r_len_enc[1]
|
|
126
|
-
p += r_len_enc[0]
|
|
127
|
-
if p > len(buf):
|
|
128
|
-
return None
|
|
129
|
-
return _ParsedTx(tx_len=p - start, signatures=sigs)
|
|
130
56
|
|
|
131
57
|
|
|
132
58
|
class _BatchDecoder:
|
sol_parser/event_types.py
CHANGED
|
@@ -219,6 +219,20 @@ class PumpFunCreateEvent(DexEventBase):
|
|
|
219
219
|
virtual_quote_reserves: int = 0
|
|
220
220
|
creator_fee_bps: int = 0
|
|
221
221
|
is_holder_reward: bool = False
|
|
222
|
+
mint_authority: str = ""
|
|
223
|
+
associated_bonding_curve: str = ""
|
|
224
|
+
global_account: str = "" # Rust `global` PumpFun global config
|
|
225
|
+
system_program: str = ""
|
|
226
|
+
associated_token_program: str = ""
|
|
227
|
+
mayhem_program_id: str = ""
|
|
228
|
+
global_params: str = ""
|
|
229
|
+
sol_vault: str = ""
|
|
230
|
+
mayhem_state: str = ""
|
|
231
|
+
mayhem_token_vault: str = ""
|
|
232
|
+
event_authority: str = ""
|
|
233
|
+
program: str = ""
|
|
234
|
+
observed_fee_recipient: str = ""
|
|
235
|
+
ix_name: str = "create"
|
|
222
236
|
|
|
223
237
|
|
|
224
238
|
@dataclass
|
|
@@ -1410,6 +1424,28 @@ class RaydiumLaunchlabTradeEvent(DexEventBase):
|
|
|
1410
1424
|
base_token_program: str = ""
|
|
1411
1425
|
quote_token_program: str = ""
|
|
1412
1426
|
|
|
1427
|
+
total_base_sell: int = 0
|
|
1428
|
+
virtual_base: int = 0
|
|
1429
|
+
virtual_quote: int = 0
|
|
1430
|
+
real_base_before: int = 0
|
|
1431
|
+
real_quote_before: int = 0
|
|
1432
|
+
real_base_after: int = 0
|
|
1433
|
+
real_quote_after: int = 0
|
|
1434
|
+
protocol_fee: int = 0
|
|
1435
|
+
platform_fee: int = 0
|
|
1436
|
+
creator_fee: int = 0
|
|
1437
|
+
share_fee: int = 0
|
|
1438
|
+
pool_status: str = "Fund"
|
|
1439
|
+
system_program: str = ""
|
|
1440
|
+
platform_associated_account: str = ""
|
|
1441
|
+
creator_associated_account: str = ""
|
|
1442
|
+
|
|
1443
|
+
def stonkfun_mode(self):
|
|
1444
|
+
from .transaction_route import stonkfun_mode_from_platform_config
|
|
1445
|
+
return stonkfun_mode_from_platform_config(self.platform_config)
|
|
1446
|
+
|
|
1447
|
+
def is_stonkfun(self):
|
|
1448
|
+
return self.stonkfun_mode() is not None
|
|
1413
1449
|
|
|
1414
1450
|
@dataclass
|
|
1415
1451
|
class RaydiumLaunchlabPoolCreateEvent(DexEventBase):
|
|
@@ -1428,6 +1464,14 @@ class RaydiumLaunchlabPoolCreateEvent(DexEventBase):
|
|
|
1428
1464
|
quote_token_program: str = ""
|
|
1429
1465
|
|
|
1430
1466
|
|
|
1467
|
+
|
|
1468
|
+
def stonkfun_mode(self):
|
|
1469
|
+
from .transaction_route import stonkfun_mode_from_platform_config
|
|
1470
|
+
return stonkfun_mode_from_platform_config(self.platform_config)
|
|
1471
|
+
|
|
1472
|
+
def is_stonkfun(self):
|
|
1473
|
+
return self.stonkfun_mode() is not None
|
|
1474
|
+
|
|
1431
1475
|
@dataclass
|
|
1432
1476
|
class RaydiumLaunchlabMigrateAmmEvent(DexEventBase):
|
|
1433
1477
|
"""RaydiumLaunchlab 迁移 AMM 事件"""
|
|
@@ -1436,6 +1480,18 @@ class RaydiumLaunchlabMigrateAmmEvent(DexEventBase):
|
|
|
1436
1480
|
user: str = ""
|
|
1437
1481
|
liquidity_amount: int = 0
|
|
1438
1482
|
|
|
1483
|
+
liquidity_amount_known: bool = False
|
|
1484
|
+
base_mint: str = ""
|
|
1485
|
+
quote_mint: str = ""
|
|
1486
|
+
platform_config: str = ""
|
|
1487
|
+
destination_program: str = ""
|
|
1488
|
+
|
|
1489
|
+
def stonkfun_mode(self):
|
|
1490
|
+
from .transaction_route import stonkfun_mode_from_platform_config
|
|
1491
|
+
return stonkfun_mode_from_platform_config(self.platform_config)
|
|
1492
|
+
|
|
1493
|
+
def is_stonkfun(self):
|
|
1494
|
+
return self.stonkfun_mode() is not None
|
|
1439
1495
|
|
|
1440
1496
|
# ============================================================
|
|
1441
1497
|
# 类型联合
|
|
@@ -2379,3 +2435,9 @@ def legacy_dict_to_dex_event(d: dict) -> Optional[DexEvent]:
|
|
|
2379
2435
|
except ValueError:
|
|
2380
2436
|
return None
|
|
2381
2437
|
return DexEvent(type=et, data=typed)
|
|
2438
|
+
|
|
2439
|
+
# Same classes: preserve isinstance, serialization and platform attribution.
|
|
2440
|
+
LaunchLabPoolCreateEvent = RaydiumLaunchlabPoolCreateEvent
|
|
2441
|
+
StonkFunPoolCreateEvent = RaydiumLaunchlabPoolCreateEvent
|
|
2442
|
+
LaunchLabTradeEvent = RaydiumLaunchlabTradeEvent
|
|
2443
|
+
StonkFunTradeEvent = RaydiumLaunchlabTradeEvent
|
|
@@ -131,3 +131,11 @@ __all__ = [
|
|
|
131
131
|
"build_subscribe_request_with_commitment",
|
|
132
132
|
"build_subscribe_transaction_filters_named",
|
|
133
133
|
]
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def build_subscribe_request_with_event_filter(tx_filters, acc_filters, event_type_filter=None):
|
|
137
|
+
from ..grpc_types import EventType
|
|
138
|
+
request=build_subscribe_request(tx_filters,acc_filters)
|
|
139
|
+
if event_type_filter is not None and event_type_filter.should_include(EventType.BLOCK_META):
|
|
140
|
+
request.blocks_meta["block_meta"].CopyFrom(geyser_pb2.SubscribeRequestFilterBlocksMeta())
|
|
141
|
+
return request
|