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.
@@ -75,6 +75,10 @@ RUST_EVENT_TYPES = [
75
75
  "MeteoraDammV2InitializePool",
76
76
  "MeteoraDammV2CreatePosition",
77
77
  "MeteoraDammV2ClosePosition",
78
+ "MeteoraDammV2UpdateDelegatePermission",
79
+ "MeteoraDammV2WithdrawDeadLiquidityReward",
80
+ "MeteoraDammV2CreateConfig",
81
+ "MeteoraDammV2CreateDynamicConfig",
78
82
  "MeteoraDbcSwap",
79
83
  "MeteoraDbcInitializePool",
80
84
  "MeteoraDbcCurveComplete",
sol_parser/event_types.py CHANGED
@@ -153,6 +153,8 @@ class PumpFunTradeEvent(DexEventBase):
153
153
  quote_amount: int = 0
154
154
  virtual_quote_reserves: int = 0
155
155
  real_quote_reserves: int = 0
156
+ holder_rewards_bps: int = 0
157
+ holder_rewards: int = 0
156
158
  is_cashback_coin: bool = False
157
159
  amount: int = 0
158
160
  max_sol_cost: int = 0
@@ -160,6 +162,11 @@ class PumpFunTradeEvent(DexEventBase):
160
162
  spendable_sol_in: int = 0
161
163
  spendable_quote_in: int = 0
162
164
  min_tokens_out: int = 0
165
+ # Transaction balance fields (raw units; None when meta unavailable)
166
+ pre_token_balance: Optional[int] = None
167
+ post_token_balance: Optional[int] = None
168
+ pre_sol_balance: Optional[int] = None
169
+ post_sol_balance: Optional[int] = None
163
170
  global_account: str = ""
164
171
  bonding_curve: str = ""
165
172
  bonding_curve_v2: str = ""
@@ -210,6 +217,8 @@ class PumpFunCreateEvent(DexEventBase):
210
217
  quote_vault: str = ""
211
218
  quote_token_program: str = ""
212
219
  virtual_quote_reserves: int = 0
220
+ creator_fee_bps: int = 0
221
+ is_holder_reward: bool = False
213
222
 
214
223
 
215
224
  @dataclass
@@ -238,6 +247,8 @@ class PumpFunCreateV2TokenEvent(DexEventBase):
238
247
  quote_vault: str = ""
239
248
  quote_token_program: str = ""
240
249
  virtual_quote_reserves: int = 0
250
+ creator_fee_bps: int = 0
251
+ is_holder_reward: bool = False
241
252
  mint_authority: str = ""
242
253
  associated_bonding_curve: str = ""
243
254
  global_account: str = "" # Rust `global` PumpFun global config
@@ -418,6 +429,13 @@ class PumpSwapBuyEvent(DexEventBase):
418
429
  mayhem_mode: bool = False
419
430
  cashback_fee_basis_points: int = 0
420
431
  cashback: int = 0
432
+ buyback_fee_basis_points: int = 0
433
+ buyback_fee: int = 0
434
+ virtual_quote_reserves: int = 0
435
+ can_boost: bool = False
436
+ base_supply: int = 0
437
+ holder_rewards_bps: int = 0
438
+ holder_rewards: int = 0
421
439
  is_cashback_coin: bool = False
422
440
  base_mint: str = ""
423
441
  quote_mint: str = ""
@@ -461,6 +479,13 @@ class PumpSwapSellEvent(DexEventBase):
461
479
  coin_creator_fee: int = 0
462
480
  cashback_fee_basis_points: int = 0
463
481
  cashback: int = 0
482
+ buyback_fee_basis_points: int = 0
483
+ buyback_fee: int = 0
484
+ virtual_quote_reserves: int = 0
485
+ can_boost: bool = False
486
+ base_supply: int = 0
487
+ holder_rewards_bps: int = 0
488
+ holder_rewards: int = 0
464
489
  base_mint: str = ""
465
490
  quote_mint: str = ""
466
491
  pool_base_token_account: str = ""
@@ -499,6 +524,10 @@ class PumpSwapCreatePoolEvent(DexEventBase):
499
524
  user_quote_token_account: str = ""
500
525
  coin_creator: str = ""
501
526
  is_mayhem_mode: bool = False
527
+ is_cashback_coin: bool = False
528
+ creator_fee_bps: int = 0
529
+ can_edit_creator_fee: bool = False
530
+ is_holder_reward: bool = False
502
531
 
503
532
 
504
533
  @dataclass
@@ -997,6 +1026,12 @@ class OrcaWhirlpoolPoolInitializedEvent(DexEventBase):
997
1026
  @dataclass
998
1027
  class MeteoraDlmmSwapEvent(DexEventBase):
999
1028
  """Meteora DLMM 交换事件"""
1029
+ # Instruction / account context (not in Borsh event payload)
1030
+ token_x_mint: str = ""
1031
+ token_y_mint: str = ""
1032
+ user_token_in: str = ""
1033
+ user_token_out: str = ""
1034
+ min_amount_out: int = 0
1000
1035
  pool: str = ""
1001
1036
  from_addr: str = ""
1002
1037
  start_bin_id: int = 0
@@ -1141,10 +1176,14 @@ class MeteoraPoolsPoolCreatedEvent(DexEventBase):
1141
1176
 
1142
1177
  @dataclass
1143
1178
  class MeteoraDammV2SwapEvent(DexEventBase):
1144
- """Meteora DAMM v2 交换事件"""
1179
+ """Meteora DAMM v2 交换事件(含 EvtSwap / EvtSwap2 全字段)"""
1145
1180
  pool: str = ""
1146
1181
  trade_direction: int = 0
1182
+ collect_fee_mode: int = 0
1147
1183
  has_referral: bool = False
1184
+ amount_0: int = 0
1185
+ amount_1: int = 0
1186
+ swap_mode: int = 0
1148
1187
  amount_in: int = 0
1149
1188
  minimum_amount_out: int = 0
1150
1189
  output_amount: int = 0
@@ -1154,7 +1193,16 @@ class MeteoraDammV2SwapEvent(DexEventBase):
1154
1193
  partner_fee: int = 0
1155
1194
  referral_fee: int = 0
1156
1195
  actual_amount_in: int = 0
1196
+ excluded_fee_input_amount: int = 0
1197
+ amount_left: int = 0
1198
+ claiming_fee: int = 0
1199
+ compounding_fee: int = 0
1200
+ included_transfer_fee_amount_in: int = 0
1201
+ included_transfer_fee_amount_out: int = 0
1202
+ excluded_transfer_fee_amount_out: int = 0
1157
1203
  current_timestamp: int = 0
1204
+ reserve_a_amount: int = 0
1205
+ reserve_b_amount: int = 0
1158
1206
  token_a_vault: str = ""
1159
1207
  token_b_vault: str = ""
1160
1208
  token_a_mint: str = ""
@@ -1194,6 +1242,8 @@ class MeteoraDammV2AddLiquidityEvent(DexEventBase):
1194
1242
  token_b_amount: int = 0
1195
1243
  total_amount_a: int = 0
1196
1244
  total_amount_b: int = 0
1245
+ reserve_a_amount: int = 0
1246
+ reserve_b_amount: int = 0
1197
1247
 
1198
1248
 
1199
1249
  @dataclass
@@ -1207,6 +1257,10 @@ class MeteoraDammV2RemoveLiquidityEvent(DexEventBase):
1207
1257
  token_b_amount_threshold: int = 0
1208
1258
  token_a_amount: int = 0
1209
1259
  token_b_amount: int = 0
1260
+ total_amount_a: int = 0
1261
+ total_amount_b: int = 0
1262
+ reserve_a_amount: int = 0
1263
+ reserve_b_amount: int = 0
1210
1264
 
1211
1265
 
1212
1266
  @dataclass
@@ -1237,6 +1291,62 @@ class MeteoraDammV2InitializePoolEvent(DexEventBase):
1237
1291
  pool_type: int = 0
1238
1292
 
1239
1293
 
1294
+ @dataclass
1295
+ class MeteoraDammV2DynamicFeeParameters:
1296
+ """DAMM v2 PoolFeeParameters.dynamic_fee"""
1297
+ bin_step: int = 0
1298
+ bin_step_u128: str = "0"
1299
+ filter_period: int = 0
1300
+ decay_period: int = 0
1301
+ reduction_factor: int = 0
1302
+ max_volatility_accumulator: int = 0
1303
+ variable_fee_control: int = 0
1304
+
1305
+
1306
+ @dataclass
1307
+ class MeteoraDammV2UpdateDelegatePermissionEvent(DexEventBase):
1308
+ """Meteora DAMM v2 EvtUpdateDelegatePermission"""
1309
+ position: str = ""
1310
+ owner: str = ""
1311
+ permission: int = 0
1312
+ delegate: Optional[str] = None
1313
+
1314
+
1315
+ @dataclass
1316
+ class MeteoraDammV2WithdrawDeadLiquidityRewardEvent(DexEventBase):
1317
+ """Meteora DAMM v2 EvtWithdrawDeadLiquidityReward"""
1318
+ pool: str = ""
1319
+ reward_mint: str = ""
1320
+ amount: int = 0
1321
+
1322
+
1323
+ @dataclass
1324
+ class MeteoraDammV2CreateConfigEvent(DexEventBase):
1325
+ """Meteora DAMM v2 EvtCreateConfig(含 0.2.4 permission)"""
1326
+ base_fee_data: bytes = field(default_factory=lambda: bytes(27))
1327
+ compounding_fee_bps: int = 0
1328
+ padding: int = 0
1329
+ dynamic_fee: Optional[MeteoraDammV2DynamicFeeParameters] = None
1330
+ vault_config_key: str = ""
1331
+ pool_creator_authority: str = ""
1332
+ activation_type: int = 0
1333
+ sqrt_min_price: str = "0"
1334
+ sqrt_max_price: str = "0"
1335
+ collect_fee_mode: int = 0
1336
+ index: int = 0
1337
+ config: str = ""
1338
+ permission: str = "0"
1339
+
1340
+
1341
+ @dataclass
1342
+ class MeteoraDammV2CreateDynamicConfigEvent(DexEventBase):
1343
+ """Meteora DAMM v2 EvtCreateDynamicConfig"""
1344
+ config: str = ""
1345
+ pool_creator_authority: str = ""
1346
+ index: int = 0
1347
+ permission: str = "0"
1348
+
1349
+
1240
1350
  @dataclass
1241
1351
  class MeteoraDbcSwapEvent(DexEventBase):
1242
1352
  """Meteora DBC 交易事件"""
@@ -1289,6 +1399,16 @@ class RaydiumLaunchlabTradeEvent(DexEventBase):
1289
1399
  is_buy: bool = False
1290
1400
  trade_direction: str = ""
1291
1401
  exact_in: bool = False
1402
+ global_config: str = ""
1403
+ platform_config: str = ""
1404
+ user_base_token: str = ""
1405
+ user_quote_token: str = ""
1406
+ base_vault: str = ""
1407
+ quote_vault: str = ""
1408
+ base_mint: str = ""
1409
+ quote_mint: str = ""
1410
+ base_token_program: str = ""
1411
+ quote_token_program: str = ""
1292
1412
 
1293
1413
 
1294
1414
  @dataclass
@@ -1297,6 +1417,15 @@ class RaydiumLaunchlabPoolCreateEvent(DexEventBase):
1297
1417
  pool_state: str = ""
1298
1418
  creator: str = ""
1299
1419
  base_mint_param: Optional[Dict[str, Any]] = None
1420
+ payer: str = ""
1421
+ global_config: str = ""
1422
+ platform_config: str = ""
1423
+ base_mint: str = ""
1424
+ quote_mint: str = ""
1425
+ base_vault: str = ""
1426
+ quote_vault: str = ""
1427
+ base_token_program: str = ""
1428
+ quote_token_program: str = ""
1300
1429
 
1301
1430
 
1302
1431
  @dataclass
@@ -1373,6 +1502,10 @@ TypedDexEvent = Union[
1373
1502
  MeteoraDammV2AddLiquidityEvent,
1374
1503
  MeteoraDammV2RemoveLiquidityEvent,
1375
1504
  MeteoraDammV2InitializePoolEvent,
1505
+ MeteoraDammV2UpdateDelegatePermissionEvent,
1506
+ MeteoraDammV2WithdrawDeadLiquidityRewardEvent,
1507
+ MeteoraDammV2CreateConfigEvent,
1508
+ MeteoraDammV2CreateDynamicConfigEvent,
1376
1509
  RaydiumLaunchlabTradeEvent,
1377
1510
  RaydiumLaunchlabPoolCreateEvent,
1378
1511
  RaydiumLaunchlabMigrateAmmEvent,
@@ -1409,11 +1542,20 @@ def _get_int(m: dict, key: str) -> int:
1409
1542
  v = m.get(key, 0)
1410
1543
  if isinstance(v, int):
1411
1544
  return v
1412
- if isinstance(v, str) and v.isdigit():
1413
- return int(v)
1545
+ if isinstance(v, str):
1546
+ try:
1547
+ return int(v, 10)
1548
+ except ValueError:
1549
+ pass
1414
1550
  return 0
1415
1551
 
1416
1552
 
1553
+ def _get_optional_int(m: dict, key: str) -> Optional[int]:
1554
+ if key not in m or m.get(key) is None:
1555
+ return None
1556
+ return _get_int(m, key)
1557
+
1558
+
1417
1559
  def _get_bool(m: dict, key: str) -> bool:
1418
1560
  v = m.get(key, False)
1419
1561
  return bool(v)
@@ -1517,6 +1659,8 @@ def to_typed_event(event: dict) -> Optional[TypedDexEvent]:
1517
1659
  quote_amount=_get_int(data, "quote_amount"),
1518
1660
  virtual_quote_reserves=_get_int(data, "virtual_quote_reserves"),
1519
1661
  real_quote_reserves=_get_int(data, "real_quote_reserves"),
1662
+ holder_rewards_bps=_get_int(data, "holder_rewards_bps"),
1663
+ holder_rewards=_get_int(data, "holder_rewards"),
1520
1664
  is_cashback_coin=_get_bool(data, "is_cashback_coin"),
1521
1665
  amount=_get_int(data, "amount"),
1522
1666
  max_sol_cost=_get_int(data, "max_sol_cost"),
@@ -1524,6 +1668,10 @@ def to_typed_event(event: dict) -> Optional[TypedDexEvent]:
1524
1668
  spendable_sol_in=_get_int(data, "spendable_sol_in"),
1525
1669
  spendable_quote_in=_get_int(data, "spendable_quote_in"),
1526
1670
  min_tokens_out=_get_int(data, "min_tokens_out"),
1671
+ pre_token_balance=_get_optional_int(data, "pre_token_balance"),
1672
+ post_token_balance=_get_optional_int(data, "post_token_balance"),
1673
+ pre_sol_balance=_get_optional_int(data, "pre_sol_balance"),
1674
+ post_sol_balance=_get_optional_int(data, "post_sol_balance"),
1527
1675
  global_account=_get_str(data, "global") or _get_str(data, "global_account"),
1528
1676
  bonding_curve=_get_str(data, "bonding_curve"),
1529
1677
  bonding_curve_v2=_get_str(data, "bonding_curve_v2"),
@@ -1573,6 +1721,8 @@ def to_typed_event(event: dict) -> Optional[TypedDexEvent]:
1573
1721
  quote_vault=_get_str(data, "quote_vault"),
1574
1722
  quote_token_program=_get_str(data, "quote_token_program"),
1575
1723
  virtual_quote_reserves=_get_int(data, "virtual_quote_reserves"),
1724
+ creator_fee_bps=_get_int(data, "creator_fee_bps"),
1725
+ is_holder_reward=_get_bool(data, "is_holder_reward"),
1576
1726
  )
1577
1727
 
1578
1728
  if event_type == EventType.PUMP_FUN_CREATE_V2:
@@ -1598,6 +1748,8 @@ def to_typed_event(event: dict) -> Optional[TypedDexEvent]:
1598
1748
  quote_vault=_get_str(data, "quote_vault"),
1599
1749
  quote_token_program=_get_str(data, "quote_token_program"),
1600
1750
  virtual_quote_reserves=_get_int(data, "virtual_quote_reserves"),
1751
+ creator_fee_bps=_get_int(data, "creator_fee_bps"),
1752
+ is_holder_reward=_get_bool(data, "is_holder_reward"),
1601
1753
  mint_authority=_get_str(data, "mint_authority"),
1602
1754
  associated_bonding_curve=_get_str(data, "associated_bonding_curve"),
1603
1755
  global_account=g,
@@ -1663,6 +1815,13 @@ def to_typed_event(event: dict) -> Optional[TypedDexEvent]:
1663
1815
  mayhem_mode=_get_bool(data, "mayhem_mode"),
1664
1816
  cashback_fee_basis_points=_get_int(data, "cashback_fee_basis_points"),
1665
1817
  cashback=_get_int(data, "cashback"),
1818
+ buyback_fee_basis_points=_get_int(data, "buyback_fee_basis_points"),
1819
+ buyback_fee=_get_int(data, "buyback_fee"),
1820
+ virtual_quote_reserves=_get_int(data, "virtual_quote_reserves"),
1821
+ can_boost=_get_bool(data, "can_boost"),
1822
+ base_supply=_get_int(data, "base_supply"),
1823
+ holder_rewards_bps=_get_int(data, "holder_rewards_bps"),
1824
+ holder_rewards=_get_int(data, "holder_rewards"),
1666
1825
  is_cashback_coin=_get_bool(data, "is_cashback_coin"),
1667
1826
  is_pump_pool=_get_bool(data, "is_pump_pool"),
1668
1827
  base_mint=_get_str(data, "base_mint"),
@@ -1706,6 +1865,13 @@ def to_typed_event(event: dict) -> Optional[TypedDexEvent]:
1706
1865
  coin_creator_fee=_get_int(data, "coin_creator_fee"),
1707
1866
  cashback_fee_basis_points=_get_int(data, "cashback_fee_basis_points"),
1708
1867
  cashback=_get_int(data, "cashback"),
1868
+ buyback_fee_basis_points=_get_int(data, "buyback_fee_basis_points"),
1869
+ buyback_fee=_get_int(data, "buyback_fee"),
1870
+ virtual_quote_reserves=_get_int(data, "virtual_quote_reserves"),
1871
+ can_boost=_get_bool(data, "can_boost"),
1872
+ base_supply=_get_int(data, "base_supply"),
1873
+ holder_rewards_bps=_get_int(data, "holder_rewards_bps"),
1874
+ holder_rewards=_get_int(data, "holder_rewards"),
1709
1875
  is_pump_pool=_get_bool(data, "is_pump_pool"),
1710
1876
  base_mint=_get_str(data, "base_mint"),
1711
1877
  quote_mint=_get_str(data, "quote_mint"),
@@ -1744,6 +1910,10 @@ def to_typed_event(event: dict) -> Optional[TypedDexEvent]:
1744
1910
  user_quote_token_account=_get_str(data, "user_quote_token_account"),
1745
1911
  coin_creator=_get_str(data, "coin_creator"),
1746
1912
  is_mayhem_mode=_get_bool(data, "is_mayhem_mode"),
1913
+ is_cashback_coin=_get_bool(data, "is_cashback_coin"),
1914
+ creator_fee_bps=_get_int(data, "creator_fee_bps"),
1915
+ can_edit_creator_fee=_get_bool(data, "can_edit_creator_fee"),
1916
+ is_holder_reward=_get_bool(data, "is_holder_reward"),
1747
1917
  )
1748
1918
 
1749
1919
  if event_type == EventType.PUMP_SWAP_LIQUIDITY_ADDED:
@@ -1801,6 +1971,35 @@ def to_typed_event(event: dict) -> Optional[TypedDexEvent]:
1801
1971
  return MeteoraDammV2ClosePositionEvent(metadata=meta, pool=_get_str(data, "pool"))
1802
1972
  if event_type == EventType.METEORA_DAMM_V2_INITIALIZE_POOL:
1803
1973
  return MeteoraDammV2InitializePoolEvent(metadata=meta, pool=_get_str(data, "pool"))
1974
+ if event_type == EventType.METEORA_DAMM_V2_UPDATE_DELEGATE_PERMISSION:
1975
+ return MeteoraDammV2UpdateDelegatePermissionEvent(
1976
+ metadata=meta,
1977
+ position=_get_str(data, "position"),
1978
+ owner=_get_str(data, "owner"),
1979
+ permission=_get_int(data, "permission"),
1980
+ delegate=data.get("delegate"),
1981
+ )
1982
+ if event_type == EventType.METEORA_DAMM_V2_WITHDRAW_DEAD_LIQUIDITY_REWARD:
1983
+ return MeteoraDammV2WithdrawDeadLiquidityRewardEvent(
1984
+ metadata=meta,
1985
+ pool=_get_str(data, "pool"),
1986
+ reward_mint=_get_str(data, "reward_mint"),
1987
+ amount=_get_int(data, "amount"),
1988
+ )
1989
+ if event_type == EventType.METEORA_DAMM_V2_CREATE_CONFIG:
1990
+ return MeteoraDammV2CreateConfigEvent(
1991
+ metadata=meta,
1992
+ config=_get_str(data, "config"),
1993
+ permission=str(data.get("permission", "0")),
1994
+ )
1995
+ if event_type == EventType.METEORA_DAMM_V2_CREATE_DYNAMIC_CONFIG:
1996
+ return MeteoraDammV2CreateDynamicConfigEvent(
1997
+ metadata=meta,
1998
+ config=_get_str(data, "config"),
1999
+ pool_creator_authority=_get_str(data, "pool_creator_authority"),
2000
+ index=_get_int(data, "index"),
2001
+ permission=str(data.get("permission", "0")),
2002
+ )
1804
2003
 
1805
2004
  if event_type == EventType.RAYDIUM_CLMM_SWAP:
1806
2005
  return RaydiumClmmSwapEvent(
@@ -2124,6 +2323,16 @@ def to_typed_event(event: dict) -> Optional[TypedDexEvent]:
2124
2323
  is_buy=_get_bool(data, "is_buy"),
2125
2324
  trade_direction=_get_str(data, "trade_direction"),
2126
2325
  exact_in=_get_bool(data, "exact_in"),
2326
+ global_config=_get_str(data, "global_config"),
2327
+ platform_config=_get_str(data, "platform_config"),
2328
+ user_base_token=_get_str(data, "user_base_token"),
2329
+ user_quote_token=_get_str(data, "user_quote_token"),
2330
+ base_vault=_get_str(data, "base_vault"),
2331
+ quote_vault=_get_str(data, "quote_vault"),
2332
+ base_mint=_get_str(data, "base_mint"),
2333
+ quote_mint=_get_str(data, "quote_mint"),
2334
+ base_token_program=_get_str(data, "base_token_program"),
2335
+ quote_token_program=_get_str(data, "quote_token_program"),
2127
2336
  )
2128
2337
 
2129
2338
  if event_type == EventType.RAYDIUM_LAUNCHLAB_POOL_CREATE:
@@ -2132,6 +2341,15 @@ def to_typed_event(event: dict) -> Optional[TypedDexEvent]:
2132
2341
  pool_state=_get_str(data, "pool_state"),
2133
2342
  creator=_get_str(data, "creator"),
2134
2343
  base_mint_param=_get_dict_any(data, "base_mint_param"),
2344
+ payer=_get_str(data, "payer"),
2345
+ global_config=_get_str(data, "global_config"),
2346
+ platform_config=_get_str(data, "platform_config"),
2347
+ base_mint=_get_str(data, "base_mint"),
2348
+ quote_mint=_get_str(data, "quote_mint"),
2349
+ base_vault=_get_str(data, "base_vault"),
2350
+ quote_vault=_get_str(data, "quote_vault"),
2351
+ base_token_program=_get_str(data, "base_token_program"),
2352
+ quote_token_program=_get_str(data, "quote_token_program"),
2135
2353
  )
2136
2354
 
2137
2355
  if event_type == EventType.RAYDIUM_LAUNCHLAB_MIGRATE_AMM:
@@ -7,17 +7,18 @@ from typing import Any, Dict, List, Optional, Tuple
7
7
 
8
8
  import base58
9
9
 
10
- from .account_dispatcher import fill_accounts_with_owned_keys, fill_data
10
+ from .account_dispatcher import fill_accounts_with_owned_keys, fill_data, fill_token_balances
11
11
  from .event_types import DexEvent
12
12
  from .grpc_types import (
13
13
  EventMetadata,
14
+ EventType,
14
15
  EventTypeFilter,
15
16
  SubscribeUpdateTransactionInfo,
16
17
  event_type_filter_allows_instruction_parsing,
17
18
  )
18
19
  from .inner_instruction_parser import parse_inner_instruction
19
20
  from .instructions import parse_inner_compiled_instruction_if_supported, parse_instruction_unified
20
- from .merger import merge_dex_events
21
+ from .merger import try_merge_dex_events
21
22
  from .pumpfun_fee_enrich import enrich_pumpfun_same_tx_post_merge
22
23
 
23
24
 
@@ -73,6 +74,7 @@ def apply_account_fill_to_events(
73
74
  for ev in events:
74
75
  fill_accounts_with_owned_keys(ev, meta_pb, tx_pb, invokes_raw)
75
76
  fill_data(ev, meta_pb, tx_pb, invokes_str)
77
+ fill_token_balances(ev, meta_pb, tx_pb)
76
78
  recent_bh = ""
77
79
  if msg.recent_blockhash:
78
80
  recent_bh = base58.b58encode(bytes(msg.recent_blockhash)).decode("ascii")
@@ -124,36 +126,86 @@ def should_parse_instructions(filter: Optional[EventTypeFilter]) -> bool:
124
126
  return event_type_filter_allows_instruction_parsing(list(inc))
125
127
 
126
128
 
127
- def merge_instruction_events(
128
- events: List[Tuple[int, Optional[int], DexEvent]],
129
- ) -> List[DexEvent]:
129
+ _DLMM_EVENT_TYPES = {
130
+ EventType.METEORA_DLMM_SWAP,
131
+ EventType.METEORA_DLMM_ADD_LIQUIDITY,
132
+ EventType.METEORA_DLMM_REMOVE_LIQUIDITY,
133
+ EventType.METEORA_DLMM_INITIALIZE_POOL,
134
+ EventType.METEORA_DLMM_INITIALIZE_BIN_ARRAY,
135
+ EventType.METEORA_DLMM_CREATE_POSITION,
136
+ EventType.METEORA_DLMM_CLOSE_POSITION,
137
+ EventType.METEORA_DLMM_CLAIM_FEE,
138
+ }
139
+
140
+
141
+ def _is_dlmm_event_cpi(data: bytes) -> bool:
142
+ return len(data) >= 16 and (
143
+ data[:8] == bytes((228, 69, 165, 46, 81, 203, 154, 29))
144
+ or data[8:16] == bytes((155, 167, 108, 32, 122, 76, 173, 64))
145
+ )
146
+
147
+
148
+ def merge_instruction_events(events: List[Tuple[Any, ...]]) -> List[DexEvent]:
130
149
  """对齐 Rust ``merge_instruction_events``。"""
131
150
  if not events:
132
151
  return []
133
- events = sorted(events, key=lambda x: (x[0], 0 if x[1] is None else 1 + x[1]))
152
+ normalized = events if all(len(item) == 5 for item in events) else [
153
+ (item[0], item[1], None, False, item[2]) if len(item) == 3 else item
154
+ for item in events
155
+ ]
156
+ normalized.sort(key=lambda x: (x[0], 0 if x[1] is None else 1 + x[1]))
134
157
  result: List[DexEvent] = []
135
- pending_outer: Optional[Tuple[int, DexEvent]] = None
158
+ outer_target: Optional[Tuple[int, int]] = None
159
+ dlmm_targets: List[Tuple[int, Optional[int], int]] = []
136
160
 
137
- for outer_idx, inner_idx, event in events:
161
+ for outer_idx, inner_idx, stack_height, is_dlmm_event_cpi, event in normalized:
138
162
  if inner_idx is None:
139
- if pending_outer is not None:
140
- result.append(pending_outer[1])
141
- pending_outer = (outer_idx, event)
142
- else:
143
- if pending_outer is not None:
144
- po_idx, mut_outer = pending_outer
145
- pending_outer = None
146
- if po_idx == outer_idx:
147
- merge_dex_events(mut_outer, event)
148
- pending_outer = (outer_idx, mut_outer)
149
- else:
150
- result.append(mut_outer)
151
- result.append(event)
163
+ result.append(event)
164
+ target_idx = len(result) - 1
165
+ outer_target = (outer_idx, target_idx)
166
+ dlmm_targets = (
167
+ [(outer_idx, stack_height, target_idx)] if event.type in _DLMM_EVENT_TYPES else []
168
+ )
169
+ continue
170
+
171
+ if is_dlmm_event_cpi:
172
+ for candidate_idx in range(len(dlmm_targets) - 1, -1, -1):
173
+ target_outer, target_height, target_idx = dlmm_targets[candidate_idx]
174
+ direct_child = (
175
+ target_height is None
176
+ or stack_height is None
177
+ or stack_height == target_height + 1
178
+ )
179
+ if target_outer == outer_idx and direct_child:
180
+ del dlmm_targets[candidate_idx + 1:]
181
+ if try_merge_dex_events(result[target_idx], event):
182
+ break
152
183
  else:
153
184
  result.append(event)
185
+ continue
186
+
187
+ target_idx: Optional[int] = None
188
+ if outer_target is not None and outer_target[0] == outer_idx:
189
+ if try_merge_dex_events(result[outer_target[1]], event):
190
+ target_idx = outer_target[1]
191
+ if target_idx is None:
192
+ result.append(event)
193
+ target_idx = len(result) - 1
194
+
195
+ if event.type in _DLMM_EVENT_TYPES:
196
+ if stack_height is None:
197
+ dlmm_targets.clear()
198
+ else:
199
+ while dlmm_targets and (
200
+ dlmm_targets[-1][0] != outer_idx
201
+ or (
202
+ dlmm_targets[-1][1] is not None
203
+ and dlmm_targets[-1][1] >= stack_height
204
+ )
205
+ ):
206
+ dlmm_targets.pop()
207
+ dlmm_targets.append((outer_idx, stack_height, target_idx))
154
208
 
155
- if pending_outer is not None:
156
- result.append(pending_outer[1])
157
209
  return result
158
210
 
159
211
 
@@ -260,7 +312,7 @@ def parse_instructions_enhanced_from_parsed(
260
312
 
261
313
  is_created_buy = detect_pumpfun_create_from_logs(list(meta.log_messages))
262
314
 
263
- result: List[Tuple[int, Optional[int], DexEvent]] = []
315
+ result: List[Tuple[Any, ...]] = []
264
316
 
265
317
  for i, ix in enumerate(msg.instructions):
266
318
  pid_idx = ix.program_id_index
@@ -272,7 +324,7 @@ def parse_instructions_enhanced_from_parsed(
272
324
  data, accounts, signature, slot, tx_index, block_time_us, grpc_us, filter, pid
273
325
  )
274
326
  if ev:
275
- result.append((i, None, ev))
327
+ result.append((i, None, 1, False, ev))
276
328
 
277
329
  for inner in meta.inner_instructions:
278
330
  outer_idx = inner.index
@@ -298,7 +350,13 @@ def parse_instructions_enhanced_from_parsed(
298
350
  is_created_buy,
299
351
  )
300
352
  if ev:
301
- result.append((int(outer_idx), j, ev))
353
+ result.append((
354
+ int(outer_idx),
355
+ j,
356
+ int(inner_ix.stack_height) if inner_ix.HasField("stack_height") else None,
357
+ pid == METEORA_DLMM_PROGRAM_ID and _is_dlmm_event_cpi(data),
358
+ ev,
359
+ ))
302
360
 
303
361
  merged = merge_instruction_events(result)
304
362
  enrich_pumpfun_same_tx_post_merge(merged)
@@ -310,6 +368,7 @@ def parse_instructions_enhanced_from_parsed(
310
368
  for ev in merged:
311
369
  fill_accounts_with_owned_keys(ev, meta, transaction_pb, invokes_raw)
312
370
  fill_data(ev, meta, transaction_pb, invokes_str)
371
+ fill_token_balances(ev, meta, transaction_pb)
313
372
 
314
373
  for ev in merged:
315
374
  if isinstance(ev.data, object) and hasattr(ev.data, "metadata"):
sol_parser/grpc_types.py CHANGED
@@ -115,6 +115,10 @@ class EventType(str, Enum):
115
115
  METEORA_DAMM_V2_INITIALIZE_POOL = "MeteoraDammV2InitializePool"
116
116
  METEORA_DAMM_V2_CREATE_POSITION = "MeteoraDammV2CreatePosition"
117
117
  METEORA_DAMM_V2_CLOSE_POSITION = "MeteoraDammV2ClosePosition"
118
+ METEORA_DAMM_V2_UPDATE_DELEGATE_PERMISSION = "MeteoraDammV2UpdateDelegatePermission"
119
+ METEORA_DAMM_V2_WITHDRAW_DEAD_LIQUIDITY_REWARD = "MeteoraDammV2WithdrawDeadLiquidityReward"
120
+ METEORA_DAMM_V2_CREATE_CONFIG = "MeteoraDammV2CreateConfig"
121
+ METEORA_DAMM_V2_CREATE_DYNAMIC_CONFIG = "MeteoraDammV2CreateDynamicConfig"
118
122
  # Meteora DBC
119
123
  METEORA_DBC_SWAP = "MeteoraDbcSwap"
120
124
  METEORA_DBC_INITIALIZE_POOL = "MeteoraDbcInitializePool"
@@ -206,6 +210,10 @@ METEORA_DAMM_V2_FILTER_TYPES = (
206
210
  EventType.METEORA_DAMM_V2_CLOSE_POSITION,
207
211
  EventType.METEORA_DAMM_V2_INITIALIZE_POOL,
208
212
  EventType.METEORA_DAMM_V2_REMOVE_LIQUIDITY,
213
+ EventType.METEORA_DAMM_V2_UPDATE_DELEGATE_PERMISSION,
214
+ EventType.METEORA_DAMM_V2_WITHDRAW_DEAD_LIQUIDITY_REWARD,
215
+ EventType.METEORA_DAMM_V2_CREATE_CONFIG,
216
+ EventType.METEORA_DAMM_V2_CREATE_DYNAMIC_CONFIG,
209
217
  )
210
218
  METEORA_DBC_FILTER_TYPES = (
211
219
  EventType.METEORA_DBC_SWAP,
@@ -372,6 +380,10 @@ def all_event_types() -> List[EventType]:
372
380
  EventType.METEORA_DAMM_V2_INITIALIZE_POOL,
373
381
  EventType.METEORA_DAMM_V2_CREATE_POSITION,
374
382
  EventType.METEORA_DAMM_V2_CLOSE_POSITION,
383
+ EventType.METEORA_DAMM_V2_UPDATE_DELEGATE_PERMISSION,
384
+ EventType.METEORA_DAMM_V2_WITHDRAW_DEAD_LIQUIDITY_REWARD,
385
+ EventType.METEORA_DAMM_V2_CREATE_CONFIG,
386
+ EventType.METEORA_DAMM_V2_CREATE_DYNAMIC_CONFIG,
375
387
  # Meteora DBC
376
388
  EventType.METEORA_DBC_SWAP,
377
389
  EventType.METEORA_DBC_INITIALIZE_POOL,
@@ -43,7 +43,7 @@ from .dex_parsers import (
43
43
  parse_cpmm_swap_in_from_data,
44
44
  parse_cpmm_swap_out_from_data,
45
45
  parse_cpmm_withdraw_from_data,
46
- parse_dlmm_from_program_data,
46
+ parse_dlmm_event_from_data,
47
47
  parse_meteora_damm_from_buf,
48
48
  parse_meteora_add_from_data,
49
49
  parse_meteora_bootstrap_from_data,
@@ -184,11 +184,6 @@ def _damm_buf_from_inner(disc16: bytes, inner: bytes) -> bytes:
184
184
  _RAYDIUM_LAUNCHLAB_TRADE = bytes([189, 219, 127, 211, 78, 230, 97, 238, 155, 167, 108, 32, 122, 76, 173, 64])
185
185
  _RAYDIUM_LAUNCHLAB_POOL_CREATE = bytes([151, 215, 226, 9, 118, 161, 115, 174, 155, 167, 108, 32, 122, 76, 173, 64])
186
186
 
187
- # DLMM(8 字节 event disc + payload)
188
- def _dlmm_buf_from_inner(disc16: bytes, inner: bytes) -> bytes:
189
- return disc16[:8] + inner
190
-
191
-
192
187
  def _meteora_pools_swap_inner(data: bytes, meta_d: dict) -> Optional[DexEvent]:
193
188
  if len(data) < 16:
194
189
  return None
@@ -440,6 +435,9 @@ def parse_inner_instruction(
440
435
  if program_id_b58 == METEORA_DLMM_PROGRAM_ID:
441
436
  if filter is not None and not event_type_filter_includes_meteora_dlmm(filter):
442
437
  return None
443
- return emit(parse_dlmm_from_program_data(_dlmm_buf_from_inner(disc16, inner), meta_d))
438
+ event_disc = _event_cpi_disc8(disc16)
439
+ if event_disc is None:
440
+ return None
441
+ return emit(parse_dlmm_event_from_data(event_disc, inner, meta_d))
444
442
 
445
443
  return None