sol-parser-sdk-python 0.4.4__py3-none-any.whl → 0.4.5__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.
@@ -22,31 +22,96 @@ AccountGetter = Callable[[int], str]
22
22
 
23
23
 
24
24
  def fill_trade_accounts(e: PumpFunTradeEvent, get: AccountGetter) -> None:
25
- if e.ix_name in ("buy_v2", "sell_v2", "buy_exact_quote_in_v2"):
26
- if _empty(e.user):
27
- e.user = get(13)
28
- if _empty(e.bonding_curve):
29
- e.bonding_curve = get(10)
30
- if _empty(e.associated_bonding_curve):
31
- e.associated_bonding_curve = get(11)
32
- if _empty(e.creator_vault):
33
- e.creator_vault = get(16)
34
- if _empty(e.token_program):
35
- e.token_program = get(3)
25
+ def account_at_matches_mint(idx: int) -> bool:
26
+ return not _empty(e.mint) and get(idx) == e.mint
27
+
28
+ def set_attr(name: str, idx: int) -> None:
29
+ if _empty(getattr(e, name)):
30
+ setattr(e, name, get(idx))
31
+
32
+ is_v2 = e.ix_name in ("buy_v2", "sell_v2", "buy_exact_quote_in_v2") or (
33
+ e.ix_name == "buy_exact_quote_in" and account_at_matches_mint(1)
34
+ )
35
+ if is_v2:
36
+ set_attr("global_account", 0)
37
+ set_attr("quote_mint", 2)
38
+ set_attr("fee_recipient", 6)
39
+ set_attr("bonding_curve", 10)
40
+ set_attr("associated_bonding_curve", 11)
41
+ set_attr("associated_quote_bonding_curve", 12)
42
+ set_attr("user", 13)
43
+ set_attr("associated_user", 14)
44
+ set_attr("associated_quote_user", 15)
45
+ set_attr("token_program", 3)
46
+ set_attr("quote_token_program", 4)
47
+ set_attr("associated_token_program", 5)
48
+ set_attr("creator_vault", 16)
49
+ set_attr("associated_quote_fee_recipient", 7)
50
+ set_attr("buyback_fee_recipient", 8)
51
+ set_attr("associated_quote_buyback_fee_recipient", 9)
52
+ set_attr("associated_creator_vault", 17)
53
+ set_attr("sharing_config", 18)
54
+ if e.ix_name == "sell_v2":
55
+ set_attr("user_volume_accumulator", 19)
56
+ set_attr("associated_user_volume_accumulator", 20)
57
+ set_attr("fee_config", 21)
58
+ set_attr("fee_program", 22)
59
+ set_attr("system_program", 23)
60
+ set_attr("event_authority", 24)
61
+ set_attr("program", 25)
62
+ else:
63
+ set_attr("global_volume_accumulator", 19)
64
+ set_attr("user_volume_accumulator", 20)
65
+ set_attr("associated_user_volume_accumulator", 21)
66
+ set_attr("fee_config", 22)
67
+ set_attr("fee_program", 23)
68
+ set_attr("system_program", 24)
69
+ set_attr("event_authority", 25)
70
+ set_attr("program", 26)
36
71
  return
37
- if _empty(e.user):
38
- e.user = get(6)
39
- if _empty(e.bonding_curve):
40
- e.bonding_curve = get(3)
41
- if _empty(e.associated_bonding_curve):
42
- e.associated_bonding_curve = get(4)
72
+ set_attr("global_account", 0)
73
+ set_attr("fee_recipient", 1)
74
+ set_attr("bonding_curve", 3)
75
+ set_attr("associated_bonding_curve", 4)
76
+ set_attr("associated_user", 5)
77
+ set_attr("user", 6)
78
+ set_attr("system_program", 7)
43
79
  if _empty(e.creator_vault):
44
80
  e.creator_vault = get(9) if e.is_buy else get(8)
45
81
  if _empty(e.token_program):
46
82
  e.token_program = get(8) if e.is_buy else get(9)
83
+ set_attr("event_authority", 10)
84
+ set_attr("program", 11)
85
+ if e.is_buy:
86
+ set_attr("global_volume_accumulator", 12)
87
+ set_attr("user_volume_accumulator", 13)
88
+ set_attr("fee_config", 14)
89
+ set_attr("fee_program", 15)
90
+ set_attr("bonding_curve_v2", 16)
91
+ set_attr("buyback_fee_recipient", 17)
92
+ a17 = get(17)
93
+ if not _empty(a17) and _empty(e.extra_instruction_account):
94
+ e.extra_instruction_account = a17
95
+ return
96
+ set_attr("fee_config", 12)
97
+ set_attr("fee_program", 13)
47
98
  a16 = get(16)
48
99
  if not _empty(a16):
49
- e.extra_instruction_account = a16
100
+ set_attr("user_volume_accumulator", 14)
101
+ set_attr("bonding_curve_v2", 15)
102
+ set_attr("buyback_fee_recipient", 16)
103
+ if _empty(e.extra_instruction_account):
104
+ e.extra_instruction_account = a16
105
+ return
106
+ if e.is_cashback_coin:
107
+ set_attr("user_volume_accumulator", 14)
108
+ set_attr("bonding_curve_v2", 15)
109
+ return
110
+ set_attr("bonding_curve_v2", 14)
111
+ set_attr("buyback_fee_recipient", 15)
112
+ a15 = get(15)
113
+ if not _empty(a15) and _empty(e.extra_instruction_account):
114
+ e.extra_instruction_account = a15
50
115
 
51
116
 
52
117
  def fill_create_accounts(e: PumpFunCreateEvent, get: AccountGetter) -> None:
@@ -58,10 +58,50 @@ def _fill_trade_common(
58
58
 
59
59
  def fill_buy_accounts(e: PumpSwapBuyEvent, get: AccountGetter) -> None:
60
60
  _fill_trade_common(e, get)
61
+ a26 = get(26)
62
+ if not _empty(a26):
63
+ if _empty(e.pool_v2):
64
+ e.pool_v2 = get(24)
65
+ if _empty(e.fee_recipient):
66
+ e.fee_recipient = get(25)
67
+ if _empty(e.fee_recipient_quote_token_account):
68
+ e.fee_recipient_quote_token_account = a26
69
+ return
70
+ a25 = get(25)
71
+ if not _empty(a25):
72
+ if _empty(e.pool_v2):
73
+ e.pool_v2 = get(23)
74
+ if _empty(e.fee_recipient):
75
+ e.fee_recipient = get(24)
76
+ if _empty(e.fee_recipient_quote_token_account):
77
+ e.fee_recipient_quote_token_account = a25
78
+ return
79
+ if _empty(e.pool_v2):
80
+ e.pool_v2 = get(23)
61
81
 
62
82
 
63
83
  def fill_sell_accounts(e: PumpSwapSellEvent, get: AccountGetter) -> None:
64
84
  _fill_trade_common(e, get)
85
+ a25 = get(25)
86
+ if not _empty(a25):
87
+ if _empty(e.pool_v2):
88
+ e.pool_v2 = get(23)
89
+ if _empty(e.fee_recipient):
90
+ e.fee_recipient = get(24)
91
+ if _empty(e.fee_recipient_quote_token_account):
92
+ e.fee_recipient_quote_token_account = a25
93
+ return
94
+ a23 = get(23)
95
+ if not _empty(a23):
96
+ if _empty(e.pool_v2):
97
+ e.pool_v2 = get(21)
98
+ if _empty(e.fee_recipient):
99
+ e.fee_recipient = get(22)
100
+ if _empty(e.fee_recipient_quote_token_account):
101
+ e.fee_recipient_quote_token_account = a23
102
+ return
103
+ if _empty(e.pool_v2):
104
+ e.pool_v2 = get(21)
65
105
 
66
106
 
67
107
  def fill_trade_accounts(_e: Any, _get: AccountGetter) -> None:
@@ -16,9 +16,15 @@ from . import utils as acc_utils
16
16
 
17
17
  # 程序 ID(与 Rust ``accounts/program_ids`` / ``instr/program_ids`` 一致)
18
18
  PUMPFUN_PROGRAM_ID = "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"
19
+ PUMP_FEES_PROGRAM_ID = "pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ"
19
20
  PUMPSWAP_PROGRAM_ID = "pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA"
20
21
 
21
22
  _DISC_PUMPFUN_GLOBAL = bytes([167, 232, 232, 177, 200, 108, 114, 127])
23
+ _DISC_PUMPFUN_BONDING_CURVE = bytes([23, 183, 248, 55, 96, 216, 172, 96])
24
+ _DISC_PUMPFUN_FEE_CONFIG = bytes([143, 52, 146, 187, 219, 123, 76, 155])
25
+ _DISC_PUMPFUN_GLOBAL_VOLUME_ACCUMULATOR = bytes([202, 42, 246, 43, 142, 190, 30, 255])
26
+ _DISC_PUMPFUN_SHARING_CONFIG = bytes([216, 74, 9, 0, 56, 140, 93, 75])
27
+ _DISC_PUMPFUN_USER_VOLUME_ACCUMULATOR = bytes([86, 255, 112, 14, 102, 53, 154, 250])
22
28
  _DISC_GLOBAL_CONFIG = bytes([149, 8, 156, 202, 160, 252, 176, 217])
23
29
  _DISC_POOL = bytes([241, 154, 109, 4, 17, 177, 109, 188])
24
30
  _DISC_NONCE = bytes([1, 0, 0, 0, 1, 0, 0, 0])
@@ -26,9 +32,14 @@ _DISC_NONCE = bytes([1, 0, 0, 0, 1, 0, 0, 0])
26
32
  MINT_SIZE = 82
27
33
  TOKEN_ACCOUNT_SIZE = 165
28
34
  NONCE_ACCOUNT_SIZE = 80
29
- PUMPFUN_GLOBAL_BODY = 1021
35
+ PUMPFUN_GLOBAL_BODY = 1037
36
+ PUMPFUN_BONDING_CURVE_BODY = 107
37
+ PUMPFUN_GLOBAL_VOLUME_ACCUMULATOR_BODY = 536
38
+ PUMPFUN_USER_VOLUME_ACCUMULATOR_BODY = 98
30
39
  GLOBAL_CONFIG_BODY = 634
31
40
  POOL_BODY = 244
41
+ MAX_PUMPFUN_FEE_TIERS = 64
42
+ MAX_PUMPFUN_SHAREHOLDERS = 64
32
43
 
33
44
  SUPPLY_OFFSET = 36
34
45
  DECIMALS_OFFSET = 44
@@ -75,6 +86,71 @@ def read_u16_fast(data: bytes, offset: int) -> int:
75
86
  return struct.unpack_from("<H", data, offset)[0]
76
87
 
77
88
 
89
+ def read_i64_fast(data: bytes, offset: int) -> int:
90
+ return struct.unpack_from("<q", data, offset)[0]
91
+
92
+
93
+ def read_u32_fast(data: bytes, offset: int) -> int:
94
+ return struct.unpack_from("<I", data, offset)[0]
95
+
96
+
97
+ def read_u128_fast(data: bytes, offset: int) -> int:
98
+ return int.from_bytes(data[offset : offset + 16], "little")
99
+
100
+
101
+ def _read_pumpfun_fees(data: bytes, offset: int) -> Optional[tuple[dict, int]]:
102
+ if offset + 24 > len(data):
103
+ return None
104
+ return (
105
+ {
106
+ "lp_fee_bps": read_u64_fast(data, offset),
107
+ "protocol_fee_bps": read_u64_fast(data, offset + 8),
108
+ "creator_fee_bps": read_u64_fast(data, offset + 16),
109
+ },
110
+ offset + 24,
111
+ )
112
+
113
+
114
+ def _read_pumpfun_fee_tiers(data: bytes, offset: int) -> Optional[tuple[list[dict], int]]:
115
+ if offset + 4 > len(data):
116
+ return None
117
+ length = read_u32_fast(data, offset)
118
+ if length > MAX_PUMPFUN_FEE_TIERS:
119
+ return None
120
+ offset += 4
121
+ if offset + length * 40 > len(data):
122
+ return None
123
+ out = []
124
+ for _ in range(length):
125
+ threshold = read_u128_fast(data, offset)
126
+ offset += 16
127
+ fees_result = _read_pumpfun_fees(data, offset)
128
+ if fees_result is None:
129
+ return None
130
+ fees, offset = fees_result
131
+ out.append({"market_cap_lamports_threshold": threshold, "fees": fees})
132
+ return out, offset
133
+
134
+
135
+ def _read_pumpfun_shareholders(data: bytes, offset: int) -> Optional[tuple[list[dict], int]]:
136
+ if offset + 4 > len(data):
137
+ return None
138
+ length = read_u32_fast(data, offset)
139
+ if length > MAX_PUMPFUN_SHAREHOLDERS:
140
+ return None
141
+ offset += 4
142
+ if offset + length * 34 > len(data):
143
+ return None
144
+ out = []
145
+ for _ in range(length):
146
+ address = read_pubkey_fast(data, offset)
147
+ offset += 32
148
+ share_bps = read_u16_fast(data, offset)
149
+ offset += 2
150
+ out.append({"address": address, "share_bps": share_bps})
151
+ return out, offset
152
+
153
+
78
154
  def parse_account_unified(
79
155
  account: AccountData,
80
156
  metadata: EventMetadata,
@@ -93,6 +169,11 @@ def parse_account_unified(
93
169
  EventType.TOKEN_INFO,
94
170
  EventType.NONCE_ACCOUNT,
95
171
  EventType.ACCOUNT_PUMP_FUN_GLOBAL,
172
+ EventType.ACCOUNT_PUMP_FUN_BONDING_CURVE,
173
+ EventType.ACCOUNT_PUMP_FUN_FEE_CONFIG,
174
+ EventType.ACCOUNT_PUMP_FUN_SHARING_CONFIG,
175
+ EventType.ACCOUNT_PUMP_FUN_GLOBAL_VOLUME_ACCUMULATOR,
176
+ EventType.ACCOUNT_PUMP_FUN_USER_VOLUME_ACCUMULATOR,
96
177
  EventType.ACCOUNT_PUMP_SWAP_GLOBAL_CONFIG,
97
178
  EventType.ACCOUNT_PUMP_SWAP_POOL,
98
179
  }
@@ -107,8 +188,20 @@ def parse_account_unified(
107
188
  if ev is not None:
108
189
  return ev
109
190
 
110
- if account.owner == PUMPFUN_PROGRAM_ID and event_type_filter is not None:
111
- if event_type_filter.should_include(EventType.ACCOUNT_PUMP_FUN_GLOBAL):
191
+ if account.owner in (PUMPFUN_PROGRAM_ID, PUMP_FEES_PROGRAM_ID) and event_type_filter is not None:
192
+ if event_type_filter.should_include(
193
+ EventType.ACCOUNT_PUMP_FUN_GLOBAL
194
+ ) or event_type_filter.should_include(
195
+ EventType.ACCOUNT_PUMP_FUN_BONDING_CURVE
196
+ ) or event_type_filter.should_include(
197
+ EventType.ACCOUNT_PUMP_FUN_FEE_CONFIG
198
+ ) or event_type_filter.should_include(
199
+ EventType.ACCOUNT_PUMP_FUN_SHARING_CONFIG
200
+ ) or event_type_filter.should_include(
201
+ EventType.ACCOUNT_PUMP_FUN_GLOBAL_VOLUME_ACCUMULATOR
202
+ ) or event_type_filter.should_include(
203
+ EventType.ACCOUNT_PUMP_FUN_USER_VOLUME_ACCUMULATOR
204
+ ):
112
205
  ev = _parse_pumpfun_account(account, metadata)
113
206
  if ev is not None:
114
207
  return ev
@@ -134,6 +227,16 @@ def _parse_pumpswap_account(account: AccountData, metadata: EventMetadata) -> Op
134
227
 
135
228
 
136
229
  def _parse_pumpfun_account(account: AccountData, metadata: EventMetadata) -> Optional[DexEvent]:
230
+ if acc_utils.has_discriminator(account.data, _DISC_PUMPFUN_FEE_CONFIG):
231
+ return parse_pumpfun_fee_config(account, metadata)
232
+ if acc_utils.has_discriminator(account.data, _DISC_PUMPFUN_SHARING_CONFIG):
233
+ return parse_pumpfun_sharing_config(account, metadata)
234
+ if acc_utils.has_discriminator(account.data, _DISC_PUMPFUN_GLOBAL_VOLUME_ACCUMULATOR):
235
+ return parse_pumpfun_global_volume_accumulator(account, metadata)
236
+ if acc_utils.has_discriminator(account.data, _DISC_PUMPFUN_USER_VOLUME_ACCUMULATOR):
237
+ return parse_pumpfun_user_volume_accumulator(account, metadata)
238
+ if acc_utils.has_discriminator(account.data, _DISC_PUMPFUN_BONDING_CURVE):
239
+ return parse_pumpfun_bonding_curve(account, metadata)
137
240
  if acc_utils.has_discriminator(account.data, _DISC_PUMPFUN_GLOBAL):
138
241
  return parse_pumpfun_global(account, metadata)
139
242
  return None
@@ -219,7 +322,7 @@ def _parse_pumpfun_global_fast(account: AccountData, metadata: EventMetadata) ->
219
322
  creator_fee_basis_points = read_u64_fast(data, o)
220
323
  o += 8
221
324
  fee_recipients = []
222
- for _ in range(8):
325
+ for _ in range(7):
223
326
  fee_recipients.append(read_pubkey_fast(data, o))
224
327
  o += 32
225
328
  set_creator_authority = read_pubkey_fast(data, o)
@@ -238,6 +341,18 @@ def _parse_pumpfun_global_fast(account: AccountData, metadata: EventMetadata) ->
238
341
  for _ in range(7):
239
342
  reserved_fee_recipients.append(read_pubkey_fast(data, o))
240
343
  o += 32
344
+ is_cashback_enabled = data[o] != 0
345
+ o += 1
346
+ buyback_fee_recipients = []
347
+ for _ in range(8):
348
+ buyback_fee_recipients.append(read_pubkey_fast(data, o))
349
+ o += 32
350
+ buyback_basis_points = read_u64_fast(data, o)
351
+ o += 8
352
+ initial_virtual_quote_reserves = read_u64_fast(data, o)
353
+ o += 8
354
+ whitelisted_quote_mints = [read_pubkey_fast(data, o)]
355
+ o += 32
241
356
  return _account_event(
242
357
  EventType.ACCOUNT_PUMP_FUN_GLOBAL,
243
358
  {
@@ -264,6 +379,221 @@ def _parse_pumpfun_global_fast(account: AccountData, metadata: EventMetadata) ->
264
379
  "reserved_fee_recipient": reserved_fee_recipient,
265
380
  "mayhem_mode_enabled": mayhem_mode_enabled,
266
381
  "reserved_fee_recipients": reserved_fee_recipients,
382
+ "is_cashback_enabled": is_cashback_enabled,
383
+ "buyback_fee_recipients": buyback_fee_recipients,
384
+ "buyback_basis_points": buyback_basis_points,
385
+ "initial_virtual_quote_reserves": initial_virtual_quote_reserves,
386
+ "whitelisted_quote_mints": whitelisted_quote_mints,
387
+ },
388
+ },
389
+ )
390
+
391
+
392
+ def _parse_pumpfun_bonding_curve_fast(
393
+ account: AccountData, metadata: EventMetadata
394
+ ) -> Optional[DexEvent]:
395
+ data = account.data[8:]
396
+ o = 0
397
+ virtual_token_reserves = read_u64_fast(data, o)
398
+ o += 8
399
+ virtual_quote_reserves = read_u64_fast(data, o)
400
+ o += 8
401
+ real_token_reserves = read_u64_fast(data, o)
402
+ o += 8
403
+ real_quote_reserves = read_u64_fast(data, o)
404
+ o += 8
405
+ token_total_supply = read_u64_fast(data, o)
406
+ o += 8
407
+ complete = data[o] != 0
408
+ o += 1
409
+ creator = read_pubkey_fast(data, o)
410
+ o += 32
411
+ is_mayhem_mode = data[o] != 0
412
+ o += 1
413
+ is_cashback_coin = data[o] != 0
414
+ o += 1
415
+ quote_mint = read_pubkey_fast(data, o)
416
+ return _account_event(
417
+ EventType.ACCOUNT_PUMP_FUN_BONDING_CURVE,
418
+ {
419
+ "metadata": metadata,
420
+ "pubkey": account.pubkey,
421
+ "bonding_curve": {
422
+ "virtual_token_reserves": virtual_token_reserves,
423
+ "virtual_quote_reserves": virtual_quote_reserves,
424
+ "real_token_reserves": real_token_reserves,
425
+ "real_quote_reserves": real_quote_reserves,
426
+ "token_total_supply": token_total_supply,
427
+ "complete": complete,
428
+ "creator": creator,
429
+ "is_mayhem_mode": is_mayhem_mode,
430
+ "is_cashback_coin": is_cashback_coin,
431
+ "quote_mint": quote_mint,
432
+ },
433
+ },
434
+ )
435
+
436
+
437
+ def _parse_pumpfun_fee_config_fast(
438
+ account: AccountData, metadata: EventMetadata
439
+ ) -> Optional[DexEvent]:
440
+ data = account.data[8:]
441
+ o = 0
442
+ bump = data[o]
443
+ o += 1
444
+ admin = read_pubkey_fast(data, o)
445
+ o += 32
446
+ flat_fees_result = _read_pumpfun_fees(data, o)
447
+ if flat_fees_result is None:
448
+ return None
449
+ flat_fees, o = flat_fees_result
450
+ fee_tiers_result = _read_pumpfun_fee_tiers(data, o)
451
+ if fee_tiers_result is None:
452
+ return None
453
+ fee_tiers, o = fee_tiers_result
454
+ stable_fee_tiers_result = _read_pumpfun_fee_tiers(data, o)
455
+ if stable_fee_tiers_result is None:
456
+ return None
457
+ stable_fee_tiers, _ = stable_fee_tiers_result
458
+ return _account_event(
459
+ EventType.ACCOUNT_PUMP_FUN_FEE_CONFIG,
460
+ {
461
+ "metadata": metadata,
462
+ "pubkey": account.pubkey,
463
+ "fee_config": {
464
+ "bump": bump,
465
+ "admin": admin,
466
+ "flat_fees": flat_fees,
467
+ "fee_tiers": fee_tiers,
468
+ "stable_fee_tiers": stable_fee_tiers,
469
+ },
470
+ },
471
+ )
472
+
473
+
474
+ def _parse_pumpfun_sharing_config_fast(
475
+ account: AccountData, metadata: EventMetadata
476
+ ) -> Optional[DexEvent]:
477
+ data = account.data[8:]
478
+ o = 0
479
+ bump = data[o]
480
+ o += 1
481
+ version = data[o]
482
+ o += 1
483
+ status_raw = data[o]
484
+ if status_raw > 1:
485
+ return None
486
+ status = "Paused" if status_raw == 0 else "Active"
487
+ o += 1
488
+ mint = read_pubkey_fast(data, o)
489
+ o += 32
490
+ admin = read_pubkey_fast(data, o)
491
+ o += 32
492
+ admin_revoked = data[o] != 0
493
+ o += 1
494
+ shareholders_result = _read_pumpfun_shareholders(data, o)
495
+ if shareholders_result is None:
496
+ return None
497
+ shareholders, _ = shareholders_result
498
+ return _account_event(
499
+ EventType.ACCOUNT_PUMP_FUN_SHARING_CONFIG,
500
+ {
501
+ "metadata": metadata,
502
+ "pubkey": account.pubkey,
503
+ "sharing_config": {
504
+ "bump": bump,
505
+ "version": version,
506
+ "status": status,
507
+ "mint": mint,
508
+ "admin": admin,
509
+ "admin_revoked": admin_revoked,
510
+ "shareholders": shareholders,
511
+ },
512
+ },
513
+ )
514
+
515
+
516
+ def _parse_pumpfun_global_volume_accumulator_fast(
517
+ account: AccountData, metadata: EventMetadata
518
+ ) -> Optional[DexEvent]:
519
+ data = account.data[8:]
520
+ o = 0
521
+ start_time = read_i64_fast(data, o)
522
+ o += 8
523
+ end_time = read_i64_fast(data, o)
524
+ o += 8
525
+ seconds_in_a_day = read_i64_fast(data, o)
526
+ o += 8
527
+ mint = read_pubkey_fast(data, o)
528
+ o += 32
529
+ total_token_supply = []
530
+ for _ in range(30):
531
+ total_token_supply.append(read_u64_fast(data, o))
532
+ o += 8
533
+ sol_volumes = []
534
+ for _ in range(30):
535
+ sol_volumes.append(read_u64_fast(data, o))
536
+ o += 8
537
+ return _account_event(
538
+ EventType.ACCOUNT_PUMP_FUN_GLOBAL_VOLUME_ACCUMULATOR,
539
+ {
540
+ "metadata": metadata,
541
+ "pubkey": account.pubkey,
542
+ "global_volume_accumulator": {
543
+ "start_time": start_time,
544
+ "end_time": end_time,
545
+ "seconds_in_a_day": seconds_in_a_day,
546
+ "mint": mint,
547
+ "total_token_supply": total_token_supply,
548
+ "sol_volumes": sol_volumes,
549
+ },
550
+ },
551
+ )
552
+
553
+
554
+ def _parse_pumpfun_user_volume_accumulator_fast(
555
+ account: AccountData, metadata: EventMetadata
556
+ ) -> Optional[DexEvent]:
557
+ data = account.data[8:]
558
+ o = 0
559
+ user = read_pubkey_fast(data, o)
560
+ o += 32
561
+ needs_claim = data[o] != 0
562
+ o += 1
563
+ total_unclaimed_tokens = read_u64_fast(data, o)
564
+ o += 8
565
+ total_claimed_tokens = read_u64_fast(data, o)
566
+ o += 8
567
+ current_sol_volume = read_u64_fast(data, o)
568
+ o += 8
569
+ last_update_timestamp = read_i64_fast(data, o)
570
+ o += 8
571
+ has_total_claimed_tokens = data[o] != 0
572
+ o += 1
573
+ cashback_earned = read_u64_fast(data, o)
574
+ o += 8
575
+ total_cashback_claimed = read_u64_fast(data, o)
576
+ o += 8
577
+ stable_cashback_earned = read_u64_fast(data, o)
578
+ o += 8
579
+ total_stable_cashback_claimed = read_u64_fast(data, o)
580
+ return _account_event(
581
+ EventType.ACCOUNT_PUMP_FUN_USER_VOLUME_ACCUMULATOR,
582
+ {
583
+ "metadata": metadata,
584
+ "pubkey": account.pubkey,
585
+ "user_volume_accumulator": {
586
+ "user": user,
587
+ "needs_claim": needs_claim,
588
+ "total_unclaimed_tokens": total_unclaimed_tokens,
589
+ "total_claimed_tokens": total_claimed_tokens,
590
+ "current_sol_volume": current_sol_volume,
591
+ "last_update_timestamp": last_update_timestamp,
592
+ "has_total_claimed_tokens": has_total_claimed_tokens,
593
+ "cashback_earned": cashback_earned,
594
+ "total_cashback_claimed": total_cashback_claimed,
595
+ "stable_cashback_earned": stable_cashback_earned,
596
+ "total_stable_cashback_claimed": total_stable_cashback_claimed,
267
597
  },
268
598
  },
269
599
  )
@@ -399,6 +729,52 @@ def parse_pumpfun_global(account: AccountData, metadata: EventMetadata) -> Optio
399
729
  return _parse_pumpfun_global_fast(account, metadata)
400
730
 
401
731
 
732
+ def parse_pumpfun_bonding_curve(
733
+ account: AccountData, metadata: EventMetadata
734
+ ) -> Optional[DexEvent]:
735
+ if len(account.data) < 8 + PUMPFUN_BONDING_CURVE_BODY:
736
+ return None
737
+ if not has_discriminator(account.data, _DISC_PUMPFUN_BONDING_CURVE):
738
+ return None
739
+ return _parse_pumpfun_bonding_curve_fast(account, metadata)
740
+
741
+
742
+ def parse_pumpfun_fee_config(account: AccountData, metadata: EventMetadata) -> Optional[DexEvent]:
743
+ if len(account.data) < 8 + 1 + 32 + 24 + 4 + 4:
744
+ return None
745
+ if not has_discriminator(account.data, _DISC_PUMPFUN_FEE_CONFIG):
746
+ return None
747
+ return _parse_pumpfun_fee_config_fast(account, metadata)
748
+
749
+
750
+ def parse_pumpfun_sharing_config(account: AccountData, metadata: EventMetadata) -> Optional[DexEvent]:
751
+ if len(account.data) < 8 + 1 + 1 + 1 + 32 + 32 + 1 + 4:
752
+ return None
753
+ if not has_discriminator(account.data, _DISC_PUMPFUN_SHARING_CONFIG):
754
+ return None
755
+ return _parse_pumpfun_sharing_config_fast(account, metadata)
756
+
757
+
758
+ def parse_pumpfun_global_volume_accumulator(
759
+ account: AccountData, metadata: EventMetadata
760
+ ) -> Optional[DexEvent]:
761
+ if len(account.data) < 8 + PUMPFUN_GLOBAL_VOLUME_ACCUMULATOR_BODY:
762
+ return None
763
+ if not has_discriminator(account.data, _DISC_PUMPFUN_GLOBAL_VOLUME_ACCUMULATOR):
764
+ return None
765
+ return _parse_pumpfun_global_volume_accumulator_fast(account, metadata)
766
+
767
+
768
+ def parse_pumpfun_user_volume_accumulator(
769
+ account: AccountData, metadata: EventMetadata
770
+ ) -> Optional[DexEvent]:
771
+ if len(account.data) < 8 + PUMPFUN_USER_VOLUME_ACCUMULATOR_BODY:
772
+ return None
773
+ if not has_discriminator(account.data, _DISC_PUMPFUN_USER_VOLUME_ACCUMULATOR):
774
+ return None
775
+ return _parse_pumpfun_user_volume_accumulator_fast(account, metadata)
776
+
777
+
402
778
  def is_nonce_account(data: bytes) -> bool:
403
779
  return acc_utils.is_nonce_account(data)
404
780
 
@@ -445,6 +821,11 @@ __all__ = [
445
821
  "parse_token_account",
446
822
  "parse_nonce_account",
447
823
  "parse_pumpfun_global",
824
+ "parse_pumpfun_bonding_curve",
825
+ "parse_pumpfun_fee_config",
826
+ "parse_pumpfun_sharing_config",
827
+ "parse_pumpfun_global_volume_accumulator",
828
+ "parse_pumpfun_user_volume_accumulator",
448
829
  "is_nonce_account",
449
830
  "is_pumpfun_global_account",
450
831
  "parse_pumpswap_global_config",
@@ -453,6 +834,7 @@ __all__ = [
453
834
  "is_pool_account",
454
835
  "has_discriminator",
455
836
  "PUMPFUN_PROGRAM_ID",
837
+ "PUMP_FEES_PROGRAM_ID",
456
838
  "PUMPSWAP_PROGRAM_ID",
457
839
  "rpc_resolve_user_wallet_pubkey",
458
840
  "user_wallet_pubkey_for_onchain_account",