sol-parser-sdk-python 0.5.7__py3-none-any.whl → 0.5.9__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 +34 -0
- sol_parser/account_dispatcher.py +98 -4
- sol_parser/account_fillers/meteora.py +10 -2
- sol_parser/account_fillers/raydium.py +9 -4
- sol_parser/account_fillers/raydium_launchlab.py +54 -0
- sol_parser/accounts/__init__.py +52 -2
- sol_parser/block_meta.py +29 -0
- sol_parser/dex_parsers.py +662 -69
- sol_parser/entries_decode.py +6 -80
- sol_parser/event_type_parity.py +4 -0
- sol_parser/event_types.py +269 -3
- sol_parser/grpc/subscribe_builder.py +8 -0
- sol_parser/grpc_client.py +114 -20
- sol_parser/grpc_instruction_parser.py +85 -26
- sol_parser/grpc_types.py +31 -0
- sol_parser/inner_instruction_parser.py +5 -7
- sol_parser/instructions.py +259 -53
- sol_parser/json_util.py +15 -1
- sol_parser/liquidity_snapshot.py +101 -0
- sol_parser/log_instr_dedup.py +56 -12
- sol_parser/merger.py +73 -85
- sol_parser/parser.py +11 -0
- sol_parser/pumpfun_fee_enrich.py +2 -0
- sol_parser/rpc_parser.py +30 -4
- sol_parser/simulation_route.py +233 -0
- sol_parser/stonkfun_registry.py +139 -0
- sol_parser/transaction_route.py +510 -0
- sol_parser/wire_transaction.py +172 -0
- {sol_parser_sdk_python-0.5.7.dist-info → sol_parser_sdk_python-0.5.9.dist-info}/METADATA +44 -9
- {sol_parser_sdk_python-0.5.7.dist-info → sol_parser_sdk_python-0.5.9.dist-info}/RECORD +32 -26
- {sol_parser_sdk_python-0.5.7.dist-info → sol_parser_sdk_python-0.5.9.dist-info}/WHEEL +1 -1
- {sol_parser_sdk_python-0.5.7.dist-info → sol_parser_sdk_python-0.5.9.dist-info}/entry_points.txt +0 -0
sol_parser/instructions.py
CHANGED
|
@@ -43,6 +43,7 @@ from .event_types import (
|
|
|
43
43
|
PumpFunCreateV2TokenEvent,
|
|
44
44
|
PumpFunTradeEvent,
|
|
45
45
|
PumpSwapBuyEvent,
|
|
46
|
+
PumpSwapCreatePoolEvent,
|
|
46
47
|
PumpSwapSellEvent,
|
|
47
48
|
MeteoraDlmmAddLiquidityEvent,
|
|
48
49
|
MeteoraDlmmClaimFeeEvent,
|
|
@@ -83,6 +84,7 @@ def _d(*xs: int) -> int:
|
|
|
83
84
|
_DISC_PUMPSWAP_BUY = _d(102, 6, 61, 18, 1, 218, 235, 234)
|
|
84
85
|
_DISC_PUMPSWAP_SELL = _d(51, 230, 133, 164, 1, 127, 131, 173)
|
|
85
86
|
_DISC_PUMPSWAP_BUY_EXACT_QUOTE_IN = _d(198, 46, 21, 82, 180, 217, 232, 112)
|
|
87
|
+
_DISC_PUMPSWAP_CREATE_POOL = _d(233, 146, 209, 142, 207, 104, 64, 188)
|
|
86
88
|
|
|
87
89
|
_DISC_DAMM_SWAP = _d(27, 60, 21, 213, 138, 170, 187, 147)
|
|
88
90
|
_DISC_DAMM_SWAP2 = _d(189, 66, 51, 168, 38, 80, 117, 153)
|
|
@@ -97,6 +99,50 @@ _DISC_METEORA_POOLS_ADD_LIQUIDITY = _d(181, 157, 89, 67, 143, 182, 52, 72)
|
|
|
97
99
|
_DISC_METEORA_POOLS_REMOVE_LIQUIDITY = _d(80, 85, 209, 72, 24, 206, 177, 108)
|
|
98
100
|
_DISC_METEORA_POOLS_CREATE_POOL = _d(95, 180, 10, 172, 84, 174, 232, 40)
|
|
99
101
|
|
|
102
|
+
_DISC_DLMM_ADD_LIQUIDITY = _d(181, 157, 89, 67, 143, 182, 52, 72)
|
|
103
|
+
_DISC_DLMM_ADD_LIQUIDITY2 = _d(228, 162, 78, 28, 70, 219, 116, 115)
|
|
104
|
+
_DISC_DLMM_CLAIM_FEE = _d(169, 32, 79, 137, 136, 232, 70, 137)
|
|
105
|
+
_DISC_DLMM_CLAIM_FEE2 = _d(112, 191, 101, 171, 28, 144, 127, 187)
|
|
106
|
+
_DISC_DLMM_CLOSE_POSITION = _d(123, 134, 81, 0, 49, 68, 98, 98)
|
|
107
|
+
_DISC_DLMM_CLOSE_POSITION2 = _d(174, 90, 35, 115, 186, 40, 147, 226)
|
|
108
|
+
_DISC_DLMM_INITIALIZE_BIN_ARRAY = _d(35, 86, 19, 185, 78, 212, 75, 211)
|
|
109
|
+
_DISC_DLMM_INITIALIZE_LB_PAIR = _d(45, 154, 237, 210, 221, 15, 166, 92)
|
|
110
|
+
_DISC_DLMM_INITIALIZE_LB_PAIR2 = _d(73, 59, 36, 120, 237, 83, 108, 198)
|
|
111
|
+
_DISC_DLMM_INITIALIZE_POSITION = _d(219, 192, 234, 71, 190, 191, 102, 80)
|
|
112
|
+
_DISC_DLMM_INITIALIZE_POSITION2 = _d(143, 19, 242, 145, 213, 15, 104, 115)
|
|
113
|
+
_DISC_DLMM_INITIALIZE_POSITION_PDA = _d(46, 82, 125, 146, 85, 141, 228, 153)
|
|
114
|
+
_DISC_DLMM_REMOVE_LIQUIDITY = _d(80, 85, 209, 72, 24, 206, 177, 108)
|
|
115
|
+
_DISC_DLMM_REMOVE_LIQUIDITY2 = _d(230, 215, 82, 127, 241, 101, 227, 146)
|
|
116
|
+
_DISC_DLMM_SWAP = _d(248, 198, 158, 145, 225, 117, 135, 200)
|
|
117
|
+
_DISC_DLMM_SWAP2 = _d(65, 75, 63, 76, 235, 91, 91, 136)
|
|
118
|
+
_DISC_DLMM_SWAP_EXACT_OUT = _d(250, 73, 101, 33, 38, 207, 75, 184)
|
|
119
|
+
_DISC_DLMM_SWAP_EXACT_OUT2 = _d(43, 215, 247, 132, 137, 60, 243, 81)
|
|
120
|
+
_DISC_DLMM_SWAP_WITH_PRICE_IMPACT = _d(56, 173, 230, 208, 173, 228, 156, 205)
|
|
121
|
+
_DISC_DLMM_SWAP_WITH_PRICE_IMPACT2 = _d(74, 98, 192, 214, 177, 51, 75, 51)
|
|
122
|
+
|
|
123
|
+
_DLMM_INSTRUCTION_DISCS = (
|
|
124
|
+
_DISC_DLMM_INITIALIZE_LB_PAIR,
|
|
125
|
+
_DISC_DLMM_INITIALIZE_LB_PAIR2,
|
|
126
|
+
_DISC_DLMM_INITIALIZE_BIN_ARRAY,
|
|
127
|
+
_DISC_DLMM_ADD_LIQUIDITY,
|
|
128
|
+
_DISC_DLMM_ADD_LIQUIDITY2,
|
|
129
|
+
_DISC_DLMM_REMOVE_LIQUIDITY,
|
|
130
|
+
_DISC_DLMM_REMOVE_LIQUIDITY2,
|
|
131
|
+
_DISC_DLMM_INITIALIZE_POSITION,
|
|
132
|
+
_DISC_DLMM_INITIALIZE_POSITION2,
|
|
133
|
+
_DISC_DLMM_INITIALIZE_POSITION_PDA,
|
|
134
|
+
_DISC_DLMM_SWAP,
|
|
135
|
+
_DISC_DLMM_SWAP2,
|
|
136
|
+
_DISC_DLMM_SWAP_EXACT_OUT,
|
|
137
|
+
_DISC_DLMM_SWAP_EXACT_OUT2,
|
|
138
|
+
_DISC_DLMM_SWAP_WITH_PRICE_IMPACT,
|
|
139
|
+
_DISC_DLMM_SWAP_WITH_PRICE_IMPACT2,
|
|
140
|
+
_DISC_DLMM_CLAIM_FEE,
|
|
141
|
+
_DISC_DLMM_CLAIM_FEE2,
|
|
142
|
+
_DISC_DLMM_CLOSE_POSITION,
|
|
143
|
+
_DISC_DLMM_CLOSE_POSITION2,
|
|
144
|
+
)
|
|
145
|
+
|
|
100
146
|
_DISC_CLMM_SWAP = _d(248, 198, 158, 145, 225, 117, 135, 200)
|
|
101
147
|
_DISC_CLMM_SWAP_V2 = _d(43, 4, 237, 11, 26, 201, 30, 98)
|
|
102
148
|
_DISC_CLMM_INC_LIQ = _d(133, 29, 89, 223, 69, 238, 176, 10)
|
|
@@ -322,9 +368,10 @@ def normal_instruction_data_may_parse(program_id: str, instruction_data: bytes)
|
|
|
322
368
|
if not instruction_data:
|
|
323
369
|
return False
|
|
324
370
|
if program_id == RAYDIUM_AMM_V4_PROGRAM_ID:
|
|
325
|
-
return instruction_data[0] in (1, 3, 4, 7, 9, 11)
|
|
371
|
+
return instruction_data[0] in (1, 3, 4, 7, 9, 11, 16, 17)
|
|
326
372
|
if program_id == METEORA_DLMM_PROGRAM_ID:
|
|
327
|
-
|
|
373
|
+
disc = _disc8(instruction_data)
|
|
374
|
+
return disc in _DLMM_INSTRUCTION_DISCS if disc is not None else False
|
|
328
375
|
disc = _disc8(instruction_data)
|
|
329
376
|
if disc is None:
|
|
330
377
|
return False
|
|
@@ -345,7 +392,7 @@ def normal_instruction_data_may_parse(program_id: str, instruction_data: bytes)
|
|
|
345
392
|
return disc in (
|
|
346
393
|
_DISC_PUMPSWAP_BUY,
|
|
347
394
|
_DISC_PUMPSWAP_SELL,
|
|
348
|
-
|
|
395
|
+
_DISC_PUMPSWAP_CREATE_POOL,
|
|
349
396
|
_DISC_PUMPSWAP_BUY_EXACT_QUOTE_IN,
|
|
350
397
|
_d(242, 35, 198, 137, 82, 225, 242, 182),
|
|
351
398
|
_d(183, 18, 70, 156, 148, 109, 161, 34),
|
|
@@ -764,6 +811,12 @@ def _parse_pumpfun_create_v2(data: bytes, accounts: List[str], meta: EventMetada
|
|
|
764
811
|
is_mayhem_mode = data[offset] == 1
|
|
765
812
|
offset += 1
|
|
766
813
|
is_cashback_enabled = data[offset] == 1 if offset < len(data) else False
|
|
814
|
+
if offset < len(data):
|
|
815
|
+
offset += 1
|
|
816
|
+
creator_fee_bps = struct.unpack_from("<Q", data, offset)[0] if offset + 8 <= len(data) else 0
|
|
817
|
+
if offset + 8 <= len(data):
|
|
818
|
+
offset += 8
|
|
819
|
+
is_holder_reward = data[offset] == 1 if offset < len(data) else False
|
|
767
820
|
|
|
768
821
|
return DexEvent(
|
|
769
822
|
type=EventType.PUMP_FUN_CREATE_V2,
|
|
@@ -796,6 +849,8 @@ def _parse_pumpfun_create_v2(data: bytes, accounts: List[str], meta: EventMetada
|
|
|
796
849
|
token_total_supply=0,
|
|
797
850
|
is_mayhem_mode=is_mayhem_mode,
|
|
798
851
|
is_cashback_enabled=is_cashback_enabled,
|
|
852
|
+
creator_fee_bps=creator_fee_bps,
|
|
853
|
+
is_holder_reward=is_holder_reward,
|
|
799
854
|
quote_mint=_get_account_safe(accounts, 16) or Z,
|
|
800
855
|
quote_vault=_get_account_safe(accounts, 17),
|
|
801
856
|
quote_token_program=_get_account_safe(accounts, 18),
|
|
@@ -906,6 +961,38 @@ def parse_pumpswap_instruction(
|
|
|
906
961
|
fill_sell_tail(ev)
|
|
907
962
|
return DexEvent(type=EventType.PUMP_SWAP_SELL, data=ev)
|
|
908
963
|
|
|
964
|
+
if discriminator == _DISC_PUMPSWAP_CREATE_POOL:
|
|
965
|
+
if len(accounts) < 8:
|
|
966
|
+
return None
|
|
967
|
+
return DexEvent(
|
|
968
|
+
type=EventType.PUMP_SWAP_CREATE_POOL,
|
|
969
|
+
data=PumpSwapCreatePoolEvent(
|
|
970
|
+
metadata=meta,
|
|
971
|
+
index=struct.unpack_from("<H", payload, 0)[0] if len(payload) >= 2 else 0,
|
|
972
|
+
pool=_get_account_safe(accounts, 0),
|
|
973
|
+
creator=_get_account_safe(accounts, 2),
|
|
974
|
+
base_mint=_get_account_safe(accounts, 3),
|
|
975
|
+
quote_mint=_get_account_safe(accounts, 4),
|
|
976
|
+
base_amount_in=struct.unpack_from("<Q", payload, 2)[0] if len(payload) >= 10 else 0,
|
|
977
|
+
quote_amount_in=struct.unpack_from("<Q", payload, 10)[0] if len(payload) >= 18 else 0,
|
|
978
|
+
lp_mint=_get_account_safe(accounts, 5),
|
|
979
|
+
user_base_token_account=_get_account_safe(accounts, 6),
|
|
980
|
+
user_quote_token_account=_get_account_safe(accounts, 7),
|
|
981
|
+
coin_creator=(
|
|
982
|
+
base58.b58encode(payload[18:50]).decode("ascii")
|
|
983
|
+
if len(payload) >= 50
|
|
984
|
+
else Z
|
|
985
|
+
),
|
|
986
|
+
is_mayhem_mode=len(payload) > 50 and payload[50] == 1,
|
|
987
|
+
is_cashback_coin=len(payload) > 51 and payload[51] == 1,
|
|
988
|
+
creator_fee_bps=(
|
|
989
|
+
struct.unpack_from("<Q", payload, 52)[0] if len(payload) >= 60 else 0
|
|
990
|
+
),
|
|
991
|
+
can_edit_creator_fee=len(payload) > 60 and payload[60] == 1,
|
|
992
|
+
is_holder_reward=len(payload) > 61 and payload[61] == 1,
|
|
993
|
+
),
|
|
994
|
+
)
|
|
995
|
+
|
|
909
996
|
return None
|
|
910
997
|
|
|
911
998
|
|
|
@@ -1024,94 +1111,124 @@ def parse_meteora_dlmm_instruction(
|
|
|
1024
1111
|
block_time_us: Optional[int],
|
|
1025
1112
|
grpc_recv_us: int,
|
|
1026
1113
|
) -> Optional[DexEvent]:
|
|
1027
|
-
if
|
|
1114
|
+
if len(data) < 8 or not accounts:
|
|
1028
1115
|
return None
|
|
1029
|
-
|
|
1030
|
-
payload = data[
|
|
1116
|
+
discriminator = struct.unpack_from("<Q", data, 0)[0]
|
|
1117
|
+
payload = data[8:]
|
|
1031
1118
|
meta = _make_meta(signature, slot, tx_index, block_time_us, grpc_recv_us)
|
|
1032
|
-
pool = accounts[0]
|
|
1033
1119
|
|
|
1034
|
-
if
|
|
1120
|
+
if discriminator == _DISC_DLMM_INITIALIZE_LB_PAIR:
|
|
1035
1121
|
if len(payload) < 6:
|
|
1036
1122
|
return None
|
|
1123
|
+
pool = _get_account_safe(accounts, 0)
|
|
1037
1124
|
return DexEvent(
|
|
1038
1125
|
type=EventType.METEORA_DLMM_INITIALIZE_POOL,
|
|
1039
1126
|
data=MeteoraDlmmInitializePoolEvent(
|
|
1040
1127
|
metadata=meta,
|
|
1041
1128
|
pool=pool,
|
|
1042
|
-
creator=_get_account_safe(accounts,
|
|
1129
|
+
creator=_get_account_safe(accounts, 8),
|
|
1043
1130
|
active_bin_id=struct.unpack_from("<i", payload, 0)[0],
|
|
1044
1131
|
bin_step=struct.unpack_from("<H", payload, 4)[0],
|
|
1045
1132
|
),
|
|
1046
1133
|
)
|
|
1047
1134
|
|
|
1048
|
-
if
|
|
1135
|
+
if discriminator == _DISC_DLMM_INITIALIZE_LB_PAIR2:
|
|
1136
|
+
if len(payload) < 4:
|
|
1137
|
+
return None
|
|
1138
|
+
pool = _get_account_safe(accounts, 0)
|
|
1139
|
+
return DexEvent(
|
|
1140
|
+
type=EventType.METEORA_DLMM_INITIALIZE_POOL,
|
|
1141
|
+
data=MeteoraDlmmInitializePoolEvent(
|
|
1142
|
+
metadata=meta,
|
|
1143
|
+
pool=pool,
|
|
1144
|
+
creator=_get_account_safe(accounts, 8),
|
|
1145
|
+
active_bin_id=struct.unpack_from("<i", payload, 0)[0],
|
|
1146
|
+
bin_step=0,
|
|
1147
|
+
),
|
|
1148
|
+
)
|
|
1149
|
+
|
|
1150
|
+
if discriminator == _DISC_DLMM_INITIALIZE_BIN_ARRAY:
|
|
1049
1151
|
if len(payload) < 8:
|
|
1050
1152
|
return None
|
|
1153
|
+
pool = _get_account_safe(accounts, 0)
|
|
1051
1154
|
return DexEvent(
|
|
1052
1155
|
type=EventType.METEORA_DLMM_INITIALIZE_BIN_ARRAY,
|
|
1053
1156
|
data=MeteoraDlmmInitializeBinArrayEvent(
|
|
1054
1157
|
metadata=meta,
|
|
1055
1158
|
pool=pool,
|
|
1056
1159
|
bin_array=_get_account_safe(accounts, 1),
|
|
1057
|
-
index=struct.unpack_from("<
|
|
1160
|
+
index=struct.unpack_from("<q", payload, 0)[0],
|
|
1058
1161
|
),
|
|
1059
1162
|
)
|
|
1060
1163
|
|
|
1061
|
-
if
|
|
1062
|
-
|
|
1063
|
-
|
|
1164
|
+
if discriminator in (_DISC_DLMM_ADD_LIQUIDITY, _DISC_DLMM_ADD_LIQUIDITY2):
|
|
1165
|
+
pool = _get_account_safe(accounts, 1)
|
|
1166
|
+
sender_index = 9 if discriminator == _DISC_DLMM_ADD_LIQUIDITY2 else 11
|
|
1064
1167
|
return DexEvent(
|
|
1065
1168
|
type=EventType.METEORA_DLMM_ADD_LIQUIDITY,
|
|
1066
1169
|
data=MeteoraDlmmAddLiquidityEvent(
|
|
1067
1170
|
metadata=meta,
|
|
1068
1171
|
pool=pool,
|
|
1069
|
-
from_addr=_get_account_safe(accounts,
|
|
1070
|
-
position=_get_account_safe(accounts,
|
|
1172
|
+
from_addr=_get_account_safe(accounts, sender_index),
|
|
1173
|
+
position=_get_account_safe(accounts, 0),
|
|
1071
1174
|
amounts=[0, 0],
|
|
1072
1175
|
active_bin_id=0,
|
|
1073
1176
|
),
|
|
1074
1177
|
)
|
|
1075
1178
|
|
|
1076
|
-
if
|
|
1077
|
-
|
|
1078
|
-
|
|
1179
|
+
if discriminator in (_DISC_DLMM_REMOVE_LIQUIDITY, _DISC_DLMM_REMOVE_LIQUIDITY2):
|
|
1180
|
+
pool = _get_account_safe(accounts, 1)
|
|
1181
|
+
sender_index = 9 if discriminator == _DISC_DLMM_REMOVE_LIQUIDITY2 else 11
|
|
1079
1182
|
return DexEvent(
|
|
1080
1183
|
type=EventType.METEORA_DLMM_REMOVE_LIQUIDITY,
|
|
1081
1184
|
data=MeteoraDlmmRemoveLiquidityEvent(
|
|
1082
1185
|
metadata=meta,
|
|
1083
1186
|
pool=pool,
|
|
1084
|
-
from_addr=_get_account_safe(accounts,
|
|
1085
|
-
position=_get_account_safe(accounts,
|
|
1187
|
+
from_addr=_get_account_safe(accounts, sender_index),
|
|
1188
|
+
position=_get_account_safe(accounts, 0),
|
|
1086
1189
|
amounts=[0, 0],
|
|
1087
1190
|
active_bin_id=0,
|
|
1088
1191
|
),
|
|
1089
1192
|
)
|
|
1090
1193
|
|
|
1091
|
-
if
|
|
1194
|
+
if discriminator in (
|
|
1195
|
+
_DISC_DLMM_INITIALIZE_POSITION,
|
|
1196
|
+
_DISC_DLMM_INITIALIZE_POSITION2,
|
|
1197
|
+
_DISC_DLMM_INITIALIZE_POSITION_PDA,
|
|
1198
|
+
):
|
|
1092
1199
|
if len(payload) < 8:
|
|
1093
1200
|
return None
|
|
1201
|
+
lower_bin_id, width = struct.unpack_from("<ii", payload, 0)
|
|
1202
|
+
if width < 0:
|
|
1203
|
+
return None
|
|
1204
|
+
pda = discriminator == _DISC_DLMM_INITIALIZE_POSITION_PDA
|
|
1205
|
+
position_index, pool_index, owner_index = (2, 3, 4) if pda else (1, 2, 3)
|
|
1094
1206
|
return DexEvent(
|
|
1095
1207
|
type=EventType.METEORA_DLMM_CREATE_POSITION,
|
|
1096
1208
|
data=MeteoraDlmmCreatePositionEvent(
|
|
1097
1209
|
metadata=meta,
|
|
1098
|
-
pool=
|
|
1099
|
-
position=_get_account_safe(accounts,
|
|
1100
|
-
owner=_get_account_safe(accounts,
|
|
1101
|
-
lower_bin_id=
|
|
1102
|
-
width=
|
|
1210
|
+
pool=_get_account_safe(accounts, pool_index),
|
|
1211
|
+
position=_get_account_safe(accounts, position_index),
|
|
1212
|
+
owner=_get_account_safe(accounts, owner_index),
|
|
1213
|
+
lower_bin_id=lower_bin_id,
|
|
1214
|
+
width=width,
|
|
1103
1215
|
),
|
|
1104
1216
|
)
|
|
1105
1217
|
|
|
1106
|
-
if
|
|
1107
|
-
if len(payload) <
|
|
1218
|
+
if discriminator in (_DISC_DLMM_SWAP, _DISC_DLMM_SWAP2):
|
|
1219
|
+
if len(payload) < 8:
|
|
1108
1220
|
return None
|
|
1221
|
+
min_out = struct.unpack_from("<Q", payload, 8)[0] if len(payload) >= 16 else 0
|
|
1222
|
+
pool = _get_account_safe(accounts, 0)
|
|
1109
1223
|
return DexEvent(
|
|
1110
1224
|
type=EventType.METEORA_DLMM_SWAP,
|
|
1111
1225
|
data=MeteoraDlmmSwapEvent(
|
|
1112
1226
|
metadata=meta,
|
|
1113
1227
|
pool=pool,
|
|
1114
|
-
from_addr=_get_account_safe(accounts,
|
|
1228
|
+
from_addr=_get_account_safe(accounts, 10),
|
|
1229
|
+
user_token_in=_get_account_safe(accounts, 4),
|
|
1230
|
+
user_token_out=_get_account_safe(accounts, 5),
|
|
1231
|
+
min_amount_out=min_out,
|
|
1115
1232
|
start_bin_id=0,
|
|
1116
1233
|
end_bin_id=0,
|
|
1117
1234
|
amount_in=struct.unpack_from("<Q", payload, 0)[0],
|
|
@@ -1124,27 +1241,65 @@ def parse_meteora_dlmm_instruction(
|
|
|
1124
1241
|
),
|
|
1125
1242
|
)
|
|
1126
1243
|
|
|
1127
|
-
if
|
|
1244
|
+
if discriminator in (
|
|
1245
|
+
_DISC_DLMM_SWAP_EXACT_OUT,
|
|
1246
|
+
_DISC_DLMM_SWAP_EXACT_OUT2,
|
|
1247
|
+
_DISC_DLMM_SWAP_WITH_PRICE_IMPACT,
|
|
1248
|
+
_DISC_DLMM_SWAP_WITH_PRICE_IMPACT2,
|
|
1249
|
+
):
|
|
1250
|
+
exact_out = discriminator in (_DISC_DLMM_SWAP_EXACT_OUT, _DISC_DLMM_SWAP_EXACT_OUT2)
|
|
1251
|
+
if len(payload) < (16 if exact_out else 8):
|
|
1252
|
+
return None
|
|
1253
|
+
amount_out = 0
|
|
1254
|
+
if exact_out:
|
|
1255
|
+
amount_out = struct.unpack_from("<Q", payload, 8)[0]
|
|
1256
|
+
pool = _get_account_safe(accounts, 0)
|
|
1257
|
+
return DexEvent(
|
|
1258
|
+
type=EventType.METEORA_DLMM_SWAP,
|
|
1259
|
+
data=MeteoraDlmmSwapEvent(
|
|
1260
|
+
metadata=meta,
|
|
1261
|
+
pool=pool,
|
|
1262
|
+
from_addr=_get_account_safe(accounts, 10),
|
|
1263
|
+
user_token_in=_get_account_safe(accounts, 4),
|
|
1264
|
+
user_token_out=_get_account_safe(accounts, 5),
|
|
1265
|
+
min_amount_out=0,
|
|
1266
|
+
start_bin_id=0,
|
|
1267
|
+
end_bin_id=0,
|
|
1268
|
+
amount_in=struct.unpack_from("<Q", payload, 0)[0],
|
|
1269
|
+
amount_out=amount_out,
|
|
1270
|
+
swap_for_y=False,
|
|
1271
|
+
fee=0,
|
|
1272
|
+
protocol_fee=0,
|
|
1273
|
+
fee_bps="0",
|
|
1274
|
+
host_fee=0,
|
|
1275
|
+
),
|
|
1276
|
+
)
|
|
1277
|
+
|
|
1278
|
+
if discriminator in (_DISC_DLMM_CLAIM_FEE, _DISC_DLMM_CLAIM_FEE2):
|
|
1279
|
+
pool = _get_account_safe(accounts, 0)
|
|
1280
|
+
owner_index = 2 if discriminator == _DISC_DLMM_CLAIM_FEE2 else 4
|
|
1128
1281
|
return DexEvent(
|
|
1129
1282
|
type=EventType.METEORA_DLMM_CLAIM_FEE,
|
|
1130
1283
|
data=MeteoraDlmmClaimFeeEvent(
|
|
1131
1284
|
metadata=meta,
|
|
1132
1285
|
pool=pool,
|
|
1133
1286
|
position=_get_account_safe(accounts, 1),
|
|
1134
|
-
owner=_get_account_safe(accounts,
|
|
1287
|
+
owner=_get_account_safe(accounts, owner_index),
|
|
1135
1288
|
fee_x=0,
|
|
1136
1289
|
fee_y=0,
|
|
1137
1290
|
),
|
|
1138
1291
|
)
|
|
1139
1292
|
|
|
1140
|
-
if
|
|
1293
|
+
if discriminator in (_DISC_DLMM_CLOSE_POSITION, _DISC_DLMM_CLOSE_POSITION2):
|
|
1294
|
+
position = _get_account_safe(accounts, 0)
|
|
1295
|
+
v2 = discriminator == _DISC_DLMM_CLOSE_POSITION2
|
|
1141
1296
|
return DexEvent(
|
|
1142
1297
|
type=EventType.METEORA_DLMM_CLOSE_POSITION,
|
|
1143
1298
|
data=MeteoraDlmmClosePositionEvent(
|
|
1144
1299
|
metadata=meta,
|
|
1145
|
-
pool=
|
|
1146
|
-
position=
|
|
1147
|
-
owner=_get_account_safe(accounts,
|
|
1300
|
+
pool=Z if v2 else _get_account_safe(accounts, 1),
|
|
1301
|
+
position=position,
|
|
1302
|
+
owner=_get_account_safe(accounts, 1 if v2 else 4),
|
|
1148
1303
|
),
|
|
1149
1304
|
)
|
|
1150
1305
|
|
|
@@ -1486,7 +1641,7 @@ def parse_raydium_cpmm_instruction(
|
|
|
1486
1641
|
return None
|
|
1487
1642
|
return legacy_dict_to_dex_event({"RaydiumCpmmSwap": {
|
|
1488
1643
|
"metadata": meta,
|
|
1489
|
-
"pool_id":
|
|
1644
|
+
"pool_id": _get_account_safe(accounts, 3),
|
|
1490
1645
|
"input_amount": 0, "output_amount": 0,
|
|
1491
1646
|
"input_vault_before": 0, "output_vault_before": 0,
|
|
1492
1647
|
"input_transfer_fee": 0, "output_transfer_fee": 0,
|
|
@@ -1497,7 +1652,7 @@ def parse_raydium_cpmm_instruction(
|
|
|
1497
1652
|
return None
|
|
1498
1653
|
return legacy_dict_to_dex_event({"RaydiumCpmmSwap": {
|
|
1499
1654
|
"metadata": meta,
|
|
1500
|
-
"pool_id":
|
|
1655
|
+
"pool_id": _get_account_safe(accounts, 3),
|
|
1501
1656
|
"input_amount": 0, "output_amount": 0,
|
|
1502
1657
|
"input_vault_before": 0, "output_vault_before": 0,
|
|
1503
1658
|
"input_transfer_fee": 0, "output_transfer_fee": 0,
|
|
@@ -1555,21 +1710,35 @@ def parse_raydium_amm_v4_instruction(
|
|
|
1555
1710
|
instr_type = data[0]
|
|
1556
1711
|
meta = _make_meta(signature, slot, tx_index, block_time_us, grpc_recv_us)
|
|
1557
1712
|
|
|
1558
|
-
if instr_type in (9, 11): # SwapBaseIn / SwapBaseOut
|
|
1713
|
+
if instr_type in (9, 11, 16, 17): # SwapBaseIn / SwapBaseOut
|
|
1714
|
+
if len(data) < 17:
|
|
1715
|
+
return None
|
|
1716
|
+
modern = instr_type in (16,17)
|
|
1717
|
+
if modern and len(accounts)<8:return None
|
|
1718
|
+
first, second = struct.unpack_from("<QQ", data, 1)
|
|
1719
|
+
shift = 1 if len(accounts) == 17 else 0
|
|
1720
|
+
def g(index: int) -> str:
|
|
1721
|
+
if modern:
|
|
1722
|
+
index = {0:0,1:1,2:2,5:3,6:4,15:5,16:6,17:7}.get(index,-1)
|
|
1723
|
+
else:
|
|
1724
|
+
index = index-shift if index>=5 else index
|
|
1725
|
+
return _get_account_safe(accounts,index)
|
|
1559
1726
|
return legacy_dict_to_dex_event({"RaydiumAmmV4Swap": {
|
|
1560
1727
|
"metadata": meta,
|
|
1561
1728
|
"amm": _get_account_safe(accounts, 1),
|
|
1562
|
-
"user_source_owner":
|
|
1563
|
-
"amount_in":
|
|
1564
|
-
"
|
|
1565
|
-
"
|
|
1566
|
-
"
|
|
1567
|
-
"
|
|
1568
|
-
"
|
|
1569
|
-
"
|
|
1570
|
-
"
|
|
1571
|
-
"
|
|
1572
|
-
"
|
|
1729
|
+
"user_source_owner": g(17),
|
|
1730
|
+
"amount_in": first if instr_type in (9,16) else 0,
|
|
1731
|
+
"minimum_amount_out": second if instr_type in (9,16) else 0,
|
|
1732
|
+
"max_amount_in": first if instr_type in (11,17) else 0,
|
|
1733
|
+
"amount_out": second if instr_type in (11,17) else 0,
|
|
1734
|
+
"token_program": g(0), "amm_authority": g(2), "amm_open_orders": g(3),
|
|
1735
|
+
"pool_coin_token_account": g(5), "pool_pc_token_account": g(6),
|
|
1736
|
+
"serum_program": g(7), "serum_market": g(8), "serum_bids": g(9),
|
|
1737
|
+
"serum_asks": g(10), "serum_event_queue": g(11),
|
|
1738
|
+
"serum_coin_vault_account": g(12), "serum_pc_vault_account": g(13),
|
|
1739
|
+
"serum_vault_signer": g(14),
|
|
1740
|
+
"user_source_token_account": g(15),
|
|
1741
|
+
"user_destination_token_account": g(16),
|
|
1573
1742
|
}})
|
|
1574
1743
|
|
|
1575
1744
|
return None
|
|
@@ -1599,9 +1768,10 @@ def parse_orca_whirlpool_instruction(
|
|
|
1599
1768
|
sqrt_price_limit = int.from_bytes(data[24:40], "little")
|
|
1600
1769
|
amount_specified_is_input = data[40] != 0
|
|
1601
1770
|
a_to_b = data[41] != 0
|
|
1771
|
+
whirlpool_index = 4 if discriminator == _DISC_ORCA_SWAP_V2 else 2
|
|
1602
1772
|
return legacy_dict_to_dex_event({"OrcaWhirlpoolSwap": {
|
|
1603
1773
|
"metadata": meta,
|
|
1604
|
-
"whirlpool": _get_account_safe(accounts,
|
|
1774
|
+
"whirlpool": _get_account_safe(accounts, whirlpool_index),
|
|
1605
1775
|
"a_to_b": a_to_b,
|
|
1606
1776
|
"pre_sqrt_price": str(sqrt_price_limit), "post_sqrt_price": "0",
|
|
1607
1777
|
"input_amount": amount if amount_specified_is_input else 0,
|
|
@@ -1679,7 +1849,7 @@ def parse_raydium_launchlab_instruction(
|
|
|
1679
1849
|
payload = data[8:]
|
|
1680
1850
|
|
|
1681
1851
|
if discriminator == _DISC_RAYDIUM_LAUNCHLAB_TRADE:
|
|
1682
|
-
if len(payload)
|
|
1852
|
+
if len(payload) != 139 or payload[136] > 1 or payload[137] > 2 or payload[138] > 1:
|
|
1683
1853
|
return None
|
|
1684
1854
|
return legacy_dict_to_dex_event({"RaydiumLaunchlabTrade": {
|
|
1685
1855
|
"metadata": meta,
|
|
@@ -1690,6 +1860,19 @@ def parse_raydium_launchlab_instruction(
|
|
|
1690
1860
|
"is_buy": payload[136] == 0,
|
|
1691
1861
|
"trade_direction": "Buy" if payload[136] == 0 else "Sell",
|
|
1692
1862
|
"exact_in": payload[138] == 1,
|
|
1863
|
+
"pool_status": ("Fund","Migrate","Trade")[payload[137]],
|
|
1864
|
+
"total_base_sell": _u64_payload(payload,32),
|
|
1865
|
+
"virtual_base": _u64_payload(payload,40),
|
|
1866
|
+
"virtual_quote": _u64_payload(payload,48),
|
|
1867
|
+
"real_base_before": _u64_payload(payload,56),
|
|
1868
|
+
"real_quote_before": _u64_payload(payload,64),
|
|
1869
|
+
"real_base_after": _u64_payload(payload,72),
|
|
1870
|
+
"real_quote_after": _u64_payload(payload,80),
|
|
1871
|
+
"protocol_fee": _u64_payload(payload,104),
|
|
1872
|
+
"platform_fee": _u64_payload(payload,112),
|
|
1873
|
+
"creator_fee": _u64_payload(payload,120),
|
|
1874
|
+
"share_fee": _u64_payload(payload,128),
|
|
1875
|
+
|
|
1693
1876
|
}})
|
|
1694
1877
|
if discriminator == _DISC_RAYDIUM_LAUNCHLAB_POOL_CREATE:
|
|
1695
1878
|
if len(payload) < 97:
|
|
@@ -1733,6 +1916,20 @@ def parse_raydium_launchlab_instruction(
|
|
|
1733
1916
|
"is_buy": is_buy,
|
|
1734
1917
|
"trade_direction": "Buy" if is_buy else "Sell",
|
|
1735
1918
|
"exact_in": exact_in,
|
|
1919
|
+
"global_config": _get_account_safe(accounts,2),
|
|
1920
|
+
"platform_config": _get_account_safe(accounts,3),
|
|
1921
|
+
"user_base_token": _get_account_safe(accounts,5),
|
|
1922
|
+
"user_quote_token": _get_account_safe(accounts,6),
|
|
1923
|
+
"base_vault": _get_account_safe(accounts,7),
|
|
1924
|
+
"quote_vault": _get_account_safe(accounts,8),
|
|
1925
|
+
"base_mint": _get_account_safe(accounts,9),
|
|
1926
|
+
"quote_mint": _get_account_safe(accounts,10),
|
|
1927
|
+
"base_token_program": _get_account_safe(accounts,11),
|
|
1928
|
+
"quote_token_program": _get_account_safe(accounts,12),
|
|
1929
|
+
"system_program": _get_account_safe(accounts,15),
|
|
1930
|
+
"platform_associated_account": _get_account_safe(accounts,16),
|
|
1931
|
+
"creator_associated_account": _get_account_safe(accounts,17),
|
|
1932
|
+
|
|
1736
1933
|
}})
|
|
1737
1934
|
if discriminator in (
|
|
1738
1935
|
_IX_RAYDIUM_LAUNCHLAB_INITIALIZE,
|
|
@@ -1758,7 +1955,16 @@ def parse_raydium_launchlab_instruction(
|
|
|
1758
1955
|
_IX_RAYDIUM_LAUNCHLAB_MIGRATE_TO_AMM,
|
|
1759
1956
|
_IX_RAYDIUM_LAUNCHLAB_MIGRATE_TO_CPSWAP,
|
|
1760
1957
|
):
|
|
1761
|
-
|
|
1958
|
+
cp = discriminator == _IX_RAYDIUM_LAUNCHLAB_MIGRATE_TO_CPSWAP
|
|
1959
|
+
if len(accounts) < (28 if cp else 32) or (not cp and len(payload) < 9): return None
|
|
1960
|
+
return legacy_dict_to_dex_event({"RaydiumLaunchlabMigrateAmm": {
|
|
1961
|
+
"metadata": meta, "old_pool": _get_account_safe(accounts,17 if cp else 23),
|
|
1962
|
+
"new_pool": _get_account_safe(accounts,5 if cp else 13), "user": _get_account_safe(accounts,0),
|
|
1963
|
+
"liquidity_amount": 0, "liquidity_amount_known": False,
|
|
1964
|
+
"base_mint": _get_account_safe(accounts,1), "quote_mint": _get_account_safe(accounts,2),
|
|
1965
|
+
"platform_config": _get_account_safe(accounts,3) if cp else Z,
|
|
1966
|
+
"destination_program": _get_account_safe(accounts,4 if cp else 12),
|
|
1967
|
+
}})
|
|
1762
1968
|
|
|
1763
1969
|
return None
|
|
1764
1970
|
|
sol_parser/json_util.py
CHANGED
|
@@ -11,7 +11,7 @@ from .grpc_types import EventType
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
def dex_event_json_dumps(obj: Any, **kwargs: Any) -> str:
|
|
14
|
-
return json.dumps(obj, default=str, **kwargs)
|
|
14
|
+
return json.dumps(_precise_metadata(dex_event_to_jsonable(obj)), default=str, **kwargs)
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
def dex_event_to_jsonable(ev: Any) -> Any:
|
|
@@ -39,3 +39,17 @@ def format_dex_event_json(ev: Any, *, indent: int = 2, ensure_ascii: bool = Fals
|
|
|
39
39
|
indent=indent,
|
|
40
40
|
ensure_ascii=ensure_ascii,
|
|
41
41
|
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _precise_metadata(obj):
|
|
45
|
+
"""Match Node exact metadata JSON without changing floating latency metrics."""
|
|
46
|
+
if isinstance(obj,dict):
|
|
47
|
+
result={k:_precise_metadata(v) for k,v in obj.items()}
|
|
48
|
+
if "signature" in obj and all(k in obj for k in ("slot","tx_index","block_time_us","grpc_recv_us")):
|
|
49
|
+
from .grpc_types import EventMetadata
|
|
50
|
+
validated=EventMetadata(**{k:obj[k] for k in ("signature","slot","tx_index","block_time_us","grpc_recv_us")})
|
|
51
|
+
for k in ("slot","tx_index","block_time_us","grpc_recv_us"):result[k]=str(getattr(validated,k))
|
|
52
|
+
return result
|
|
53
|
+
if isinstance(obj,(tuple,list)):return [_precise_metadata(v) for v in obj]
|
|
54
|
+
if is_dataclass(obj):return _precise_metadata(asdict(obj))
|
|
55
|
+
return obj
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""Native liquidity identity decoders and immutable raw subscription snapshots."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
import base58
|
|
6
|
+
from .accounts import AccountData
|
|
7
|
+
from .grpc_types import EventMetadata
|
|
8
|
+
from .transaction_route import PROGRAMS
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass
|
|
12
|
+
class RawAccountSnapshotEvent:
|
|
13
|
+
metadata: EventMetadata
|
|
14
|
+
account: AccountData
|
|
15
|
+
write_version: int
|
|
16
|
+
is_startup: bool
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class LiquidityAccountSnapshotEvent:
|
|
21
|
+
metadata: EventMetadata
|
|
22
|
+
pubkey: str
|
|
23
|
+
owner: str
|
|
24
|
+
kind: dict | str
|
|
25
|
+
data: bytes
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def parse_liquidity_account(account: AccountData, metadata: EventMetadata):
|
|
29
|
+
if account.lamports <= 0 or account.executable:
|
|
30
|
+
return None
|
|
31
|
+
d, owner = bytes(account.data), account.owner
|
|
32
|
+
disc = d[:8]
|
|
33
|
+
|
|
34
|
+
def key(o):
|
|
35
|
+
return base58.b58encode(d[o : o + 32]).decode()
|
|
36
|
+
|
|
37
|
+
def number(o, n, signed=False):
|
|
38
|
+
return int.from_bytes(d[o : o + n], "little", signed=signed)
|
|
39
|
+
|
|
40
|
+
kind = None
|
|
41
|
+
if owner == PROGRAMS["LaunchLab"]:
|
|
42
|
+
if disc == bytes([247, 237, 227, 245, 215, 195, 222, 70]) and len(d) >= 429:
|
|
43
|
+
kind = {
|
|
44
|
+
"LaunchLabPool": dict(
|
|
45
|
+
base_mint=key(205),
|
|
46
|
+
quote_mint=key(237),
|
|
47
|
+
global_config=key(141),
|
|
48
|
+
platform_config=key(173),
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
elif disc == bytes([149, 8, 156, 202, 160, 252, 176, 217]) and len(d) >= 35:
|
|
52
|
+
kind = "LaunchLabGlobalConfig"
|
|
53
|
+
elif disc == bytes([160, 78, 128, 0, 248, 83, 230, 160]) and len(d) >= 728:
|
|
54
|
+
kind = "LaunchLabPlatformConfig"
|
|
55
|
+
elif owner == PROGRAMS["MeteoraDlmm"]:
|
|
56
|
+
if disc == bytes([33, 11, 49, 98, 181, 101, 177, 13]) and len(d) >= 904:
|
|
57
|
+
kind = {
|
|
58
|
+
"DlmmPool": dict(
|
|
59
|
+
token_x_mint=key(88),
|
|
60
|
+
token_y_mint=key(120),
|
|
61
|
+
active_id=number(76, 4, True),
|
|
62
|
+
bin_step=number(80, 2),
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
elif disc == bytes([92, 142, 92, 220, 5, 148, 70, 181]) and len(d) >= 10136:
|
|
66
|
+
kind = {"DlmmBinArray": dict(pool=key(24), index=number(8, 8, True))}
|
|
67
|
+
elif disc == bytes([80, 111, 124, 113, 55, 237, 18, 5]) and len(d) >= 1576:
|
|
68
|
+
kind = {"DlmmBitmap": dict(pool=key(8))}
|
|
69
|
+
elif owner == PROGRAMS["OrcaWhirlpool"]:
|
|
70
|
+
if disc == bytes([17, 216, 246, 142, 225, 199, 218, 56]) and len(d) >= 148:
|
|
71
|
+
bitmap, offset = number(44, 16), 60
|
|
72
|
+
if bitmap >> 88:
|
|
73
|
+
return None
|
|
74
|
+
for i in range(88):
|
|
75
|
+
if (
|
|
76
|
+
offset >= len(d)
|
|
77
|
+
or d[offset] not in (0, 1)
|
|
78
|
+
or d[offset] != (bitmap >> i) & 1
|
|
79
|
+
):
|
|
80
|
+
return None
|
|
81
|
+
offset += 1 + (112 if d[offset] else 0)
|
|
82
|
+
if offset > len(d):
|
|
83
|
+
return None
|
|
84
|
+
kind = {
|
|
85
|
+
"OrcaDynamicTickArray": dict(
|
|
86
|
+
pool=key(12),
|
|
87
|
+
start_tick_index=number(8, 4, True),
|
|
88
|
+
tick_bitmap=bitmap,
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
elif disc == bytes([139, 194, 131, 179, 140, 179, 229, 244]) and len(d) >= 254:
|
|
92
|
+
kind = {"OrcaAdaptiveOracle": dict(pool=key(8))}
|
|
93
|
+
elif (
|
|
94
|
+
owner == PROGRAMS["RaydiumClmm"]
|
|
95
|
+
and disc == bytes([60, 150, 36, 219, 97, 128, 139, 153])
|
|
96
|
+
and len(d) >= 1832
|
|
97
|
+
):
|
|
98
|
+
kind = {"ClmmBitmap": dict(pool=key(8))}
|
|
99
|
+
if kind is None:
|
|
100
|
+
return None
|
|
101
|
+
return LiquidityAccountSnapshotEvent(metadata, account.pubkey, owner, kind, d)
|