sol-parser-sdk-python 0.4.4__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 +400 -0
- sol_parser/account_dispatcher.py +209 -0
- sol_parser/account_fillers/__init__.py +5 -0
- sol_parser/account_fillers/bonk.py +30 -0
- sol_parser/account_fillers/meteora.py +51 -0
- sol_parser/account_fillers/orca.py +40 -0
- sol_parser/account_fillers/pumpfun.py +97 -0
- sol_parser/account_fillers/pumpswap.py +93 -0
- sol_parser/account_fillers/raydium.py +119 -0
- sol_parser/accounts/__init__.py +461 -0
- sol_parser/accounts/rpc_wallet.py +64 -0
- sol_parser/accounts/utils.py +71 -0
- sol_parser/check_migration.py +18 -0
- sol_parser/clock.py +10 -0
- sol_parser/common/__init__.py +27 -0
- sol_parser/dex_parsers.py +2576 -0
- sol_parser/entries_decode.py +186 -0
- sol_parser/env_config.py +215 -0
- sol_parser/event_types.py +1750 -0
- sol_parser/geyser_pb2.py +148 -0
- sol_parser/geyser_pb2_grpc.py +398 -0
- sol_parser/grpc/__init__.py +61 -0
- sol_parser/grpc/geyser_connect.py +42 -0
- sol_parser/grpc/subscribe_builder.py +133 -0
- sol_parser/grpc/transaction_meta.py +183 -0
- sol_parser/grpc_client.py +870 -0
- sol_parser/grpc_instruction_parser.py +318 -0
- sol_parser/grpc_types.py +919 -0
- sol_parser/inner_instruction_parser.py +281 -0
- sol_parser/instr/__init__.py +15 -0
- sol_parser/instr_account_utils.py +58 -0
- sol_parser/instructions.py +1026 -0
- sol_parser/json_util.py +41 -0
- sol_parser/log_instr_dedup.py +284 -0
- sol_parser/logs/__init__.py +15 -0
- sol_parser/merger.py +233 -0
- sol_parser/order_buffer.py +171 -0
- sol_parser/parser.py +300 -0
- sol_parser/pumpfun_fee_enrich.py +75 -0
- sol_parser/rpc_parser.py +655 -0
- sol_parser/rust_api_inventory.py +42 -0
- sol_parser/rust_event_json.py +50 -0
- sol_parser/shredstream_client.py +191 -0
- sol_parser/shredstream_pb2.py +40 -0
- sol_parser/shredstream_pb2_grpc.py +81 -0
- sol_parser/shredstream_pumpfun.py +296 -0
- sol_parser/solana_storage_pb2.py +75 -0
- sol_parser/solana_storage_pb2_grpc.py +24 -0
- sol_parser/u128_parity.py +115 -0
- sol_parser/verify_discriminators.py +85 -0
- sol_parser_sdk_python-0.4.4.dist-info/METADATA +14 -0
- sol_parser_sdk_python-0.4.4.dist-info/RECORD +54 -0
- sol_parser_sdk_python-0.4.4.dist-info/WHEEL +4 -0
- sol_parser_sdk_python-0.4.4.dist-info/entry_points.txt +4 -0
sol_parser/json_util.py
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""与 TS `dexEventToJsonString` 对应:将解析结果安全序列化为 JSON(`default=str` 覆盖非原生类型)。"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from dataclasses import asdict, is_dataclass
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from .event_types import DexEvent
|
|
10
|
+
from .grpc_types import EventType
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def dex_event_json_dumps(obj: Any, **kwargs: Any) -> str:
|
|
14
|
+
return json.dumps(obj, default=str, **kwargs)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def dex_event_to_jsonable(ev: Any) -> Any:
|
|
18
|
+
"""将 :class:`~sol_parser.event_types.DexEvent` 转为可 JSON 化的 ``{"type","data"}`` 结构。
|
|
19
|
+
|
|
20
|
+
``data`` 内嵌 dataclass(含 ``metadata``)用 :func:`dataclasses.asdict` 递归展开,
|
|
21
|
+
便于 ``indent`` 后一行一个字段阅读。
|
|
22
|
+
"""
|
|
23
|
+
if isinstance(ev, DexEvent):
|
|
24
|
+
t = ev.type.value if isinstance(ev.type, EventType) else str(ev.type)
|
|
25
|
+
if ev.data is None:
|
|
26
|
+
return {"type": t, "data": None}
|
|
27
|
+
if is_dataclass(ev.data):
|
|
28
|
+
return {"type": t, "data": asdict(ev.data)}
|
|
29
|
+
return {"type": t, "data": ev.data}
|
|
30
|
+
if is_dataclass(ev):
|
|
31
|
+
return asdict(ev)
|
|
32
|
+
return ev
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def format_dex_event_json(ev: Any, *, indent: int = 2, ensure_ascii: bool = False) -> str:
|
|
36
|
+
"""将事件格式化为缩进 JSON 字符串(默认每字段一行,对齐常见日志阅读习惯)。"""
|
|
37
|
+
return dex_event_json_dumps(
|
|
38
|
+
dex_event_to_jsonable(ev),
|
|
39
|
+
indent=indent,
|
|
40
|
+
ensure_ascii=ensure_ascii,
|
|
41
|
+
)
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
"""Rust-style log/instruction dedupe for Yellowstone transaction parsing."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
6
|
+
|
|
7
|
+
from .event_types import DexEvent
|
|
8
|
+
from .grpc_types import EventType
|
|
9
|
+
|
|
10
|
+
ZERO = "11111111111111111111111111111111"
|
|
11
|
+
|
|
12
|
+
PUMPFUN_TRADE_TYPES = {
|
|
13
|
+
EventType.PUMP_FUN_TRADE,
|
|
14
|
+
EventType.PUMP_FUN_BUY,
|
|
15
|
+
EventType.PUMP_FUN_SELL,
|
|
16
|
+
EventType.PUMP_FUN_BUY_EXACT_SOL_IN,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _empty(value: Any) -> bool:
|
|
21
|
+
return value is None or value == "" or value == ZERO
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _fill_attr(log: Any, attr: str, ix: Any, ix_attr: Optional[str] = None) -> None:
|
|
25
|
+
src_attr = ix_attr or attr
|
|
26
|
+
value = getattr(ix, src_attr, None)
|
|
27
|
+
if _empty(getattr(log, attr, None)) and not _empty(value):
|
|
28
|
+
setattr(log, attr, value)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _fill_bonk_mint_param(log: Any, ix: Any, key: str) -> None:
|
|
32
|
+
src = getattr(ix, "base_mint_param", None)
|
|
33
|
+
if not isinstance(src, dict):
|
|
34
|
+
return
|
|
35
|
+
dst = getattr(log, "base_mint_param", None)
|
|
36
|
+
if not isinstance(dst, dict):
|
|
37
|
+
dst = {}
|
|
38
|
+
setattr(log, "base_mint_param", dst)
|
|
39
|
+
value = src.get(key)
|
|
40
|
+
if _empty(dst.get(key)) and not _empty(value):
|
|
41
|
+
dst[key] = value
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _ix_lane(ix_name: Any) -> int:
|
|
45
|
+
if ix_name == "sell":
|
|
46
|
+
return 1
|
|
47
|
+
if ix_name == "buy_exact_sol_in":
|
|
48
|
+
return 2
|
|
49
|
+
return 0
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
PumpfunLaneBase = Tuple[str, str, bool, int]
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _next_occurrence(base: PumpfunLaneBase, counts: Dict[PumpfunLaneBase, int]) -> int:
|
|
56
|
+
current = counts.get(base, 0)
|
|
57
|
+
counts[base] = current + 1
|
|
58
|
+
return current
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _dedupe_key(ev: DexEvent, pumpfun_lane_counts: Dict[PumpfunLaneBase, int]) -> Optional[str]:
|
|
62
|
+
data = ev.data
|
|
63
|
+
if data is None:
|
|
64
|
+
return None
|
|
65
|
+
|
|
66
|
+
if ev.type in PUMPFUN_TRADE_TYPES:
|
|
67
|
+
lane = _ix_lane(getattr(data, "ix_name", ""))
|
|
68
|
+
base = (
|
|
69
|
+
getattr(data, "mint", ""),
|
|
70
|
+
getattr(data, "user", ""),
|
|
71
|
+
bool(getattr(data, "is_buy", False)),
|
|
72
|
+
lane,
|
|
73
|
+
)
|
|
74
|
+
occ = _next_occurrence(base, pumpfun_lane_counts)
|
|
75
|
+
return f"PumpFunTrade|{base[0]}|{base[1]}|{base[2]}|{base[3]}|{occ}"
|
|
76
|
+
|
|
77
|
+
t = ev.type
|
|
78
|
+
if t == EventType.PUMP_FUN_CREATE:
|
|
79
|
+
return f"PumpFunCreate|{getattr(data, 'mint', '')}"
|
|
80
|
+
if t == EventType.PUMP_FUN_CREATE_V2:
|
|
81
|
+
return f"PumpFunCreateV2|{getattr(data, 'mint', '')}"
|
|
82
|
+
if t == EventType.PUMP_FUN_MIGRATE:
|
|
83
|
+
return (
|
|
84
|
+
f"PumpFunMigrate|{getattr(data, 'mint', '')}|"
|
|
85
|
+
f"{getattr(data, 'pool', '')}|{getattr(data, 'user', '')}"
|
|
86
|
+
)
|
|
87
|
+
if t == EventType.BONK_TRADE:
|
|
88
|
+
return (
|
|
89
|
+
f"BonkTrade|{getattr(data, 'pool_state', '')}|"
|
|
90
|
+
f"{getattr(data, 'user', '')}|{bool(getattr(data, 'is_buy', False))}"
|
|
91
|
+
)
|
|
92
|
+
if t == EventType.BONK_POOL_CREATE:
|
|
93
|
+
return f"BonkPoolCreate|{getattr(data, 'pool_state', '')}"
|
|
94
|
+
if t == EventType.BONK_MIGRATE_AMM:
|
|
95
|
+
return (
|
|
96
|
+
f"BonkMigrateAmm|{getattr(data, 'old_pool', '')}|"
|
|
97
|
+
f"{getattr(data, 'new_pool', '')}|{getattr(data, 'user', '')}"
|
|
98
|
+
)
|
|
99
|
+
if t == EventType.PUMP_SWAP_BUY:
|
|
100
|
+
return f"PumpSwapBuy|{getattr(data, 'pool', '')}|{getattr(data, 'user', '')}"
|
|
101
|
+
if t == EventType.PUMP_SWAP_SELL:
|
|
102
|
+
return f"PumpSwapSell|{getattr(data, 'pool', '')}|{getattr(data, 'user', '')}"
|
|
103
|
+
if t == EventType.PUMP_SWAP_CREATE_POOL:
|
|
104
|
+
return (
|
|
105
|
+
f"PumpSwapCreatePool|{getattr(data, 'pool', '')}|"
|
|
106
|
+
f"{getattr(data, 'base_mint', '')}|{getattr(data, 'quote_mint', '')}"
|
|
107
|
+
)
|
|
108
|
+
if t == EventType.PUMP_SWAP_LIQUIDITY_ADDED:
|
|
109
|
+
return f"PumpSwapLiquidityAdded|{getattr(data, 'pool', '')}|{getattr(data, 'user', '')}"
|
|
110
|
+
if t == EventType.PUMP_SWAP_LIQUIDITY_REMOVED:
|
|
111
|
+
return f"PumpSwapLiquidityRemoved|{getattr(data, 'pool', '')}|{getattr(data, 'user', '')}"
|
|
112
|
+
if t == EventType.RAYDIUM_CLMM_SWAP:
|
|
113
|
+
return f"RaydiumClmmSwap|{getattr(data, 'pool_state', '')}|{bool(getattr(data, 'zero_for_one', False))}"
|
|
114
|
+
if t == EventType.RAYDIUM_AMM_V4_SWAP:
|
|
115
|
+
return f"RaydiumAmmV4Swap|{getattr(data, 'amm', '')}"
|
|
116
|
+
if t == EventType.METEORA_DLMM_SWAP:
|
|
117
|
+
return (
|
|
118
|
+
f"MeteoraDlmmSwap|{getattr(data, 'pool', '')}|"
|
|
119
|
+
f"{getattr(data, 'from_addr', '')}|{bool(getattr(data, 'swap_for_y', False))}"
|
|
120
|
+
)
|
|
121
|
+
return None
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def _merge_pumpfun_trade(log: Any, ix: Any) -> None:
|
|
125
|
+
for attr in (
|
|
126
|
+
"bonding_curve",
|
|
127
|
+
"associated_bonding_curve",
|
|
128
|
+
"token_program",
|
|
129
|
+
"creator_vault",
|
|
130
|
+
"fee_recipient",
|
|
131
|
+
"creator",
|
|
132
|
+
"extra_instruction_account",
|
|
133
|
+
):
|
|
134
|
+
_fill_attr(log, attr, ix)
|
|
135
|
+
if getattr(log, "ix_name", "") == "" and getattr(ix, "ix_name", "") != "":
|
|
136
|
+
log.ix_name = ix.ix_name
|
|
137
|
+
log.is_created_buy = bool(getattr(log, "is_created_buy", False)) or bool(
|
|
138
|
+
getattr(ix, "is_created_buy", False)
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def _merge_pumpfun_create(log: Any, ix: Any) -> None:
|
|
143
|
+
for attr in ("name", "symbol", "uri", "bonding_curve", "user", "creator", "token_program"):
|
|
144
|
+
_fill_attr(log, attr, ix)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def _merge_pumpfun_create_v2(log: Any, ix: Any) -> None:
|
|
148
|
+
_merge_pumpfun_create(log, ix)
|
|
149
|
+
for attr in (
|
|
150
|
+
"mint_authority",
|
|
151
|
+
"associated_bonding_curve",
|
|
152
|
+
"global_account",
|
|
153
|
+
"system_program",
|
|
154
|
+
"associated_token_program",
|
|
155
|
+
"mayhem_program_id",
|
|
156
|
+
"global_params",
|
|
157
|
+
"sol_vault",
|
|
158
|
+
"mayhem_state",
|
|
159
|
+
"mayhem_token_vault",
|
|
160
|
+
"event_authority",
|
|
161
|
+
"program",
|
|
162
|
+
"observed_fee_recipient",
|
|
163
|
+
):
|
|
164
|
+
_fill_attr(log, attr, ix)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def _merge_pumpswap_buy_sell(log: Any, ix: Any, include_ix_name: bool) -> None:
|
|
168
|
+
for attr in (
|
|
169
|
+
"user_base_token_account",
|
|
170
|
+
"user_quote_token_account",
|
|
171
|
+
"protocol_fee_recipient",
|
|
172
|
+
"protocol_fee_recipient_token_account",
|
|
173
|
+
"coin_creator",
|
|
174
|
+
"base_mint",
|
|
175
|
+
"quote_mint",
|
|
176
|
+
"pool_base_token_account",
|
|
177
|
+
"pool_quote_token_account",
|
|
178
|
+
"coin_creator_vault_ata",
|
|
179
|
+
"coin_creator_vault_authority",
|
|
180
|
+
"base_token_program",
|
|
181
|
+
"quote_token_program",
|
|
182
|
+
):
|
|
183
|
+
_fill_attr(log, attr, ix)
|
|
184
|
+
if include_ix_name and getattr(log, "ix_name", "") == "" and getattr(ix, "ix_name", "") != "":
|
|
185
|
+
log.ix_name = ix.ix_name
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def _merge_grpc_instruction_into_log(log_ev: DexEvent, ix_ev: DexEvent) -> None:
|
|
189
|
+
log = log_ev.data
|
|
190
|
+
ix = ix_ev.data
|
|
191
|
+
if log is None or ix is None:
|
|
192
|
+
return
|
|
193
|
+
|
|
194
|
+
if log_ev.type in PUMPFUN_TRADE_TYPES and ix_ev.type in PUMPFUN_TRADE_TYPES:
|
|
195
|
+
_merge_pumpfun_trade(log, ix)
|
|
196
|
+
elif log_ev.type == EventType.PUMP_FUN_CREATE and ix_ev.type == EventType.PUMP_FUN_CREATE:
|
|
197
|
+
_merge_pumpfun_create(log, ix)
|
|
198
|
+
elif log_ev.type == EventType.PUMP_FUN_CREATE_V2 and ix_ev.type == EventType.PUMP_FUN_CREATE_V2:
|
|
199
|
+
_merge_pumpfun_create_v2(log, ix)
|
|
200
|
+
elif log_ev.type == EventType.PUMP_FUN_MIGRATE and ix_ev.type == EventType.PUMP_FUN_MIGRATE:
|
|
201
|
+
for attr in ("bonding_curve", "pool", "user"):
|
|
202
|
+
_fill_attr(log, attr, ix)
|
|
203
|
+
elif log_ev.type == EventType.PUMP_SWAP_BUY and ix_ev.type == EventType.PUMP_SWAP_BUY:
|
|
204
|
+
_merge_pumpswap_buy_sell(log, ix, True)
|
|
205
|
+
elif log_ev.type == EventType.PUMP_SWAP_SELL and ix_ev.type == EventType.PUMP_SWAP_SELL:
|
|
206
|
+
_merge_pumpswap_buy_sell(log, ix, False)
|
|
207
|
+
elif log_ev.type == EventType.PUMP_SWAP_CREATE_POOL and ix_ev.type == EventType.PUMP_SWAP_CREATE_POOL:
|
|
208
|
+
for attr in (
|
|
209
|
+
"creator",
|
|
210
|
+
"pool",
|
|
211
|
+
"lp_mint",
|
|
212
|
+
"user_base_token_account",
|
|
213
|
+
"user_quote_token_account",
|
|
214
|
+
"coin_creator",
|
|
215
|
+
):
|
|
216
|
+
_fill_attr(log, attr, ix)
|
|
217
|
+
elif (
|
|
218
|
+
log_ev.type == EventType.PUMP_SWAP_LIQUIDITY_ADDED
|
|
219
|
+
and ix_ev.type == EventType.PUMP_SWAP_LIQUIDITY_ADDED
|
|
220
|
+
) or (
|
|
221
|
+
log_ev.type == EventType.PUMP_SWAP_LIQUIDITY_REMOVED
|
|
222
|
+
and ix_ev.type == EventType.PUMP_SWAP_LIQUIDITY_REMOVED
|
|
223
|
+
):
|
|
224
|
+
for attr in ("user_base_token_account", "user_quote_token_account", "user_pool_token_account"):
|
|
225
|
+
_fill_attr(log, attr, ix)
|
|
226
|
+
elif log_ev.type == EventType.RAYDIUM_CLMM_SWAP and ix_ev.type == EventType.RAYDIUM_CLMM_SWAP:
|
|
227
|
+
for attr in ("token_account_0", "token_account_1", "sender"):
|
|
228
|
+
_fill_attr(log, attr, ix)
|
|
229
|
+
elif log_ev.type == EventType.RAYDIUM_AMM_V4_SWAP and ix_ev.type == EventType.RAYDIUM_AMM_V4_SWAP:
|
|
230
|
+
for attr in (
|
|
231
|
+
"token_program",
|
|
232
|
+
"amm_authority",
|
|
233
|
+
"amm_open_orders",
|
|
234
|
+
"pool_coin_token_account",
|
|
235
|
+
"pool_pc_token_account",
|
|
236
|
+
"serum_program",
|
|
237
|
+
"serum_market",
|
|
238
|
+
"serum_bids",
|
|
239
|
+
"serum_asks",
|
|
240
|
+
"serum_event_queue",
|
|
241
|
+
"serum_coin_vault_account",
|
|
242
|
+
"serum_pc_vault_account",
|
|
243
|
+
"serum_vault_signer",
|
|
244
|
+
"user_source_token_account",
|
|
245
|
+
"user_destination_token_account",
|
|
246
|
+
):
|
|
247
|
+
_fill_attr(log, attr, ix)
|
|
248
|
+
elif log_ev.type == EventType.BONK_POOL_CREATE and ix_ev.type == EventType.BONK_POOL_CREATE:
|
|
249
|
+
_fill_attr(log, "creator", ix)
|
|
250
|
+
for key in ("name", "symbol", "uri"):
|
|
251
|
+
_fill_bonk_mint_param(log, ix, key)
|
|
252
|
+
elif log_ev.type == EventType.BONK_MIGRATE_AMM and ix_ev.type == EventType.BONK_MIGRATE_AMM:
|
|
253
|
+
for attr in ("old_pool", "new_pool", "user"):
|
|
254
|
+
_fill_attr(log, attr, ix)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def dedupe_log_instruction_events(
|
|
258
|
+
log_events: List[DexEvent],
|
|
259
|
+
instruction_events: List[DexEvent],
|
|
260
|
+
) -> List[DexEvent]:
|
|
261
|
+
out: List[DexEvent] = []
|
|
262
|
+
index_by_key: Dict[str, int] = {}
|
|
263
|
+
log_pumpfun_counts: Dict[PumpfunLaneBase, int] = {}
|
|
264
|
+
ix_pumpfun_counts: Dict[PumpfunLaneBase, int] = {}
|
|
265
|
+
|
|
266
|
+
for ev in log_events:
|
|
267
|
+
key = _dedupe_key(ev, log_pumpfun_counts)
|
|
268
|
+
if key is not None:
|
|
269
|
+
index_by_key[key] = len(out)
|
|
270
|
+
out.append(ev)
|
|
271
|
+
|
|
272
|
+
for ev in instruction_events:
|
|
273
|
+
key = _dedupe_key(ev, ix_pumpfun_counts)
|
|
274
|
+
if key is None:
|
|
275
|
+
out.append(ev)
|
|
276
|
+
continue
|
|
277
|
+
idx = index_by_key.get(key)
|
|
278
|
+
if idx is None:
|
|
279
|
+
index_by_key[key] = len(out)
|
|
280
|
+
out.append(ev)
|
|
281
|
+
continue
|
|
282
|
+
_merge_grpc_instruction_into_log(out[idx], ev)
|
|
283
|
+
|
|
284
|
+
return out
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""对齐 Rust ``logs`` 模块:日志解析入口与工具(实现位于 ``parser`` / ``dex_parsers``)。"""
|
|
2
|
+
|
|
3
|
+
from ..parser import (
|
|
4
|
+
decode_program_data_line,
|
|
5
|
+
parse_log,
|
|
6
|
+
parse_log_optimized,
|
|
7
|
+
parse_log_unified,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"decode_program_data_line",
|
|
12
|
+
"parse_log",
|
|
13
|
+
"parse_log_optimized",
|
|
14
|
+
"parse_log_unified",
|
|
15
|
+
]
|
sol_parser/merger.py
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
"""Instruction + inner instruction 事件合并(对齐 Rust ``core/merger``)。"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import dataclasses
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from .event_types import (
|
|
9
|
+
DexEvent,
|
|
10
|
+
PumpFunCreateEvent,
|
|
11
|
+
PumpFunCreateV2TokenEvent,
|
|
12
|
+
PumpFunMigrateEvent,
|
|
13
|
+
PumpFunTradeEvent,
|
|
14
|
+
PumpSwapBuyEvent,
|
|
15
|
+
PumpSwapCreatePoolEvent,
|
|
16
|
+
PumpSwapLiquidityAddedEvent,
|
|
17
|
+
PumpSwapLiquidityRemovedEvent,
|
|
18
|
+
PumpSwapSellEvent,
|
|
19
|
+
RaydiumAmmV4DepositEvent,
|
|
20
|
+
RaydiumAmmV4SwapEvent,
|
|
21
|
+
RaydiumAmmV4WithdrawEvent,
|
|
22
|
+
RaydiumClmmCollectFeeEvent,
|
|
23
|
+
RaydiumClmmCreatePoolEvent,
|
|
24
|
+
RaydiumClmmDecreaseLiquidityEvent,
|
|
25
|
+
RaydiumClmmIncreaseLiquidityEvent,
|
|
26
|
+
RaydiumClmmSwapEvent,
|
|
27
|
+
RaydiumCpmmDepositEvent,
|
|
28
|
+
RaydiumCpmmSwapEvent,
|
|
29
|
+
RaydiumCpmmWithdrawEvent,
|
|
30
|
+
MeteoraDammV2AddLiquidityEvent,
|
|
31
|
+
MeteoraDammV2ClosePositionEvent,
|
|
32
|
+
MeteoraDammV2CreatePositionEvent,
|
|
33
|
+
MeteoraDammV2RemoveLiquidityEvent,
|
|
34
|
+
MeteoraDammV2SwapEvent,
|
|
35
|
+
MeteoraPoolsAddLiquidityEvent,
|
|
36
|
+
MeteoraPoolsRemoveLiquidityEvent,
|
|
37
|
+
MeteoraPoolsSwapEvent,
|
|
38
|
+
OrcaWhirlpoolLiquidityDecreasedEvent,
|
|
39
|
+
OrcaWhirlpoolLiquidityIncreasedEvent,
|
|
40
|
+
OrcaWhirlpoolSwapEvent,
|
|
41
|
+
BonkTradeEvent,
|
|
42
|
+
)
|
|
43
|
+
from .grpc_types import EventType
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _merge_generic(base: Any, inner: Any) -> None:
|
|
47
|
+
for f in dataclasses.fields(type(base)):
|
|
48
|
+
setattr(base, f.name, getattr(inner, f.name))
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def merge_pumpfun_trade(base: PumpFunTradeEvent, inner: PumpFunTradeEvent) -> None:
|
|
52
|
+
base.mint = inner.mint
|
|
53
|
+
base.sol_amount = inner.sol_amount
|
|
54
|
+
base.token_amount = inner.token_amount
|
|
55
|
+
base.is_buy = inner.is_buy
|
|
56
|
+
base.user = inner.user
|
|
57
|
+
base.timestamp = inner.timestamp
|
|
58
|
+
base.virtual_sol_reserves = inner.virtual_sol_reserves
|
|
59
|
+
base.virtual_token_reserves = inner.virtual_token_reserves
|
|
60
|
+
base.real_sol_reserves = inner.real_sol_reserves
|
|
61
|
+
base.real_token_reserves = inner.real_token_reserves
|
|
62
|
+
base.fee_recipient = inner.fee_recipient
|
|
63
|
+
base.fee_basis_points = inner.fee_basis_points
|
|
64
|
+
base.fee = inner.fee
|
|
65
|
+
base.creator = inner.creator
|
|
66
|
+
base.creator_fee_basis_points = inner.creator_fee_basis_points
|
|
67
|
+
base.creator_fee = inner.creator_fee
|
|
68
|
+
base.track_volume = inner.track_volume
|
|
69
|
+
base.total_unclaimed_tokens = inner.total_unclaimed_tokens
|
|
70
|
+
base.total_claimed_tokens = inner.total_claimed_tokens
|
|
71
|
+
base.current_sol_volume = inner.current_sol_volume
|
|
72
|
+
base.last_update_timestamp = inner.last_update_timestamp
|
|
73
|
+
base.ix_name = inner.ix_name
|
|
74
|
+
base.is_created_buy = inner.is_created_buy
|
|
75
|
+
base.mayhem_mode = inner.mayhem_mode
|
|
76
|
+
base.cashback_fee_basis_points = inner.cashback_fee_basis_points
|
|
77
|
+
base.cashback = inner.cashback
|
|
78
|
+
base.is_cashback_coin = inner.is_cashback_coin
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def merge_pumpfun_create(base: PumpFunCreateEvent, inner: PumpFunCreateEvent) -> None:
|
|
82
|
+
base.name = inner.name
|
|
83
|
+
base.symbol = inner.symbol
|
|
84
|
+
base.uri = inner.uri
|
|
85
|
+
base.mint = inner.mint
|
|
86
|
+
base.bonding_curve = inner.bonding_curve
|
|
87
|
+
base.user = inner.user
|
|
88
|
+
base.creator = inner.creator
|
|
89
|
+
base.timestamp = inner.timestamp
|
|
90
|
+
base.virtual_token_reserves = inner.virtual_token_reserves
|
|
91
|
+
base.virtual_sol_reserves = inner.virtual_sol_reserves
|
|
92
|
+
base.real_token_reserves = inner.real_token_reserves
|
|
93
|
+
base.token_total_supply = inner.token_total_supply
|
|
94
|
+
base.token_program = inner.token_program
|
|
95
|
+
base.is_mayhem_mode = inner.is_mayhem_mode
|
|
96
|
+
base.is_cashback_enabled = inner.is_cashback_enabled
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def merge_pumpfun_migrate(base: PumpFunMigrateEvent, inner: PumpFunMigrateEvent) -> None:
|
|
100
|
+
base.user = inner.user
|
|
101
|
+
base.mint = inner.mint
|
|
102
|
+
base.mint_amount = inner.mint_amount
|
|
103
|
+
base.sol_amount = inner.sol_amount
|
|
104
|
+
base.pool_migration_fee = inner.pool_migration_fee
|
|
105
|
+
base.bonding_curve = inner.bonding_curve
|
|
106
|
+
base.timestamp = inner.timestamp
|
|
107
|
+
base.pool = inner.pool
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def merge_dex_events(base: DexEvent, inner: DexEvent) -> None:
|
|
111
|
+
"""将 ``inner`` 合并进 ``base``(就地修改 ``base.data``)。"""
|
|
112
|
+
bd = base.data
|
|
113
|
+
ind = inner.data
|
|
114
|
+
|
|
115
|
+
if isinstance(bd, PumpFunTradeEvent) and isinstance(ind, PumpFunTradeEvent):
|
|
116
|
+
if base.type in (
|
|
117
|
+
EventType.PUMP_FUN_TRADE,
|
|
118
|
+
EventType.PUMP_FUN_BUY,
|
|
119
|
+
EventType.PUMP_FUN_SELL,
|
|
120
|
+
EventType.PUMP_FUN_BUY_EXACT_SOL_IN,
|
|
121
|
+
) and inner.type in (
|
|
122
|
+
EventType.PUMP_FUN_TRADE,
|
|
123
|
+
EventType.PUMP_FUN_BUY,
|
|
124
|
+
EventType.PUMP_FUN_SELL,
|
|
125
|
+
EventType.PUMP_FUN_BUY_EXACT_SOL_IN,
|
|
126
|
+
):
|
|
127
|
+
merge_pumpfun_trade(bd, ind)
|
|
128
|
+
base.type = inner.type
|
|
129
|
+
return
|
|
130
|
+
|
|
131
|
+
if isinstance(bd, PumpFunCreateEvent) and isinstance(ind, PumpFunCreateEvent):
|
|
132
|
+
merge_pumpfun_create(bd, ind)
|
|
133
|
+
return
|
|
134
|
+
|
|
135
|
+
if isinstance(bd, PumpFunCreateV2TokenEvent) and isinstance(ind, PumpFunCreateV2TokenEvent):
|
|
136
|
+
_merge_generic(bd, ind)
|
|
137
|
+
return
|
|
138
|
+
|
|
139
|
+
if isinstance(bd, PumpFunMigrateEvent) and isinstance(ind, PumpFunMigrateEvent):
|
|
140
|
+
merge_pumpfun_migrate(bd, ind)
|
|
141
|
+
return
|
|
142
|
+
|
|
143
|
+
if isinstance(bd, PumpSwapBuyEvent) and isinstance(ind, PumpSwapBuyEvent):
|
|
144
|
+
_merge_generic(bd, ind)
|
|
145
|
+
return
|
|
146
|
+
if isinstance(bd, PumpSwapSellEvent) and isinstance(ind, PumpSwapSellEvent):
|
|
147
|
+
_merge_generic(bd, ind)
|
|
148
|
+
return
|
|
149
|
+
if isinstance(bd, PumpSwapCreatePoolEvent) and isinstance(ind, PumpSwapCreatePoolEvent):
|
|
150
|
+
_merge_generic(bd, ind)
|
|
151
|
+
return
|
|
152
|
+
if isinstance(bd, PumpSwapLiquidityAddedEvent) and isinstance(ind, PumpSwapLiquidityAddedEvent):
|
|
153
|
+
_merge_generic(bd, ind)
|
|
154
|
+
return
|
|
155
|
+
if isinstance(bd, PumpSwapLiquidityRemovedEvent) and isinstance(ind, PumpSwapLiquidityRemovedEvent):
|
|
156
|
+
_merge_generic(bd, ind)
|
|
157
|
+
return
|
|
158
|
+
|
|
159
|
+
if isinstance(bd, RaydiumClmmSwapEvent) and isinstance(ind, RaydiumClmmSwapEvent):
|
|
160
|
+
_merge_generic(bd, ind)
|
|
161
|
+
return
|
|
162
|
+
if isinstance(bd, RaydiumClmmIncreaseLiquidityEvent) and isinstance(ind, RaydiumClmmIncreaseLiquidityEvent):
|
|
163
|
+
_merge_generic(bd, ind)
|
|
164
|
+
return
|
|
165
|
+
if isinstance(bd, RaydiumClmmDecreaseLiquidityEvent) and isinstance(ind, RaydiumClmmDecreaseLiquidityEvent):
|
|
166
|
+
_merge_generic(bd, ind)
|
|
167
|
+
return
|
|
168
|
+
if isinstance(bd, RaydiumClmmCreatePoolEvent) and isinstance(ind, RaydiumClmmCreatePoolEvent):
|
|
169
|
+
_merge_generic(bd, ind)
|
|
170
|
+
return
|
|
171
|
+
if isinstance(bd, RaydiumClmmCollectFeeEvent) and isinstance(ind, RaydiumClmmCollectFeeEvent):
|
|
172
|
+
_merge_generic(bd, ind)
|
|
173
|
+
return
|
|
174
|
+
|
|
175
|
+
if isinstance(bd, RaydiumCpmmSwapEvent) and isinstance(ind, RaydiumCpmmSwapEvent):
|
|
176
|
+
_merge_generic(bd, ind)
|
|
177
|
+
return
|
|
178
|
+
if isinstance(bd, RaydiumCpmmDepositEvent) and isinstance(ind, RaydiumCpmmDepositEvent):
|
|
179
|
+
_merge_generic(bd, ind)
|
|
180
|
+
return
|
|
181
|
+
if isinstance(bd, RaydiumCpmmWithdrawEvent) and isinstance(ind, RaydiumCpmmWithdrawEvent):
|
|
182
|
+
_merge_generic(bd, ind)
|
|
183
|
+
return
|
|
184
|
+
|
|
185
|
+
if isinstance(bd, RaydiumAmmV4SwapEvent) and isinstance(ind, RaydiumAmmV4SwapEvent):
|
|
186
|
+
_merge_generic(bd, ind)
|
|
187
|
+
return
|
|
188
|
+
if isinstance(bd, RaydiumAmmV4DepositEvent) and isinstance(ind, RaydiumAmmV4DepositEvent):
|
|
189
|
+
_merge_generic(bd, ind)
|
|
190
|
+
return
|
|
191
|
+
if isinstance(bd, RaydiumAmmV4WithdrawEvent) and isinstance(ind, RaydiumAmmV4WithdrawEvent):
|
|
192
|
+
_merge_generic(bd, ind)
|
|
193
|
+
return
|
|
194
|
+
|
|
195
|
+
if isinstance(bd, OrcaWhirlpoolSwapEvent) and isinstance(ind, OrcaWhirlpoolSwapEvent):
|
|
196
|
+
_merge_generic(bd, ind)
|
|
197
|
+
return
|
|
198
|
+
if isinstance(bd, OrcaWhirlpoolLiquidityIncreasedEvent) and isinstance(ind, OrcaWhirlpoolLiquidityIncreasedEvent):
|
|
199
|
+
_merge_generic(bd, ind)
|
|
200
|
+
return
|
|
201
|
+
if isinstance(bd, OrcaWhirlpoolLiquidityDecreasedEvent) and isinstance(ind, OrcaWhirlpoolLiquidityDecreasedEvent):
|
|
202
|
+
_merge_generic(bd, ind)
|
|
203
|
+
return
|
|
204
|
+
|
|
205
|
+
if isinstance(bd, MeteoraPoolsSwapEvent) and isinstance(ind, MeteoraPoolsSwapEvent):
|
|
206
|
+
_merge_generic(bd, ind)
|
|
207
|
+
return
|
|
208
|
+
if isinstance(bd, MeteoraPoolsAddLiquidityEvent) and isinstance(ind, MeteoraPoolsAddLiquidityEvent):
|
|
209
|
+
_merge_generic(bd, ind)
|
|
210
|
+
return
|
|
211
|
+
if isinstance(bd, MeteoraPoolsRemoveLiquidityEvent) and isinstance(ind, MeteoraPoolsRemoveLiquidityEvent):
|
|
212
|
+
_merge_generic(bd, ind)
|
|
213
|
+
return
|
|
214
|
+
|
|
215
|
+
if isinstance(bd, MeteoraDammV2SwapEvent) and isinstance(ind, MeteoraDammV2SwapEvent):
|
|
216
|
+
_merge_generic(bd, ind)
|
|
217
|
+
return
|
|
218
|
+
if isinstance(bd, MeteoraDammV2AddLiquidityEvent) and isinstance(ind, MeteoraDammV2AddLiquidityEvent):
|
|
219
|
+
_merge_generic(bd, ind)
|
|
220
|
+
return
|
|
221
|
+
if isinstance(bd, MeteoraDammV2RemoveLiquidityEvent) and isinstance(ind, MeteoraDammV2RemoveLiquidityEvent):
|
|
222
|
+
_merge_generic(bd, ind)
|
|
223
|
+
return
|
|
224
|
+
if isinstance(bd, MeteoraDammV2CreatePositionEvent) and isinstance(ind, MeteoraDammV2CreatePositionEvent):
|
|
225
|
+
_merge_generic(bd, ind)
|
|
226
|
+
return
|
|
227
|
+
if isinstance(bd, MeteoraDammV2ClosePositionEvent) and isinstance(ind, MeteoraDammV2ClosePositionEvent):
|
|
228
|
+
_merge_generic(bd, ind)
|
|
229
|
+
return
|
|
230
|
+
|
|
231
|
+
if isinstance(bd, BonkTradeEvent) and isinstance(ind, BonkTradeEvent):
|
|
232
|
+
_merge_generic(bd, ind)
|
|
233
|
+
return
|