sol-parser-sdk-python 0.5.12__py3-none-any.whl → 0.5.14__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 CHANGED
@@ -511,3 +511,8 @@ from .pump_upgrade import decode_pump_multi_hop_intent
511
511
 
512
512
  from .pump_upgrade import PumpFunPostCompleteBuyEvent, PumpFunSweepBondingCurveFeeEvent, PumpFunCompleteEvent, PumpSwapSweepPoolFeeEvent
513
513
  __all__ += ['decode_pump_multi_hop_intent','PumpFunPostCompleteBuyEvent','PumpFunSweepBondingCurveFeeEvent','PumpFunCompleteEvent','PumpSwapSweepPoolFeeEvent']
514
+
515
+ from .pump_routes import PumpRouteHop, PumpRouteIntentEvent
516
+ from .shredstream_client import parse_shred_transaction, parse_shred_transaction_with_loaded_addresses, parse_shred_transaction_best_effort
517
+
518
+ __all__ += ["PumpRouteHop", "PumpRouteIntentEvent", "parse_shred_transaction", "parse_shred_transaction_with_loaded_addresses", "parse_shred_transaction_best_effort"]
@@ -119,6 +119,7 @@ RUST_EVENT_TYPES = [
119
119
  "AccountOrcaTickArray",
120
120
  "AccountOrcaFeeTier",
121
121
  "AccountOrcaWhirlpoolsConfig",
122
+ "PumpRouteIntent",
122
123
  ]
123
124
 
124
125
 
sol_parser/event_types.py CHANGED
@@ -19,10 +19,13 @@
19
19
  from __future__ import annotations
20
20
 
21
21
  from dataclasses import dataclass, field
22
- from typing import Union, List, Optional, Any, Generic, TypeVar, Dict, Tuple
22
+ from typing import TYPE_CHECKING, Union, List, Optional, Any, Generic, TypeVar, Dict, Tuple
23
23
 
24
24
  from .grpc_types import EventMetadata, EventType
25
25
 
26
+ if TYPE_CHECKING:
27
+ from .pump_routes import PumpRouteIntentEvent
28
+
26
29
  T = TypeVar('T')
27
30
 
28
31
 
@@ -1620,6 +1623,7 @@ class RaydiumLaunchlabMigrateAmmEvent(DexEventBase):
1620
1623
  # ============================================================
1621
1624
 
1622
1625
  TypedDexEvent = Union[
1626
+ "PumpRouteIntentEvent",
1623
1627
  PumpFunTradeEvent,
1624
1628
  PumpFunCreateEvent,
1625
1629
  PumpFunCreateV2TokenEvent,
@@ -1812,6 +1816,14 @@ def to_typed_event(event: dict) -> Optional[TypedDexEvent]:
1812
1816
  values={name:(_get_str(data,name) if typ=='pubkey' else _get_int(data,name)) for name,typ in fields}
1813
1817
  return cls(metadata=meta,**values)
1814
1818
 
1819
+ if event_type == EventType.PUMP_ROUTE_INTENT:
1820
+ from .pump_routes import PumpRouteHop, PumpRouteIntentEvent
1821
+ return PumpRouteIntentEvent(metadata=meta,kind=data['kind'],program=data['program'],
1822
+ instruction_index=int(data['instruction_index']),user=data['user'],input_account=data['input_account'],output_account=data['output_account'],
1823
+ amount_in=None if data.get('amount_in') is None else int(data['amount_in']),min_amount_out=None if data.get('min_amount_out') is None else int(data['min_amount_out']),
1824
+ hops=[PumpRouteHop(**h) for h in data['hops']],instruction_data=list(data['instruction_data']),
1825
+ is_buy=data.get('is_buy'),ix_name=data.get('ix_name'))
1826
+
1815
1827
  # PumpFun events
1816
1828
  if event_type in (EventType.PUMP_FUN_TRADE, EventType.PUMP_FUN_BUY,
1817
1829
  EventType.PUMP_FUN_SELL, EventType.PUMP_FUN_BUY_EXACT_SOL_IN):
sol_parser/grpc_types.py CHANGED
@@ -47,6 +47,7 @@ class EventType(str, Enum):
47
47
  RAYDIUM_LAUNCHLAB_TRADE = "RaydiumLaunchlabTrade"
48
48
  RAYDIUM_LAUNCHLAB_POOL_CREATE = "RaydiumLaunchlabPoolCreate"
49
49
  RAYDIUM_LAUNCHLAB_MIGRATE_AMM = "RaydiumLaunchlabMigrateAmm"
50
+ PUMP_ROUTE_INTENT = "PumpRouteIntent"
50
51
  # PumpFun
51
52
  PUMP_FUN_TRADE = "PumpFunTrade"
52
53
  PUMP_FUN_BUY = "PumpFunBuy"
@@ -312,6 +313,7 @@ RAYDIUM_LAUNCHLAB_FILTER_TYPES = (
312
313
  EventType.RAYDIUM_LAUNCHLAB_MIGRATE_AMM,
313
314
  )
314
315
  INSTRUCTION_EVENT_TYPES = (
316
+ EventType.PUMP_ROUTE_INTENT,
315
317
  *PUMPFUN_FILTER_TYPES,
316
318
  *PUMP_FEES_EVENT_TYPES,
317
319
  *PUMPSWAP_FILTER_TYPES,
@@ -458,6 +460,7 @@ def all_event_types() -> List[EventType]:
458
460
  EventType.ACCOUNT_ORCA_TICK_ARRAY,
459
461
  EventType.ACCOUNT_ORCA_FEE_TIER,
460
462
  EventType.ACCOUNT_ORCA_WHIRLPOOLS_CONFIG,
463
+ EventType.PUMP_ROUTE_INTENT,
461
464
  ]
462
465
 
463
466
 
@@ -0,0 +1,96 @@
1
+ """Program-bound offline route intents. These are never confirmed fills."""
2
+ from dataclasses import dataclass, field
3
+ from typing import Optional
4
+ from .event_types import DexEvent, DexEventBase
5
+ from .grpc_types import EventType
6
+
7
+ PUMP='6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P'
8
+ AMM='pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA'
9
+ RAPID='rapidV5DAKtecYzetwCNoxXWHpezjeg4hGt9BGiVcGW'
10
+ DELTA='J7pourVwqP1VtRNBiFNqbdGxwkx7ta2LHAURURRRJqmd'
11
+ TOKEN='TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'
12
+ TOKEN22='TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb'
13
+ SYSTEM='11111111111111111111111111111111'
14
+ ATA='ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL'
15
+ GLOBAL='4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf'
16
+ EVENT='Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1'
17
+ FEES='pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ'
18
+ MULTI=bytes([43,100,73,19,233,246,111,148])
19
+ CURVE=bytes([225,154,117,22,215,86,246,103])
20
+
21
+ @dataclass
22
+ class PumpRouteHop:
23
+ base_mint: str
24
+ quote_mint: str
25
+ venue: str
26
+ base_vault: str
27
+ quote_vault: str
28
+
29
+ @dataclass
30
+ class PumpRouteIntentEvent(DexEventBase):
31
+ kind: str = ''
32
+ program: str = ''
33
+ instruction_index: int = 0
34
+ user: str = ''
35
+ input_account: str = ''
36
+ output_account: str = ''
37
+ amount_in: Optional[int] = None
38
+ min_amount_out: Optional[int] = None
39
+ hops: list[PumpRouteHop] = field(default_factory=list)
40
+ instruction_data: list[int] = field(default_factory=list)
41
+ # Intended direction relative to the wrapper hop's base mint, not a fill.
42
+ is_buy: Optional[bool] = None
43
+ # Official underlying instruction name encoded in the wrapper; unknown is None.
44
+ ix_name: Optional[str] = None
45
+
46
+
47
+ def allows_route(filter, program):
48
+ if filter is None:
49
+ return True
50
+ excluded=getattr(filter,'exclude_types',())
51
+ if EventType.PUMP_ROUTE_INTENT in excluded or EventType.PUMP_FUN_TRADE in excluded or (program==AMM and EventType.PUMP_SWAP_TRADE in excluded):
52
+ return False
53
+ included=getattr(filter,'include_only',None)
54
+ if included is not None:
55
+ return any(k in included for k in (EventType.PUMP_ROUTE_INTENT,EventType.PUMP_FUN_TRADE)) or (program==AMM and EventType.PUMP_SWAP_TRADE in included)
56
+ return filter.should_include(EventType.PUMP_ROUTE_INTENT)
57
+
58
+
59
+ def may_parse_route(program, data):
60
+ return ((program==AMM and data[:8]==MULTI) or (program==PUMP and data[:8]==CURVE)
61
+ or (program==DELTA and len(data)==28 and data[:8]==bytes([122,28,94,147,180,45,240,97]))
62
+ or (program==RAPID and len(data)==41 and data[0]==0 and data[9:17]==bytes([1,0,0,27,15,14,8,24]) and data[17:25]==bytes([194,171,28,70,104,77,91,47]) and data[25:33]==bytes(8)))
63
+
64
+
65
+ def multi_hop_args(program,data,a):
66
+ if program!=AMM or len(data)!=24 or data[:8]!=MULTI or len(a)<21 or (len(a)-16)%5 or any(a[i]!=v for i,v in {7:TOKEN,8:TOKEN22,9:SYSTEM,11:AMM,12:PUMP}.items()):
67
+ return None
68
+ amount=int.from_bytes(data[8:16],'little')
69
+ return (amount,int.from_bytes(data[16:24],'little')) if amount else None
70
+
71
+
72
+ def parse_route(program,data,a,metadata,index,filter=None):
73
+ if not may_parse_route(program,data) or not allows_route(filter,program):
74
+ return None
75
+ u=lambda at:int.from_bytes(data[at:at+8],'little')
76
+ if program==AMM:
77
+ args=multi_hop_args(program,data,a)
78
+ if args is None:return None
79
+ kind,fixed,user,source,dest,amount,minimum='MultiHopSwap',16,0,1,2,*args
80
+ elif program==PUMP:
81
+ if len(data)<20:return None
82
+ count=int.from_bytes(data[16:20],'little')
83
+ if not count or len(data)!=20+count or len(a)!=13+count*5 or any(a[i]!=v for i,v in {8:TOKEN,9:TOKEN22,10:SYSTEM,11:EVENT,12:PUMP}.items()):return None
84
+ kind,fixed,user,source,dest,amount,minimum='MultiHopCurveSwap',13,3,5,6,u(8),None
85
+ elif program==RAPID:
86
+ if len(a)!=33 or a[0]!=a[19] or a[2]!=a[8] or a[9] not in (TOKEN,TOKEN22) or any(a[i]!=v for i,v in {3:TOKEN,4:SYSTEM,5:PUMP,6:GLOBAL,10:TOKEN,11:ATA,29:FEES,30:SYSTEM,31:EVENT,32:PUMP}.items()):return None
87
+ kind,fixed,user,source,dest,amount,minimum='RapidBuy',0,0,21,20,u(1),u(33)
88
+ else:
89
+ if len(a)!=30 or a[0]!=a[14] or a[4] not in (TOKEN,TOKEN22) or a[5] not in (TOKEN,TOKEN22) or any(a[i]!=v for i,v in {1:GLOBAL,6:ATA,24:FEES,25:SYSTEM,26:EVENT,27:PUMP}.items()):return None
90
+ kind,fixed,user,source,dest,amount,minimum='BuyPumpDelta',0,0,16,15,None,None
91
+ if amount==0:return None
92
+ hops=[PumpRouteHop(*a[i:i+5]) for i in range(fixed,len(a),5)] if fixed else [PumpRouteHop(*(a[i] for i in ((7,2,16,17,18) if program==RAPID else (2,3,11,12,13))))]
93
+ return DexEvent(EventType.PUMP_ROUTE_INTENT,PumpRouteIntentEvent(
94
+ metadata,kind,program,index,a[user],a[source],a[dest],amount,minimum,hops,list(data),
95
+ is_buy=True if kind in ('RapidBuy', 'BuyPumpDelta') else None,
96
+ ix_name='buy_exact_quote_in_v2' if kind == 'RapidBuy' else None))
@@ -163,18 +163,11 @@ def parse_pump_upgrade_event(disc, data, metadata, program_id=None):
163
163
 
164
164
  def decode_pump_multi_hop_intent(program, data, accounts):
165
165
  """Instruction limits only. Actual execution is reported by per-hop trade events."""
166
- if (
167
- program != "pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA"
168
- or len(data) != 24
169
- or data[:8] != bytes([43, 100, 73, 19, 233, 246, 111, 148])
170
- or len(accounts) < 21
171
- or (len(accounts) - 16) % 5
172
- ):
173
- return None
174
- amount_in = int.from_bytes(data[8:16], "little")
175
- minimum = int.from_bytes(data[16:24], "little")
176
- if not amount_in or not minimum:
166
+ from .pump_routes import multi_hop_args
167
+ args = multi_hop_args(program, data, accounts)
168
+ if args is None:
177
169
  return None
170
+ amount_in, minimum = args
178
171
  return dict(
179
172
  user=accounts[0],
180
173
  input_account=accounts[1],
@@ -1,8 +1,7 @@
1
1
  """ShredStream gRPC 客户端:SubscribeEntries + bincode 解码 + DEX 外层指令。
2
2
 
3
3
  限制:与 Rust 文档一致——不解析 inner CPI 日志;当前 Python 热路径只使用静态账户,
4
- V0 ALT 加载账户用默认 pubkey 占位继续 best-effort 解析;若 program id 来自 ALT,
5
- 会按候选 program id 尝试 discriminator 解析。需安装 ``solders``(``pip install 'sol-parser-sdk-python[shredstream]'``)。
4
+ 默认跳过未解析账户;ALT 只使用调用方预热缓存,不回退 RPC。Legacy/V0/V1 使用原生线格式解码。
6
5
  """
7
6
 
8
7
  from __future__ import annotations
@@ -133,102 +132,94 @@ def _should_parse_shred_instructions(filter: Optional[EventTypeFilter]) -> bool:
133
132
  return event_type_filter_allows_instruction_parsing(list(include_only))
134
133
 
135
134
 
136
- def _events_from_versioned_tx_wire(
137
- raw: bytes,
138
- signature: str,
139
- slot: int,
140
- tx_index: int,
141
- recv_us: int,
142
- filter: Optional[EventTypeFilter],
143
- ) -> List[DexEvent]:
135
+ def _parse_decoded_shred(tx, keys, signature, slot, tx_index, recv_us, filter, best_effort=False):
136
+ from .pump_routes import may_parse_route, parse_route
137
+ from .grpc_types import EventMetadata
144
138
  if not _should_parse_shred_instructions(filter):
145
139
  return []
140
+ msg = tx['message']
141
+ signature = signature or tx['signatures'][0]
142
+ instructions = [(keys[ix['programIdIndex']] if ix['programIdIndex'] < len(keys) else None,
143
+ (ix['data'] if isinstance(ix['data'], bytes) else base58.b58decode(ix['data'])), bytes(ix['accounts'])) for ix in msg['instructions']]
144
+ created, mayhem = set(), set()
145
+ if _pumpfun_filter_allows(filter):
146
+ for pid, data, indices in instructions:
147
+ if pid == PUMPFUN_PROGRAM_ID and (best_effort or all(i < len(keys) for i in indices)):
148
+ c, m = detect_pumpfun_create_mints(pid, data, indices, keys)
149
+ created |= c
150
+ mayhem |= m
151
+ out = []
152
+ for index, (pid, data, indices) in enumerate(instructions):
153
+ resolved = pid is not None and all(i < len(keys) for i in indices)
154
+ if not resolved and not best_effort:
155
+ continue
156
+ if pid and may_parse_route(pid, data):
157
+ if resolved:
158
+ metadata = EventMetadata(signature=signature, slot=slot, tx_index=tx_index, grpc_recv_us=recv_us,
159
+ recent_blockhash=msg['recentBlockhash'])
160
+ event = parse_route(pid, data, [keys[i] for i in indices], metadata, index, filter)
161
+ if event:out.append(event)
162
+ continue
163
+ if pid == PUMPFUN_PROGRAM_ID:
164
+ if not _pumpfun_filter_allows(filter):continue
165
+ event = _filter_parsed_event(parse_pumpfun_shred_ix(data, keys, indices, pid, signature,
166
+ slot, tx_index, recv_us, created, mayhem), filter)
167
+ else:
168
+ accounts = _static_ix_account_strings(keys, indices)
169
+ event = None
170
+ for program in ([pid] if pid else _UNKNOWN_PROGRAM_CANDIDATES):
171
+ event = parse_instruction_unified(data, accounts, signature, slot, tx_index, None, recv_us, filter, program)
172
+ if event:break
173
+ if event:
174
+ if hasattr(event.data, 'metadata'):event.data.metadata.recent_blockhash = msg['recentBlockhash']
175
+ out.append(event)
176
+ enrich_pumpfun_same_tx_post_merge(out)
177
+ return out
146
178
 
147
- try:
148
- from solders.message import Message as LegacyMessage # type: ignore
149
- from solders.message import MessageV0 # type: ignore
150
- from solders.transaction import VersionedTransaction # type: ignore
151
- except ImportError:
152
- return []
153
179
 
180
+ def _decode_shred(raw, raw_instructions=True):
181
+ from .wire_transaction import _decode_wire_transaction
182
+ return _decode_wire_transaction(raw, raw_instructions=raw_instructions)[0]
183
+
184
+
185
+ def parse_shred_transaction_with_loaded_addresses(raw, writable, readonly, signature='', slot=0, tx_index=0, recv_us=0, filter=None):
186
+ """Strict, offline parsing. Reject inconsistent ALT counts before producing events."""
187
+ tx = _decode_shred(raw)
188
+ return _parse_loaded_shred(tx, writable, readonly, signature, slot, tx_index, recv_us, filter)
189
+
190
+
191
+ def _parse_loaded_shred(tx, writable, readonly, signature, slot, tx_index, recv_us, filter):
192
+ msg = tx['message']
193
+ lookups = msg.get('addressTableLookups', [])
194
+ if len(writable) != sum(len(l['writableIndexes']) for l in lookups) or len(readonly) != sum(len(l['readonlyIndexes']) for l in lookups):
195
+ raise ValueError('ALT address counts do not match transaction')
196
+ keys = [*msg['accountKeys'], *writable, *readonly]
197
+ if any(ix['programIdIndex'] >= len(keys) or any(i >= len(keys) for i in ix['accounts']) for ix in msg['instructions']):
198
+ raise ValueError('Unresolved instruction index')
199
+ return _parse_decoded_shred(tx, keys, signature, slot, tx_index, recv_us, filter)
200
+
201
+
202
+ def parse_shred_transaction(raw, signature='', slot=0, tx_index=0, recv_us=0, filter=None, *, best_effort=False, address_lookup_resolver=None):
203
+ """Static keys by default; optional slot-aware resolver must read only a prewarmed cache."""
154
204
  try:
155
- vt = VersionedTransaction.from_bytes(raw)
156
- # Decoding does not validate header/account/program indexes. Loaded ALT
157
- # addresses may remain unresolved, but the wire structure must be valid.
158
- vt.sanitize()
159
- except Exception:
160
- return []
161
- if not vt.signatures:
162
- return []
163
- sig = signature or base58.b58encode(bytes(vt.signatures[0])).decode("ascii")
164
- msg = vt.message
165
- out: List[DexEvent] = []
166
-
167
- if isinstance(msg, MessageV0):
168
- keys = [str(k) for k in msg.account_keys]
169
- ixs: List[tuple] = []
170
- for cix in msg.instructions:
171
- pid = keys[cix.program_id_index] if cix.program_id_index < len(keys) else None
172
- ixs.append((pid, bytes(cix.data), _ix_accounts_bytes(cix.accounts)))
173
- elif isinstance(msg, LegacyMessage):
174
- keys = [str(k) for k in msg.account_keys]
175
- ixs = []
176
- for ix in msg.instructions:
177
- pid = keys[ix.program_id_index] if ix.program_id_index < len(keys) else None
178
- ixs.append((pid, bytes(ix.data), _ix_accounts_bytes(ix.accounts)))
179
- else:
205
+ # Resolver callbacks retain the public JSON-compatible decoded shape.
206
+ tx = _decode_shred(raw, raw_instructions=address_lookup_resolver is None)
207
+ except (ValueError, IndexError, TypeError):
180
208
  return []
209
+ if address_lookup_resolver is not None and tx['message'].get('addressTableLookups'):
210
+ loaded = address_lookup_resolver(tx, slot)
211
+ if loaded is None:return []
212
+ return _parse_loaded_shred(tx, *loaded, signature, slot, tx_index, recv_us, filter)
213
+ return _parse_decoded_shred(tx, tx['message']['accountKeys'], signature, slot, tx_index, recv_us, filter, best_effort)
181
214
 
182
- created: set = set()
183
- mayhem: set = set()
184
- if _pumpfun_filter_allows(filter):
185
- for pid, data, ix_acc in ixs:
186
- if pid is not None and pid != PUMPFUN_PROGRAM_ID:
187
- continue
188
- c, m = detect_pumpfun_create_mints(PUMPFUN_PROGRAM_ID, data, ix_acc, keys)
189
- created |= c
190
- mayhem |= m
191
-
192
- for pid, data, ix_acc in ixs:
193
- if pid == PUMPFUN_PROGRAM_ID:
194
- if not _pumpfun_filter_allows(filter):
195
- continue
196
- ev = parse_pumpfun_shred_ix(
197
- data, keys, ix_acc, pid, sig, slot, tx_index, recv_us, created, mayhem
198
- )
199
- ev = _filter_parsed_event(ev, filter)
200
- if ev:
201
- out.append(ev)
202
- continue
203
- accounts = _static_ix_account_strings(keys, ix_acc)
204
- if pid is None:
205
- for candidate in _UNKNOWN_PROGRAM_CANDIDATES:
206
- if candidate == PUMPFUN_PROGRAM_ID:
207
- if not _pumpfun_filter_allows(filter):
208
- continue
209
- ev = parse_pumpfun_shred_ix(
210
- data, keys, ix_acc, PUMPFUN_PROGRAM_ID, sig, slot, tx_index, recv_us, created, mayhem
211
- )
212
- ev = _filter_parsed_event(ev, filter)
213
- else:
214
- ev = parse_instruction_unified(
215
- bytes(data), accounts, sig, slot, tx_index, None, recv_us, filter, candidate
216
- )
217
- if ev:
218
- out.append(ev)
219
- break
220
- continue
221
- ev = parse_instruction_unified(
222
- bytes(data), accounts, sig, slot, tx_index, None, recv_us, filter, pid
223
- )
224
- if ev:
225
- out.append(ev)
226
215
 
227
- for ev in out:
228
- if hasattr(ev.data, "metadata"):
229
- ev.data.metadata.grpc_recv_us = recv_us
230
- enrich_pumpfun_same_tx_post_merge(out)
231
- return out
216
+ def _events_from_versioned_tx_wire(raw, signature, slot, tx_index, recv_us, filter):
217
+ return parse_shred_transaction(raw, signature, slot, tx_index, recv_us, filter)
218
+
219
+
220
+ def parse_shred_transaction_best_effort(raw, signature='', slot=0, tx_index=0, recv_us=0, filter=None):
221
+ """Explicit legacy placeholder mapping; route adapters still require resolved keys."""
222
+ return parse_shred_transaction(raw, signature, slot, tx_index, recv_us, filter, best_effort=True)
232
223
 
233
224
 
234
225
  class ShredStreamClient:
@@ -237,6 +228,12 @@ class ShredStreamClient:
237
228
  def __init__(self, endpoint: str, config: Optional[ShredStreamConfig] = None):
238
229
  self.endpoint = endpoint
239
230
  self.config = config or ShredStreamConfig()
231
+ self.address_lookup_resolver = None
232
+
233
+ def with_address_lookup_resolver(self, resolver):
234
+ """Set a synchronous slot-aware cache callback; no automatic RPC fallback."""
235
+ self.address_lookup_resolver = resolver
236
+ return self
240
237
 
241
238
  @classmethod
242
239
  def new_with_config(cls, endpoint: str, config: ShredStreamConfig) -> ShredStreamClient:
@@ -273,14 +270,12 @@ class ShredStreamClient:
273
270
  on_error(e)
274
271
  continue
275
272
  for tx_counter, raw in enumerate(raws):
276
- sig0 = ""
277
273
  try:
278
- from solders.transaction import VersionedTransaction # type: ignore
279
-
280
- sig0 = base58.b58encode(bytes(VersionedTransaction.from_bytes(raw).signatures[0])).decode("ascii")
281
- except Exception:
282
- pass
283
- for ev in _events_from_versioned_tx_wire(raw, sig0, slot, tx_counter, recv_us, f):
284
- yield ev
274
+ events = parse_shred_transaction(raw, slot=slot, tx_index=tx_counter, recv_us=recv_us,
275
+ filter=f, address_lookup_resolver=self.address_lookup_resolver)
276
+ except Exception as error:
277
+ if on_error:on_error(error)
278
+ continue
279
+ yield from events
285
280
  finally:
286
281
  channel.close()
@@ -2,6 +2,19 @@
2
2
 
3
3
  from __future__ import annotations
4
4
  import base58
5
+ try:
6
+ from solders.pubkey import Pubkey
7
+ from solders.signature import Signature
8
+ except ImportError:
9
+ # solders is an optional ShredStream accelerator; core parsing stays usable.
10
+ def _key_string(raw):
11
+ return base58.b58encode(raw).decode()
12
+ _signature_string = _key_string
13
+ else:
14
+ def _key_string(raw):
15
+ return str(Pubkey.from_bytes(raw))
16
+ def _signature_string(raw):
17
+ return str(Signature.from_bytes(raw))
5
18
 
6
19
 
7
20
  class _Reader:
@@ -32,9 +45,12 @@ class _Reader:
32
45
  raise ValueError("Invalid short-u16")
33
46
 
34
47
 
35
- def decode_wire_transaction(
36
- data: bytes, offset: int = 0, require_complete: bool = True
37
- ) -> tuple[dict, int]:
48
+ def decode_wire_transaction(data: bytes, offset: int = 0, require_complete: bool = True) -> tuple[dict, int]:
49
+ return _decode_wire_transaction(data, offset, require_complete)
50
+
51
+
52
+ def _decode_wire_transaction(data: bytes, offset: int = 0, require_complete: bool = True,
53
+ *, raw_instructions: bool = False) -> tuple[dict, int]:
38
54
  if not isinstance(offset, int) or offset < 0 or offset >= len(data):
39
55
  raise ValueError("Invalid wire offset")
40
56
  r = _Reader(data, offset)
@@ -69,7 +85,7 @@ def decode_wire_transaction(
69
85
  {
70
86
  "programIdIndex": program,
71
87
  "accounts": list(r.take(accounts)),
72
- "data": base58.b58encode(r.take(length)).decode(),
88
+ "data": (r.take(length) if raw_instructions else base58.b58encode(r.take(length)).decode()),
73
89
  }
74
90
  for program, accounts, length in headers
75
91
  ]
@@ -103,7 +119,7 @@ def decode_wire_transaction(
103
119
  {
104
120
  "programIdIndex": program,
105
121
  "accounts": accounts,
106
- "data": base58.b58encode(payload).decode(),
122
+ "data": (payload if raw_instructions else base58.b58encode(payload).decode()),
107
123
  }
108
124
  )
109
125
  if version == 0:
@@ -113,7 +129,7 @@ def decode_wire_transaction(
113
129
  readonly = list(r.take(r.short()))
114
130
  lookups.append(
115
131
  {
116
- "accountKey": base58.b58encode(key).decode(),
132
+ "accountKey": _key_string(key),
117
133
  "writableIndexes": writable,
118
134
  "readonlyIndexes": readonly,
119
135
  }
@@ -152,15 +168,15 @@ def decode_wire_transaction(
152
168
  header,
153
169
  )
154
170
  ),
155
- "accountKeys": [base58.b58encode(key).decode() for key in keys],
156
- "recentBlockhash": base58.b58encode(blockhash).decode(),
171
+ "accountKeys": [_key_string(key) for key in keys],
172
+ "recentBlockhash": _key_string(blockhash),
157
173
  "instructions": instructions,
158
174
  "addressTableLookups": lookups,
159
175
  }
160
176
  if config is not None:
161
177
  message["config"] = config
162
178
  return {
163
- "signatures": [base58.b58encode(s).decode() for s in signatures],
179
+ "signatures": [_signature_string(s) for s in signatures],
164
180
  "message": message,
165
181
  "version": version,
166
182
  }, r.pos - offset
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: sol-parser-sdk-python
3
- Version: 0.5.12
3
+ Version: 0.5.14
4
4
  Summary: Solana DEX program log parsing (pure Python, API aligned with sol-parser-sdk)
5
5
  Requires-Python: >=3.10
6
6
  Requires-Dist: base58>=2.0
@@ -13,8 +13,11 @@ Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
13
13
  Requires-Dist: pytest-benchmark>=4.0; extra == 'dev'
14
14
  Requires-Dist: pytest>=8.0; extra == 'dev'
15
15
  Requires-Dist: requests>=2.31; extra == 'dev'
16
+ Requires-Dist: solders==0.26.0; extra == 'dev'
16
17
  Provides-Extra: shredstream
17
18
  Requires-Dist: solders>=0.21.0; extra == 'shredstream'
19
+ Provides-Extra: simulation
20
+ Requires-Dist: solders==0.26.0; extra == 'simulation'
18
21
  Description-Content-Type: text/markdown
19
22
 
20
23
  <div align="center">
@@ -57,15 +60,27 @@ Parser SDK language versions and related Rust SDKs:
57
60
 
58
61
  | Language | Repository | Description | Version |
59
62
  |----------|------------|-------------|---------|
60
- | Rust | [sol-parser-sdk](https://github.com/0xfnzero/sol-parser-sdk) | Solana DEX transaction and account event parsing | `v0.7.13` |
61
- | Node.js | [sol-parser-sdk-nodejs](https://github.com/0xfnzero/sol-parser-sdk-nodejs) | TypeScript/JavaScript for Node.js | `v0.5.19` |
62
- | Python | [sol-parser-sdk-python](https://github.com/0xfnzero/sol-parser-sdk-python) | Async/await native support | `v0.5.12` |
63
- | Go | [sol-parser-sdk-golang](https://github.com/0xfnzero/sol-parser-sdk-golang) | Go transaction and account event parsing | `v0.5.12` |
64
- | **Rust** | [sol-shred-sdk](https://github.com/0xfnzero/sol-shred-sdk) | Raw Solana shred decoding and ShredStream DEX event parsing | `v4.0.4` |
65
- | **Rust** | [sol-trade-sdk](https://github.com/0xfnzero/sol-trade-sdk) | Solana DEX trade construction and transaction execution | `v6.0.1` |
63
+ | Rust | [sol-parser-sdk](https://github.com/0xfnzero/sol-parser-sdk) | Solana DEX transaction and account event parsing | `v0.7.15` |
64
+ | Node.js | [sol-parser-sdk-nodejs](https://github.com/0xfnzero/sol-parser-sdk-nodejs) | TypeScript/JavaScript for Node.js | `v0.5.21` |
65
+ | Python | [sol-parser-sdk-python](https://github.com/0xfnzero/sol-parser-sdk-python) | Async/await native support | `v0.5.14` |
66
+ | Go | [sol-parser-sdk-golang](https://github.com/0xfnzero/sol-parser-sdk-golang) | Go transaction and account event parsing | `v0.5.14` |
67
+ | **Rust** | [sol-shred-sdk](https://github.com/0xfnzero/sol-shred-sdk) | Raw Solana shred decoding and ShredStream DEX event parsing | `v4.0.6` |
68
+ | **Rust** | [sol-trade-sdk](https://github.com/0xfnzero/sol-trade-sdk) | Solana DEX trade construction and transaction execution | `v6.0.2` |
66
69
 
67
70
  ---
68
71
 
72
+ ## v0.5.14 — Pump route direction and instruction names
73
+
74
+ Route intents now expose `is_buy` and `ix_name`, following existing trade field names and official IDL instruction names. RapidBuy reports a buy intent and `buy_exact_quote_in_v2`; BuyPumpDelta reports only a buy intent. Multi-hop direction and unknown methods remain null. Read currencies from `hops[].base_mint` / `quote_mint`. These hints do not confirm execution, and filters do not convert intents into trades.
75
+
76
+ Older JSON without the fields remains readable as unknown. Rust struct literals must supply the new fields; Go uses pointers and Node.js/Python use null/None for unknown values. Streamer now forwards `DexEvent::PumpRouteIntentEvent` with protocol and event filtering.
77
+
78
+ ## v0.5.13 — Pump routes and offline replay
79
+
80
+ Adds native Pump route-intent parsing for official multi-hop instructions and the exact RapidBuy/BuyPumpDelta wrapper layouts captured in reported transactions. Adds locally cached ALT resolution and rejects unresolved account identities by default, with explicit best-effort compatibility APIs where supported. Route intents expose instruction constraints and hop identities; confirmed execution amounts require execution metadata.
81
+
82
+ Includes the latest complete implementation, signed transaction fixtures, native offline-bank regression examples and reproducible local hot-path benchmarks. Unknown wrapper layouts are not inferred from embedded bytes. Local tests do not measure production network latency.
83
+
69
84
  ## v0.5.12 — Pump depth-2 compatibility
70
85
 
71
86
  Adds signed Pump depth-2 create-event replay coverage, including ALT-loaded accounts and executed logs. Existing event layouts and public parsing interfaces remain unchanged.
@@ -141,7 +156,7 @@ This is the Python implementation of the FnZero Solana DEX parser SDK for asynci
141
156
  **From PyPI**
142
157
 
143
158
  ```bash
144
- pip install sol-parser-sdk-python==0.5.12
159
+ pip install sol-parser-sdk-python==0.5.14
145
160
  ```
146
161
 
147
162
  **From source**
@@ -246,7 +261,7 @@ asyncio.run(main())
246
261
 
247
262
  Python includes a native ShredStream client (`ShredStreamClient`, `ShredStreamConfig`) plus the same env/CLI helpers as Node (`parse_shredstream_url`: `SHREDSTREAM_URL` / `SHRED_URL`, `--url` / `-u` / `--endpoint=`). Install the optional extra with `pip install 'sol-parser-sdk-python[shredstream]'`. ShredStream uses its own endpoint, **not** `GRPC_URL`.
248
263
 
249
- The Python ShredStream hot path uses static account keys only. V0 ALT-loaded instruction accounts are represented with default pubkey placeholders, and ALT-loaded outer program ids are parsed best-effort by discriminator. Inner CPI/log-only events still require the Yellowstone/RPC paths.
264
+ The Python ShredStream hot path uses strict static-account parsing by default. Supply loaded addresses or a slot-aware prewarmed-cache resolver for V0 ALT instructions; unresolved instructions are skipped. Legacy placeholders require the explicit `parse_shred_transaction_best_effort` API. Recognized wrapper/official routes emit `PumpRouteIntent`; raw shreds cannot reconstruct arbitrary CPI. Inner CPI/log-only events still require the Yellowstone/RPC paths.
250
265
 
251
266
  ---
252
267
 
@@ -257,18 +272,18 @@ From the **package root** after `pip install -e .`. Run with `python examples/<f
257
272
  | Description | Run command | Source |
258
273
  |-------------|-------------|--------|
259
274
  | **PumpFun** | | |
260
- | PumpFun trade filtering | `python examples/pumpfun_trade_filter.py` | [pumpfun_trade_filter.py](https://github.com/0xfnzero/sol-parser-sdk-python/blob/main/examples/pumpfun_trade_filter.py) | `v0.5.12` |
261
- | PumpFun events + metrics | `python examples/pumpfun_with_metrics.py` | [pumpfun_with_metrics.py](https://github.com/0xfnzero/sol-parser-sdk-python/blob/main/examples/pumpfun_with_metrics.py) | `v0.5.12` |
262
- | Quick PumpFun connection test | `python examples/pumpfun_quick_test.py` | [pumpfun_quick_test.py](https://github.com/0xfnzero/sol-parser-sdk-python/blob/main/examples/pumpfun_quick_test.py) | `v0.5.12` |
275
+ | PumpFun trade filtering | `python examples/pumpfun_trade_filter.py` | [pumpfun_trade_filter.py](https://github.com/0xfnzero/sol-parser-sdk-python/blob/main/examples/pumpfun_trade_filter.py) | `v0.5.14` |
276
+ | PumpFun events + metrics | `python examples/pumpfun_with_metrics.py` | [pumpfun_with_metrics.py](https://github.com/0xfnzero/sol-parser-sdk-python/blob/main/examples/pumpfun_with_metrics.py) | `v0.5.14` |
277
+ | Quick PumpFun connection test | `python examples/pumpfun_quick_test.py` | [pumpfun_quick_test.py](https://github.com/0xfnzero/sol-parser-sdk-python/blob/main/examples/pumpfun_quick_test.py) | `v0.5.14` |
263
278
  | **PumpSwap** | | |
264
- | PumpSwap ultra-low latency | `python examples/pumpswap_low_latency.py` | [pumpswap_low_latency.py](https://github.com/0xfnzero/sol-parser-sdk-python/blob/main/examples/pumpswap_low_latency.py) | `v0.5.12` |
265
- | PumpSwap events + metrics | `python examples/pumpswap_with_metrics.py` | [pumpswap_with_metrics.py](https://github.com/0xfnzero/sol-parser-sdk-python/blob/main/examples/pumpswap_with_metrics.py) | `v0.5.12` |
279
+ | PumpSwap ultra-low latency | `python examples/pumpswap_low_latency.py` | [pumpswap_low_latency.py](https://github.com/0xfnzero/sol-parser-sdk-python/blob/main/examples/pumpswap_low_latency.py) | `v0.5.14` |
280
+ | PumpSwap events + metrics | `python examples/pumpswap_with_metrics.py` | [pumpswap_with_metrics.py](https://github.com/0xfnzero/sol-parser-sdk-python/blob/main/examples/pumpswap_with_metrics.py) | `v0.5.14` |
266
281
  | **Meteora DAMM** | | |
267
- | Meteora DAMM V2 events | `python examples/meteora_damm_grpc.py` | [meteora_damm_grpc.py](https://github.com/0xfnzero/sol-parser-sdk-python/blob/main/examples/meteora_damm_grpc.py) | `v0.5.12` |
282
+ | Meteora DAMM V2 events | `python examples/meteora_damm_grpc.py` | [meteora_damm_grpc.py](https://github.com/0xfnzero/sol-parser-sdk-python/blob/main/examples/meteora_damm_grpc.py) | `v0.5.14` |
268
283
  | **Multi-protocol** | | |
269
- | Subscribe to every program in Rust `Protocol` / `program_ids` | `python examples/multi_protocol_grpc.py` | [multi_protocol_grpc.py](https://github.com/0xfnzero/sol-parser-sdk-python/blob/main/examples/multi_protocol_grpc.py) | `v0.5.12` |
284
+ | Subscribe to every program in Rust `Protocol` / `program_ids` | `python examples/multi_protocol_grpc.py` | [multi_protocol_grpc.py](https://github.com/0xfnzero/sol-parser-sdk-python/blob/main/examples/multi_protocol_grpc.py) | `v0.5.14` |
270
285
  | **Utility** | | |
271
- | Parse tx by signature (HTTP RPC; not gRPC). `TX_SIGNATURE` / `RPC_URL` or `SOLANA_RPC_URL` in `.env` or `--sig` / `--rpc`. | `python examples/parse_tx_by_signature.py` | [parse_tx_by_signature.py](https://github.com/0xfnzero/sol-parser-sdk-python/blob/main/examples/parse_tx_by_signature.py) | `v0.5.12` |
286
+ | Parse tx by signature (HTTP RPC; not gRPC). `TX_SIGNATURE` / `RPC_URL` or `SOLANA_RPC_URL` in `.env` or `--sig` / `--rpc`. | `python examples/parse_tx_by_signature.py` | [parse_tx_by_signature.py](https://github.com/0xfnzero/sol-parser-sdk-python/blob/main/examples/parse_tx_by_signature.py) | `v0.5.14` |
272
287
 
273
288
  **Env:** gRPC examples need **`GRPC_URL`** or **`GRPC_ENDPOINT`**, plus **`GRPC_AUTH_TOKEN`** or **`GRPC_TOKEN`** (or legacy `GEYSER_*`). See **`.env.example`**.
274
289
 
@@ -371,3 +386,14 @@ Full cross-language API parity is still in progress. See the [API migration guid
371
386
  实时 parser → trade 接入使用 Yellowstone **gRPC**;见 [gRPC 缓存接入与三语言示例](docs/USAGE.md#grpc-cache)。此路径不使用 WebSocket,报价和构建热路径不调用 RPC。
372
387
 
373
388
  Shared PumpFun create/create_v2 mainnet fixtures, replay instructions and verification limits are documented in the [validation guide](https://github.com/0xfnzero/sol-parser-sdk-golang/tree/main/validation/pumpfun_create_20261007).
389
+
390
+ ### Offline Pump ShredStream regressions
391
+
392
+ Pump route intents, strict cached ALT resolution and native signed replay/SBF simulation examples are documented in [examples/offline_bank/README.md](examples/offline_bank/README.md). Run the language-native examples and tests from this repository; no other-language test driver or RPC endpoint is needed. Unresolved instructions now skip by default; use the explicit best-effort API only for legacy behavior. Route intents must not be treated as confirmed fills.
393
+
394
+ Native offline CPU benchmark: `python -m examples.hot_path_benchmark`.
395
+ `examples/hot_path_benchmark.json` fixes warmup and measured iterations for six
396
+ signed wrapped-CPI/ALT transactions. Reported percentiles are per six-transaction
397
+ batch; fixture decoding and I/O occur before timing. Parsing performs no RPC.
398
+ Public wire-decoder dictionaries and resolver callbacks retain base58 strings;
399
+ the internal ShredStream path avoids an instruction-data base58 round trip.
@@ -1,4 +1,4 @@
1
- sol_parser/__init__.py,sha256=65QWzCkS993lUiDSLPaY0tu0cpvq5bzsFPabwFoyzEU,17166
1
+ sol_parser/__init__.py,sha256=0SBivj4hJynvlD617cEWSEUJScO04zIA0e_KUnw36r8,17535
2
2
  sol_parser/account_dispatcher.py,sha256=WgWD0833ArPtXuRGMO7_URDxPhLaCcnHc-e8RNeGCJI,19947
3
3
  sol_parser/block_meta.py,sha256=LuJ4oy6xvRmFjSIUDUG9k4Dg7q9l2xW9z35wYJdBmCw,854
4
4
  sol_parser/check_migration.py,sha256=PsRE_Zhnw2g_iaP_iYtlGsQutE2w_FsaZIP4GPeN8-o,537
@@ -6,13 +6,13 @@ sol_parser/clock.py,sha256=RHF99qMerKvEsT55krkftIh-uqy_uTzpgdKCqKBMDmA,278
6
6
  sol_parser/dex_parsers.py,sha256=eOigBKLpMQGZT_3dJwq18niDhY0fSGJrULDx_TGNC8Q,146032
7
7
  sol_parser/entries_decode.py,sha256=MOhGadNxWLerxBhGvuNatoWa2hzw2MXVz9NmNUhWvS8,3665
8
8
  sol_parser/env_config.py,sha256=Lw0SdZuy_MvUaVkyFxS0qPBgMzR9UBbxbN0CVz8nxg4,7296
9
- sol_parser/event_type_parity.py,sha256=089Ylls_I531kJP24i5BQBg6QBOHWuB-LP-KI_Vdu0Q,4498
10
- sol_parser/event_types.py,sha256=h8CT9-6Hm5PXVWPGGXe50cOGRGJJzDldO6L0OgdTj0s,97554
9
+ sol_parser/event_type_parity.py,sha256=mD9Lg43aPzJGvz0Ft94NxKw6XnpgBio5yL2xin9Wfdg,4521
10
+ sol_parser/event_types.py,sha256=m63dNNVxjx9baTSsKIcwZXK1EAlx4cdh2Vy0TBrAq0o,98387
11
11
  sol_parser/geyser_pb2.py,sha256=Hq66wmWxXD2jSbSVQW7vmBRB7nWmR1DuYDMQ6nKgl3o,20123
12
12
  sol_parser/geyser_pb2_grpc.py,sha256=ASPmZsCNvyCzt_j4IrhKjSacWUNLVuAiLfpjmyd-2Qc,15322
13
13
  sol_parser/grpc_client.py,sha256=fusMuSJsTPEUxgobdeimQ7s3Hu9n0bD8pIH7rEL40jM,37370
14
14
  sol_parser/grpc_instruction_parser.py,sha256=ogpnD3dTEeduxORH5VmwCnubGkQe9bbMCTC-NSH9Wkw,17107
15
- sol_parser/grpc_types.py,sha256=zqOx_JUsBQjKhZzeWqbiMw8LPzA8-3fKtU9j6HAS5u0,41276
15
+ sol_parser/grpc_types.py,sha256=cqBuHmUuRqE8MvCwGzPtRR-T7BKNonT5-k4P6yDzspI,41388
16
16
  sol_parser/inner_instruction_parser.py,sha256=i5tkKS7F1aZWUdE9pzm2o5_1EXWM8-v71cjo45jM-d8,21668
17
17
  sol_parser/instr_account_utils.py,sha256=MY8bgoIDiv2yJKeWxqhpfKc3pV4xUFTcYKnSXtnQMWc,1990
18
18
  sol_parser/instructions.py,sha256=XZt73ZJmCZE5LWF8A-yLmxGmF0dcPxnVuRmhMf-7ynY,88373
@@ -23,12 +23,13 @@ sol_parser/market.py,sha256=p_N6n3b4hEtUjHAQQyGSnrKdHYmkHdY1hXXObHRKc0Y,1858
23
23
  sol_parser/merger.py,sha256=hVIeocXYnLTP5qtXb4lZtED5EteE_g3a84ZeUwUmda0,13498
24
24
  sol_parser/order_buffer.py,sha256=f3yvvYglHX800hyF8JhFbjb1VoNtOvrqUR8lm3lvF-Y,7874
25
25
  sol_parser/parser.py,sha256=aSDbsbnUqBHEJ6UMdnZIuR-01fWs4_GxUwTJ3vQ0GXU,11906
26
- sol_parser/pump_upgrade.py,sha256=IiIjjbXqjkBp433PY4MnjDYYtFZyyKsBZrkM-AUPhVg,5470
26
+ sol_parser/pump_routes.py,sha256=U7FWxZYyP860jUZh5F8YKAoauki-hgmfu2DNDjEcplM,4868
27
+ sol_parser/pump_upgrade.py,sha256=BnVB8PVHfPtILBOlI29nbXABihVuXZUO82Yw6upFhRM,5212
27
28
  sol_parser/pumpfun_fee_enrich.py,sha256=NHC_chCv2wuaOW5taYG8R6M1bu8cmdxcLf8cjSfo7Kc,4688
28
29
  sol_parser/rpc_parser.py,sha256=Ft1VSBk66RLbwURKIoGtsRFDwjorh4EE6Gdqkil5tHY,25871
29
30
  sol_parser/rust_api_inventory.py,sha256=V5Bx1M3GT-ku_vj_kD6lnbqWExv1K_A00PrmhCFfRec,2257
30
31
  sol_parser/rust_event_json.py,sha256=7hho9TGfSOQjHev_8uRa4YHU1hrEsW1RfwcU9qHYz1o,1649
31
- sol_parser/shredstream_client.py,sha256=HwCgFPsXC8N1gq_8VhNnx2jxV6W1-wg9pFwwLgw4X-w,10141
32
+ sol_parser/shredstream_client.py,sha256=0D6dPZ366mmSuE-bMfjyt-Y3vrB35VMt1cJlCUuZQ_Y,11660
32
33
  sol_parser/shredstream_pb2.py,sha256=BMrgCTcvRu5sY_QG1nj5AhWK9RL1fqF9Ga0xYihQfio,1703
33
34
  sol_parser/shredstream_pb2_grpc.py,sha256=zfRJaDj-76Gbr6tC3x4gFOz6Xpu2fmJFWWcTOTmyIXs,3013
34
35
  sol_parser/shredstream_pumpfun.py,sha256=agTryEilG7c9Ttlek2-d2fyhzwGHIKrUD9YMAJjvXfk,11187
@@ -39,7 +40,7 @@ sol_parser/stonkfun_registry.py,sha256=el8xm3FGU5Eo4D5yq7-NCINSdsn7Pzl-9i1nKNgLa
39
40
  sol_parser/transaction_route.py,sha256=aPUy95_RHUDl6MFGzQ9hJbpv69LSHxFYCeRTBVc9SLY,19668
40
41
  sol_parser/u128_parity.py,sha256=D8PYuy1l-1QwkIEeGCLvrGfzAfTzpBDcGINxRIJAEPs,3487
41
42
  sol_parser/verify_discriminators.py,sha256=oqCBWL065ixBIjhHW255nk4S-F1F0x4zfTzs68nXMqA,3011
42
- sol_parser/wire_transaction.py,sha256=CVaVdeaNuVwgECir8MGCVApSHATMhxSwvELWA8a2A3E,6143
43
+ sol_parser/wire_transaction.py,sha256=ATJSDY1D-m0vCBMooEe2g8F5a1QVOZyl7k-lEDSheSQ,6858
43
44
  sol_parser/account_fillers/__init__.py,sha256=q4q7HZF0Z4-rxhKoRMzV52HSkJ_n_POm4vimYUQlCOA,235
44
45
  sol_parser/account_fillers/meteora.py,sha256=ecY3F4KkjnVxBc-Zsnzru52DggkYOdbeauaYrznDxFY,2111
45
46
  sol_parser/account_fillers/orca.py,sha256=2s-hfi20fa5sy6p1rGc7_7NxzkpaleJdqn3YD41aBAw,895
@@ -58,7 +59,7 @@ sol_parser/grpc/subscribe_builder.py,sha256=xH9NZ1Lp-7AQKcgxoqyE0PrB3vdOqnScm_Ht
58
59
  sol_parser/grpc/transaction_meta.py,sha256=NmIffIQ1_OIfWGjy6JY-f8pIK5ucjDZXXJryjnlgoQs,5894
59
60
  sol_parser/instr/__init__.py,sha256=0_Ky8KpVEoXzxszHcHLTuY2SDsJwu0uAF2Q0wMY1e-c,503
60
61
  sol_parser/logs/__init__.py,sha256=e1cbhbCNeXy-NZvVsYCpGksBpZf4NJBLmdlky06og-U,349
61
- sol_parser_sdk_python-0.5.12.dist-info/METADATA,sha256=Sv80DT_XBQDzK3gidPHx1qlG3YNd77o4WSYT4rIVV-0,17969
62
- sol_parser_sdk_python-0.5.12.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
63
- sol_parser_sdk_python-0.5.12.dist-info/entry_points.txt,sha256=ZGXRb-2jBdc56d8PCAZFiJBLTAzUKFeHPohysJnKVbA,206
64
- sol_parser_sdk_python-0.5.12.dist-info/RECORD,,
62
+ sol_parser_sdk_python-0.5.14.dist-info/METADATA,sha256=SruOAOSNW0NilLlGbiS2CnYu4M19rLdyl5Q2H8iM9Gc,20745
63
+ sol_parser_sdk_python-0.5.14.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
64
+ sol_parser_sdk_python-0.5.14.dist-info/entry_points.txt,sha256=ZGXRb-2jBdc56d8PCAZFiJBLTAzUKFeHPohysJnKVbA,206
65
+ sol_parser_sdk_python-0.5.14.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.27.0
2
+ Generator: hatchling 1.32.4
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any