sol-parser-sdk-python 0.5.9__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.
@@ -110,6 +110,31 @@ def fill_accounts_with_owned_keys(
110
110
  return
111
111
  filler(get)
112
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
+
113
138
  et = event.type
114
139
  data = event.data
115
140
 
@@ -121,9 +146,9 @@ def fill_accounts_with_owned_keys(
121
146
  ):
122
147
  run(PUMPFUN_PROGRAM_ID, lambda g: pumpfun.fill_trade_accounts(data, g))
123
148
  elif et == EventType.PUMP_FUN_CREATE:
124
- run(PUMPFUN_PROGRAM_ID, lambda g: pumpfun.fill_create_accounts(data, g))
149
+ fill_create()
125
150
  elif et == EventType.PUMP_FUN_CREATE_V2:
126
- run(PUMPFUN_PROGRAM_ID, lambda g: pumpfun.fill_create_v2_accounts(data, g))
151
+ fill_create(True)
127
152
  elif et == EventType.PUMP_FUN_MIGRATE:
128
153
  run(PUMPFUN_PROGRAM_ID, lambda g: pumpfun.fill_migrate_accounts(data, g))
129
154
  elif et == EventType.PUMP_SWAP_BUY:
@@ -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
- if get(15) == "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P":
117
- fill_create_v2_accounts(e, get) # type: ignore[arg-type]
118
- return
119
- if _empty(e.mint):
120
- e.mint = get(0)
121
- if _empty(e.bonding_curve):
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
 
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)
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
sol_parser/grpc_client.py CHANGED
@@ -517,6 +517,7 @@ class YellowstoneGrpc:
517
517
  signature = base58.b58encode(bytes(info.signature)).decode("ascii") if info.signature else ""
518
518
 
519
519
  from .grpc_instruction_parser import (
520
+ subscribe_transaction_failed,
520
521
  detect_pumpfun_create_from_logs,
521
522
  enrich_dex_events_with_subscribe_tx_info,
522
523
  parse_instructions_enhanced_from_subscribe_tx_info,
@@ -526,6 +527,9 @@ class YellowstoneGrpc:
526
527
  from .pumpfun_fee_enrich import enrich_pumpfun_same_tx_post_merge
527
528
  from .grpc_types import EventType
528
529
 
530
+ if subscribe_transaction_failed(info):
531
+ return # Suppress both instruction events and rolled-back log events.
532
+
529
533
  instruction_events = parse_instructions_enhanced_from_subscribe_tx_info(
530
534
  info,
531
535
  slot,
@@ -229,6 +229,16 @@ def _meta_dict(
229
229
  return m
230
230
 
231
231
 
232
+ def subscribe_transaction_failed(info: SubscribeUpdateTransactionInfo) -> bool:
233
+ """Read protobuf error presence, including errors with an empty encoded payload."""
234
+ if not info.meta_raw:
235
+ return False
236
+ from . import solana_storage_pb2 as sol_pb
237
+ meta = sol_pb.TransactionStatusMeta()
238
+ meta.ParseFromString(info.meta_raw)
239
+ return meta.HasField("err")
240
+
241
+
232
242
  def parse_instructions_enhanced_from_subscribe_tx_info(
233
243
  info: SubscribeUpdateTransactionInfo,
234
244
  slot: int,
@@ -268,7 +278,7 @@ def parse_instructions_enhanced_from_parsed(
268
278
  transaction_pb: Any = None,
269
279
  ) -> List[DexEvent]:
270
280
  """接受已 Parse 的 ``Message`` 与 ``TransactionStatusMeta``(来自 ``solana_storage_pb2``)。"""
271
- if not should_parse_instructions(filter):
281
+ if meta.HasField("err") or not should_parse_instructions(filter):
272
282
  return []
273
283
 
274
284
  grpc_us = int(time.time() * 1_000_000) if grpc_recv_us is None else grpc_recv_us
@@ -851,9 +851,9 @@ def _parse_pumpfun_create_v2(data: bytes, accounts: List[str], meta: EventMetada
851
851
  is_cashback_enabled=is_cashback_enabled,
852
852
  creator_fee_bps=creator_fee_bps,
853
853
  is_holder_reward=is_holder_reward,
854
- quote_mint=_get_account_safe(accounts, 16) or Z,
855
- quote_vault=_get_account_safe(accounts, 17),
856
- quote_token_program=_get_account_safe(accounts, 18),
854
+ quote_mint=Z,
855
+ quote_vault=Z,
856
+ quote_token_program=Z,
857
857
  virtual_quote_reserves=0,
858
858
  observed_fee_recipient="",
859
859
  ),
sol_parser/rpc_parser.py CHANGED
@@ -71,6 +71,7 @@ class RpcTransactionMeta:
71
71
  post_token_balances: List[RpcTokenBalance]
72
72
  loaded_addresses: Optional[RpcLoadedAddresses]
73
73
  compute_units_consumed: Optional[int]
74
+ err: Optional[Any] = None
74
75
 
75
76
 
76
77
  @dataclass
@@ -200,6 +201,9 @@ def parse_rpc_transaction(
200
201
  if tx.transaction is None or tx.transaction.message is None:
201
202
  return [], ParseError("ConversionError", "Transaction message is nil")
202
203
 
204
+ if tx.meta is not None and tx.meta.err is not None:
205
+ return [], None # All events from a failed transaction describe rolled-back work.
206
+
203
207
  msg = tx.transaction.message
204
208
  meta = tx.meta
205
209
  if meta is None:
@@ -429,6 +433,10 @@ def convert_rpc_to_grpc(
429
433
  log_messages=meta.log_messages,
430
434
  )
431
435
 
436
+ if meta.err is not None:
437
+ # Preserve failure presence without fabricating a Yellowstone binary error enum.
438
+ grpc_meta.err.SetInParent()
439
+
432
440
  # 转换内部指令
433
441
  for group in meta.inner_instructions:
434
442
  grpc_group = grpc_meta.inner_instructions.add()
@@ -676,6 +684,7 @@ def rpc_get_transaction_result_dict_to_response(
676
684
  post_token_balances=[],
677
685
  loaded_addresses=loaded,
678
686
  compute_units_consumed=meta_dict.get("computeUnitsConsumed"),
687
+ err=meta_dict.get("err"),
679
688
  )
680
689
 
681
690
  return RpcTransactionResponse(
@@ -743,6 +752,8 @@ def rpc_response_to_solana_storage(
743
752
  ii.data = ix.data
744
753
  if ix.stack_height is not None:
745
754
  ii.stack_height = ix.stack_height
755
+ if m.err is not None:
756
+ meta.err.SetInParent()
746
757
  if m.loaded_addresses:
747
758
  for w in m.loaded_addresses.writable:
748
759
  meta.loaded_writable_addresses.append(base58.b58decode(w))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: sol-parser-sdk-python
3
- Version: 0.5.9
3
+ Version: 0.5.10
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
@@ -76,6 +76,13 @@ This is the Python implementation of the FnZero Solana DEX parser SDK for asynci
76
76
 
77
77
  ## Release notes
78
78
 
79
+ ### v0.5.10
80
+
81
+ - Matches PumpFun create/create_v2 accounts by the actual instruction discriminator and event mint, including CPI calls; ambiguous matches are left unspecified.
82
+ - Stops inferring quote mint/vault/token-program fields from arbitrary remaining create_v2 accounts and preserves authoritative decoded fields.
83
+ - Restores historical CreateEvent decoding and verifies successful and failed transactions using saved mainnet fixtures.
84
+ - Suppresses rolled-back DEX events from failed transactions and preserves failure status through RPC/gRPC adapters.
85
+
79
86
  ### v0.5.9
80
87
 
81
88
  - Adds native gRPC lifecycle and block metadata support, instruction-level route analysis and StonkFun registry/snapshot examples.
@@ -117,7 +124,7 @@ This is the Python implementation of the FnZero Solana DEX parser SDK for asynci
117
124
  **From PyPI**
118
125
 
119
126
  ```bash
120
- pip install sol-parser-sdk-python==0.5.9
127
+ pip install sol-parser-sdk-python==0.5.10
121
128
  ```
122
129
 
123
130
  **From source**
@@ -1,21 +1,21 @@
1
1
  sol_parser/__init__.py,sha256=lDz0LDrZcvY0DCFvD7RApYzXmveUHIN04iZWUBw2Z14,16164
2
- sol_parser/account_dispatcher.py,sha256=6Nvmrx6-DsM3_aHpkCboBol37ndv36iY4aRFkD4bwys,13949
2
+ sol_parser/account_dispatcher.py,sha256=8IlDSFvr9pcr2MaFWlSvA1sL3TdR4PPiY56OFCnQmyg,15119
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
5
5
  sol_parser/clock.py,sha256=RHF99qMerKvEsT55krkftIh-uqy_uTzpgdKCqKBMDmA,278
6
- sol_parser/dex_parsers.py,sha256=yDbTfocXLaeFkuxLL6BVOzBOEDeXym2z7sv_iPO4bV4,135325
6
+ sol_parser/dex_parsers.py,sha256=uuBfhjqacAL-BMpsfaWyG9rls9CRK9kR5LvsYoystLw,135597
7
7
  sol_parser/entries_decode.py,sha256=MOhGadNxWLerxBhGvuNatoWa2hzw2MXVz9NmNUhWvS8,3665
8
8
  sol_parser/env_config.py,sha256=Lw0SdZuy_MvUaVkyFxS0qPBgMzR9UBbxbN0CVz8nxg4,7296
9
9
  sol_parser/event_type_parity.py,sha256=L_oxbUtCTQ9JLGyRiLXNhDTp0UUOcEbe_IPrisgdMBY,4206
10
- sol_parser/event_types.py,sha256=2dqkDLD_CjsAjD_mJbFluzdVUZNJz9CHtpGJJRMuGb4,88488
10
+ sol_parser/event_types.py,sha256=0aJ27cdrKa9aEVfOLjGkMmjOhwfon4N1BJaKJIxorhc,88953
11
11
  sol_parser/geyser_pb2.py,sha256=Hq66wmWxXD2jSbSVQW7vmBRB7nWmR1DuYDMQ6nKgl3o,20123
12
12
  sol_parser/geyser_pb2_grpc.py,sha256=ASPmZsCNvyCzt_j4IrhKjSacWUNLVuAiLfpjmyd-2Qc,15322
13
- sol_parser/grpc_client.py,sha256=1T0HzQ69oNZULNzYrvpumzu_Fxwspbzl1C59npdkcFo,37064
14
- sol_parser/grpc_instruction_parser.py,sha256=p_9BnhC5FHHIXLKPKEM2_infbMC7apr4CQEhMxfkKz4,13450
13
+ sol_parser/grpc_client.py,sha256=jnHvOZ26A3qiFKFOKS_2OqnA8J_-5_f1WAMMTAy3B3A,37237
14
+ sol_parser/grpc_instruction_parser.py,sha256=X7cs3PoAi3cAa_qSrK8jr9fYhr-m-5CecfDR3QVpN7s,13852
15
15
  sol_parser/grpc_types.py,sha256=3Huz33j6igVBQJbBcwurJtB8rhCUtYfvbiFgKmGeuJs,39316
16
16
  sol_parser/inner_instruction_parser.py,sha256=Mynr-pzSFG3AuRUl9wu2_G-wzDJZp_GcorGslP88f0s,20831
17
17
  sol_parser/instr_account_utils.py,sha256=MY8bgoIDiv2yJKeWxqhpfKc3pV4xUFTcYKnSXtnQMWc,1990
18
- sol_parser/instructions.py,sha256=3fcZZNCmsB31asi7Qhm2aEYzn-jU4jrfs95ynitINus,81496
18
+ sol_parser/instructions.py,sha256=tscdgJKGFljp1ELo9JtLX9FFzezfWL1lmAOtpzSn7L8,81401
19
19
  sol_parser/json_util.py,sha256=y7uCaOwmtkJtvCHx3R8ff5YxwAhTvWBTZ-duFtNRNLc,2274
20
20
  sol_parser/liquidity_snapshot.py,sha256=kk5vC3oaOZeVoU1q4wquxRbCOWorq-fSMrNVe6BdxwU,3621
21
21
  sol_parser/log_instr_dedup.py,sha256=AWF3EMaEXI5V_bwjyF24uH_ozWTijRvd0zf7lGBXTMk,14559
@@ -24,7 +24,7 @@ sol_parser/merger.py,sha256=NGjqSzTNDvDDlIH-8DV2Mk_Z5xJ3ItlnUiAGOAK6kPU,12362
24
24
  sol_parser/order_buffer.py,sha256=xW-Okii8a9t9tCqbBKtxFh1moTEi7RqycMFO2kwp-d4,6447
25
25
  sol_parser/parser.py,sha256=jd-NkWXso7Rcp8TJiBFvjTmNO468tb7rsEElQkU-EV0,11286
26
26
  sol_parser/pumpfun_fee_enrich.py,sha256=NHC_chCv2wuaOW5taYG8R6M1bu8cmdxcLf8cjSfo7Kc,4688
27
- sol_parser/rpc_parser.py,sha256=iWTl_OtNOEpoOmvVEPVmum5QDdGyjSiX6r_3Hx4LOTg,25361
27
+ sol_parser/rpc_parser.py,sha256=AkepkLyxyjAMCBmZe1YZ1Wy8ZCF8ljAFrEMbBIto-xw,25789
28
28
  sol_parser/rust_api_inventory.py,sha256=V5Bx1M3GT-ku_vj_kD6lnbqWExv1K_A00PrmhCFfRec,2257
29
29
  sol_parser/rust_event_json.py,sha256=7hho9TGfSOQjHev_8uRa4YHU1hrEsW1RfwcU9qHYz1o,1649
30
30
  sol_parser/shredstream_client.py,sha256=xBE6KE9kyTXkXO82iEi99dQCSHq-dIIkFF7u8NHBWHE,9967
@@ -42,7 +42,7 @@ sol_parser/wire_transaction.py,sha256=3r73JQz7XwCVc9gRuyLm6J3LZHdOXuVYizHum25m7G
42
42
  sol_parser/account_fillers/__init__.py,sha256=q4q7HZF0Z4-rxhKoRMzV52HSkJ_n_POm4vimYUQlCOA,235
43
43
  sol_parser/account_fillers/meteora.py,sha256=ecY3F4KkjnVxBc-Zsnzru52DggkYOdbeauaYrznDxFY,2111
44
44
  sol_parser/account_fillers/orca.py,sha256=2s-hfi20fa5sy6p1rGc7_7NxzkpaleJdqn3YD41aBAw,895
45
- sol_parser/account_fillers/pumpfun.py,sha256=hZgvqquXRDAR1Vny7y69YX7BZyo0tWiqZlnJLu1Zlxs,5969
45
+ sol_parser/account_fillers/pumpfun.py,sha256=YItZYiBjWxmahZ7vJVwsQndSYFxaxSAozN7Mpr7I2Gw,5814
46
46
  sol_parser/account_fillers/pumpswap.py,sha256=1_JBmwFGMr_tAMZpYQsPnUJDoQlGvCpwB90iZzWHLzM,4042
47
47
  sol_parser/account_fillers/raydium.py,sha256=wjRh95JFcq7JZeDBoRNQU3Wr_wby-rUjKsU3ZiWEPLQ,3831
48
48
  sol_parser/account_fillers/raydium_launchlab.py,sha256=X_Og_V54EG9Y7wHwUBEKsAa_JWmtcHsakpL_-P3QB-c,2680
@@ -57,7 +57,7 @@ sol_parser/grpc/subscribe_builder.py,sha256=xH9NZ1Lp-7AQKcgxoqyE0PrB3vdOqnScm_Ht
57
57
  sol_parser/grpc/transaction_meta.py,sha256=NmIffIQ1_OIfWGjy6JY-f8pIK5ucjDZXXJryjnlgoQs,5894
58
58
  sol_parser/instr/__init__.py,sha256=0_Ky8KpVEoXzxszHcHLTuY2SDsJwu0uAF2Q0wMY1e-c,503
59
59
  sol_parser/logs/__init__.py,sha256=e1cbhbCNeXy-NZvVsYCpGksBpZf4NJBLmdlky06og-U,349
60
- sol_parser_sdk_python-0.5.9.dist-info/METADATA,sha256=m_d8LaVv3tOUeacirJcH2yB7PdfYyu8SOuUFvXNtYTo,15431
61
- sol_parser_sdk_python-0.5.9.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
62
- sol_parser_sdk_python-0.5.9.dist-info/entry_points.txt,sha256=ZGXRb-2jBdc56d8PCAZFiJBLTAzUKFeHPohysJnKVbA,206
63
- sol_parser_sdk_python-0.5.9.dist-info/RECORD,,
60
+ sol_parser_sdk_python-0.5.10.dist-info/METADATA,sha256=_FEDfmqpjzo_KpjhSjz3e5QVD1KYKcA8HuAQ6EHSAxY,15990
61
+ sol_parser_sdk_python-0.5.10.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
62
+ sol_parser_sdk_python-0.5.10.dist-info/entry_points.txt,sha256=ZGXRb-2jBdc56d8PCAZFiJBLTAzUKFeHPohysJnKVbA,206
63
+ sol_parser_sdk_python-0.5.10.dist-info/RECORD,,