sol-parser-sdk 0.5.9
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.
- package/.env.example +24 -0
- package/LICENSE +21 -0
- package/README.md +236 -0
- package/README_CN.md +236 -0
- package/dist/accounts/mod.d.ts +15 -0
- package/dist/accounts/mod.js +173 -0
- package/dist/accounts/nonce.d.ts +5 -0
- package/dist/accounts/nonce.js +32 -0
- package/dist/accounts/pumpfun.d.ts +16 -0
- package/dist/accounts/pumpfun.js +538 -0
- package/dist/accounts/pumpswap.d.ts +8 -0
- package/dist/accounts/pumpswap.js +192 -0
- package/dist/accounts/raydium_orca.d.ts +26 -0
- package/dist/accounts/raydium_orca.js +453 -0
- package/dist/accounts/rpc_wallet.d.ts +5 -0
- package/dist/accounts/rpc_wallet.js +18 -0
- package/dist/accounts/rust_aliases.d.ts +10 -0
- package/dist/accounts/rust_aliases.js +21 -0
- package/dist/accounts/token.d.ts +5 -0
- package/dist/accounts/token.js +98 -0
- package/dist/accounts/types.d.ts +9 -0
- package/dist/accounts/types.js +2 -0
- package/dist/accounts/utils.d.ts +1 -0
- package/dist/accounts/utils.js +12 -0
- package/dist/accounts/wallet_resolve.d.ts +1 -0
- package/dist/accounts/wallet_resolve.js +28 -0
- package/dist/common/constants.d.ts +10 -0
- package/dist/common/constants.js +13 -0
- package/dist/core/account_dispatcher_rpc.d.ts +11 -0
- package/dist/core/account_dispatcher_rpc.js +155 -0
- package/dist/core/account_fill_bonk.d.ts +4 -0
- package/dist/core/account_fill_bonk.js +20 -0
- package/dist/core/account_fill_meteora.d.ts +15 -0
- package/dist/core/account_fill_meteora.js +27 -0
- package/dist/core/account_fill_orca.d.ts +5 -0
- package/dist/core/account_fill_orca.js +18 -0
- package/dist/core/account_fill_pumpfun.d.ts +7 -0
- package/dist/core/account_fill_pumpfun.js +167 -0
- package/dist/core/account_fill_pumpswap.d.ts +10 -0
- package/dist/core/account_fill_pumpswap.js +128 -0
- package/dist/core/account_fill_raydium.d.ts +20 -0
- package/dist/core/account_fill_raydium.js +104 -0
- package/dist/core/account_fill_raydium_launchlab.d.ts +4 -0
- package/dist/core/account_fill_raydium_launchlab.js +20 -0
- package/dist/core/account_pubkey_cache.d.ts +12 -0
- package/dist/core/account_pubkey_cache.js +26 -0
- package/dist/core/clock.d.ts +8 -0
- package/dist/core/clock.js +20 -0
- package/dist/core/common_filler_rpc.d.ts +6 -0
- package/dist/core/common_filler_rpc.js +21 -0
- package/dist/core/dex_event.d.ts +1704 -0
- package/dist/core/dex_event.js +14 -0
- package/dist/core/error.d.ts +43 -0
- package/dist/core/error.js +16 -0
- package/dist/core/json_utils.d.ts +8 -0
- package/dist/core/json_utils.js +18 -0
- package/dist/core/metadata.d.ts +11 -0
- package/dist/core/metadata.js +13 -0
- package/dist/core/pumpfun_fee_enrich.d.ts +6 -0
- package/dist/core/pumpfun_fee_enrich.js +159 -0
- package/dist/core/rpc_invoke_map.d.ts +23 -0
- package/dist/core/rpc_invoke_map.js +157 -0
- package/dist/core/unified_parser.d.ts +19 -0
- package/dist/core/unified_parser.js +50 -0
- package/dist/grpc/client.d.ts +83 -0
- package/dist/grpc/client.js +645 -0
- package/dist/grpc/client_stub.d.ts +5 -0
- package/dist/grpc/client_stub.js +5 -0
- package/dist/grpc/event_parser.d.ts +6 -0
- package/dist/grpc/event_parser.js +15 -0
- package/dist/grpc/geyser_connect.d.ts +30 -0
- package/dist/grpc/geyser_connect.js +40 -0
- package/dist/grpc/log_instr_dedup.d.ts +2 -0
- package/dist/grpc/log_instr_dedup.js +402 -0
- package/dist/grpc/order_buffer.d.ts +27 -0
- package/dist/grpc/order_buffer.js +166 -0
- package/dist/grpc/program_ids.d.ts +27 -0
- package/dist/grpc/program_ids.js +61 -0
- package/dist/grpc/rpc_to_grpc.d.ts +18 -0
- package/dist/grpc/rpc_to_grpc.js +127 -0
- package/dist/grpc/subscribe_builder.d.ts +13 -0
- package/dist/grpc/subscribe_builder.js +66 -0
- package/dist/grpc/transaction_meta.d.ts +29 -0
- package/dist/grpc/transaction_meta.js +208 -0
- package/dist/grpc/types.d.ts +195 -0
- package/dist/grpc/types.js +551 -0
- package/dist/grpc/yellowstone_parse.d.ts +16 -0
- package/dist/grpc/yellowstone_parse.js +62 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.js +298 -0
- package/dist/instr/bonk_ix.d.ts +8 -0
- package/dist/instr/bonk_ix.js +131 -0
- package/dist/instr/inner.d.ts +4 -0
- package/dist/instr/inner.js +453 -0
- package/dist/instr/meteora_damm_ix.d.ts +8 -0
- package/dist/instr/meteora_damm_ix.js +601 -0
- package/dist/instr/meteora_dlmm_ix.d.ts +2 -0
- package/dist/instr/meteora_dlmm_ix.js +134 -0
- package/dist/instr/meteora_pools_ix.d.ts +2 -0
- package/dist/instr/meteora_pools_ix.js +78 -0
- package/dist/instr/mod.d.ts +18 -0
- package/dist/instr/mod.js +129 -0
- package/dist/instr/orca_whirlpool_ix.d.ts +8 -0
- package/dist/instr/orca_whirlpool_ix.js +119 -0
- package/dist/instr/program_ids.d.ts +4 -0
- package/dist/instr/program_ids.js +20 -0
- package/dist/instr/pump_fees_ix.d.ts +2 -0
- package/dist/instr/pump_fees_ix.js +168 -0
- package/dist/instr/pumpfun_ix.d.ts +6 -0
- package/dist/instr/pumpfun_ix.js +448 -0
- package/dist/instr/pumpswap_ix.d.ts +5 -0
- package/dist/instr/pumpswap_ix.js +270 -0
- package/dist/instr/raydium_amm_v4_ix.d.ts +6 -0
- package/dist/instr/raydium_amm_v4_ix.js +112 -0
- package/dist/instr/raydium_clmm_ix.d.ts +5 -0
- package/dist/instr/raydium_clmm_ix.js +184 -0
- package/dist/instr/raydium_cpmm_ix.d.ts +5 -0
- package/dist/instr/raydium_cpmm_ix.js +109 -0
- package/dist/instr/raydium_launchlab_ix.d.ts +8 -0
- package/dist/instr/raydium_launchlab_ix.js +125 -0
- package/dist/instr/rust_aliases.d.ts +10 -0
- package/dist/instr/rust_aliases.js +20 -0
- package/dist/instr/utils.d.ts +10 -0
- package/dist/instr/utils.js +35 -0
- package/dist/logs/discriminator_lut.d.ts +19 -0
- package/dist/logs/discriminator_lut.js +62 -0
- package/dist/logs/meteora_amm.d.ts +8 -0
- package/dist/logs/meteora_amm.js +113 -0
- package/dist/logs/meteora_damm.d.ts +5 -0
- package/dist/logs/meteora_damm.js +367 -0
- package/dist/logs/meteora_dbc.d.ts +11 -0
- package/dist/logs/meteora_dbc.js +142 -0
- package/dist/logs/meteora_dlmm.d.ts +6 -0
- package/dist/logs/meteora_dlmm.js +201 -0
- package/dist/logs/optimized_matcher.d.ts +11 -0
- package/dist/logs/optimized_matcher.js +941 -0
- package/dist/logs/orca.d.ts +6 -0
- package/dist/logs/orca.js +148 -0
- package/dist/logs/program_data.d.ts +2 -0
- package/dist/logs/program_data.js +20 -0
- package/dist/logs/program_log_discriminators.d.ts +80 -0
- package/dist/logs/program_log_discriminators.js +88 -0
- package/dist/logs/pump.d.ts +14 -0
- package/dist/logs/pump.js +378 -0
- package/dist/logs/pump_amm.d.ts +9 -0
- package/dist/logs/pump_amm.js +418 -0
- package/dist/logs/pump_fees.d.ts +23 -0
- package/dist/logs/pump_fees.js +364 -0
- package/dist/logs/raydium_amm.d.ts +9 -0
- package/dist/logs/raydium_amm.js +224 -0
- package/dist/logs/raydium_clmm.d.ts +17 -0
- package/dist/logs/raydium_clmm.js +624 -0
- package/dist/logs/raydium_cpmm.d.ts +7 -0
- package/dist/logs/raydium_cpmm.js +121 -0
- package/dist/logs/raydium_launchlab.d.ts +10 -0
- package/dist/logs/raydium_launchlab.js +84 -0
- package/dist/logs/raydium_launchpad.d.ts +12 -0
- package/dist/logs/raydium_launchpad.js +92 -0
- package/dist/logs/rust_aliases.d.ts +7 -0
- package/dist/logs/rust_aliases.js +16 -0
- package/dist/parser_alias.d.ts +3 -0
- package/dist/parser_alias.js +2 -0
- package/dist/rpc_parser.d.ts +17 -0
- package/dist/rpc_parser.js +39 -0
- package/dist/rpc_transaction.d.ts +27 -0
- package/dist/rpc_transaction.js +416 -0
- package/dist/shredstream/alt_lookup.d.ts +9 -0
- package/dist/shredstream/alt_lookup.js +70 -0
- package/dist/shredstream/client.d.ts +65 -0
- package/dist/shredstream/client.js +403 -0
- package/dist/shredstream/config.d.ts +30 -0
- package/dist/shredstream/config.js +34 -0
- package/dist/shredstream/entries_decode.d.ts +28 -0
- package/dist/shredstream/entries_decode.js +251 -0
- package/dist/shredstream/index.d.ts +17 -0
- package/dist/shredstream/index.js +33 -0
- package/dist/shredstream/instruction_parse.d.ts +34 -0
- package/dist/shredstream/instruction_parse.js +79 -0
- package/dist/shredstream/proto_types.d.ts +9 -0
- package/dist/shredstream/proto_types.js +2 -0
- package/dist/shredstream/shredstream.proto +15 -0
- package/dist/shredstream/wire_to_shred_tx.d.ts +2 -0
- package/dist/shredstream/wire_to_shred_tx.js +59 -0
- package/dist/util/binary.d.ts +14 -0
- package/dist/util/binary.js +82 -0
- package/dist/util/market.d.ts +18 -0
- package/dist/util/market.js +54 -0
- package/dist/warmup.d.ts +3 -0
- package/dist/warmup.js +23 -0
- package/package.json +61 -0
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.fillDataRpc = exports.fillAccountsFromTransactionDataRpc = void 0;
|
|
7
|
+
exports.applyAccountFillsToLogEvents = applyAccountFillsToLogEvents;
|
|
8
|
+
exports.parseRpcTransaction = parseRpcTransaction;
|
|
9
|
+
/**
|
|
10
|
+
* RPC 交易解析:外层 + 内层指令 → 日志 → `fillAccountsFromTransactionDataRpc` → `fillDataRpc`。
|
|
11
|
+
*/
|
|
12
|
+
const bs58_1 = __importDefault(require("bs58"));
|
|
13
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
14
|
+
const types_js_1 = require("./grpc/types.js");
|
|
15
|
+
const account_dispatcher_rpc_js_1 = require("./core/account_dispatcher_rpc.js");
|
|
16
|
+
const common_filler_rpc_js_1 = require("./core/common_filler_rpc.js");
|
|
17
|
+
const pumpfun_fee_enrich_js_1 = require("./core/pumpfun_fee_enrich.js");
|
|
18
|
+
const rpc_invoke_map_js_1 = require("./core/rpc_invoke_map.js");
|
|
19
|
+
const log_instr_dedup_js_1 = require("./grpc/log_instr_dedup.js");
|
|
20
|
+
const inner_js_1 = require("./instr/inner.js");
|
|
21
|
+
const mod_js_1 = require("./instr/mod.js");
|
|
22
|
+
const optimized_matcher_js_1 = require("./logs/optimized_matcher.js");
|
|
23
|
+
const DEFAULT_PK = web3_js_1.PublicKey.default.toBase58();
|
|
24
|
+
function eventName(ev) {
|
|
25
|
+
return Object.keys(ev)[0] ?? "";
|
|
26
|
+
}
|
|
27
|
+
function eventPayload(ev) {
|
|
28
|
+
const name = eventName(ev);
|
|
29
|
+
return name ? ev[name] : null;
|
|
30
|
+
}
|
|
31
|
+
function isDefaultValue(v) {
|
|
32
|
+
return v == null || v === "" || v === DEFAULT_PK;
|
|
33
|
+
}
|
|
34
|
+
function putStringIfSet(to, key, from) {
|
|
35
|
+
const value = from[key];
|
|
36
|
+
if (!isDefaultValue(value))
|
|
37
|
+
to[key] = value;
|
|
38
|
+
}
|
|
39
|
+
function putNonZero(to, key, from) {
|
|
40
|
+
const value = from[key];
|
|
41
|
+
if (value !== undefined && value !== 0 && value !== 0n)
|
|
42
|
+
to[key] = value;
|
|
43
|
+
}
|
|
44
|
+
function fillStringIfEmpty(to, key, from) {
|
|
45
|
+
const value = from[key];
|
|
46
|
+
if (isDefaultValue(to[key]) && !isDefaultValue(value))
|
|
47
|
+
to[key] = value;
|
|
48
|
+
}
|
|
49
|
+
function mergePumpfunTradeInstruction(base, inner) {
|
|
50
|
+
const leg = inner.sol_amount !== 0n || inner.token_amount !== 0n;
|
|
51
|
+
for (const key of ["mint", "user", "fee_recipient", "creator"]) {
|
|
52
|
+
putStringIfSet(base, key, inner);
|
|
53
|
+
}
|
|
54
|
+
if (leg) {
|
|
55
|
+
for (const key of [
|
|
56
|
+
"sol_amount",
|
|
57
|
+
"token_amount",
|
|
58
|
+
"timestamp",
|
|
59
|
+
"virtual_sol_reserves",
|
|
60
|
+
"virtual_token_reserves",
|
|
61
|
+
"real_sol_reserves",
|
|
62
|
+
"real_token_reserves",
|
|
63
|
+
"fee_basis_points",
|
|
64
|
+
"fee",
|
|
65
|
+
"creator_fee_basis_points",
|
|
66
|
+
"creator_fee",
|
|
67
|
+
"total_unclaimed_tokens",
|
|
68
|
+
"total_claimed_tokens",
|
|
69
|
+
"current_sol_volume",
|
|
70
|
+
"last_update_timestamp",
|
|
71
|
+
]) {
|
|
72
|
+
base[key] = inner[key];
|
|
73
|
+
}
|
|
74
|
+
base.is_buy = inner.is_buy;
|
|
75
|
+
base.track_volume = Boolean(base.track_volume) || Boolean(inner.track_volume);
|
|
76
|
+
base.mayhem_mode = Boolean(base.mayhem_mode) || Boolean(inner.mayhem_mode);
|
|
77
|
+
if ((base.shareholders?.length ?? 0) === 0 && (inner.shareholders?.length ?? 0) !== 0) {
|
|
78
|
+
base.shareholders = inner.shareholders;
|
|
79
|
+
}
|
|
80
|
+
if ((inner.ix_name ?? "") !== "")
|
|
81
|
+
base.ix_name = inner.ix_name;
|
|
82
|
+
base.is_cashback_coin = Boolean(base.is_cashback_coin) || Boolean(inner.is_cashback_coin);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
for (const key of [
|
|
86
|
+
"fee",
|
|
87
|
+
"creator_fee",
|
|
88
|
+
"fee_basis_points",
|
|
89
|
+
"creator_fee_basis_points",
|
|
90
|
+
"virtual_sol_reserves",
|
|
91
|
+
"virtual_token_reserves",
|
|
92
|
+
"real_sol_reserves",
|
|
93
|
+
"real_token_reserves",
|
|
94
|
+
"total_unclaimed_tokens",
|
|
95
|
+
"total_claimed_tokens",
|
|
96
|
+
"current_sol_volume",
|
|
97
|
+
"timestamp",
|
|
98
|
+
"last_update_timestamp",
|
|
99
|
+
]) {
|
|
100
|
+
putNonZero(base, key, inner);
|
|
101
|
+
}
|
|
102
|
+
base.track_volume = Boolean(base.track_volume) || Boolean(inner.track_volume);
|
|
103
|
+
base.mayhem_mode = Boolean(base.mayhem_mode) || Boolean(inner.mayhem_mode);
|
|
104
|
+
base.is_cashback_coin = Boolean(base.is_cashback_coin) || Boolean(inner.is_cashback_coin);
|
|
105
|
+
if ((base.shareholders?.length ?? 0) === 0 && (inner.shareholders?.length ?? 0) !== 0) {
|
|
106
|
+
base.shareholders = inner.shareholders;
|
|
107
|
+
}
|
|
108
|
+
if ((inner.ix_name ?? "") !== "")
|
|
109
|
+
base.ix_name = inner.ix_name;
|
|
110
|
+
}
|
|
111
|
+
for (const key of [
|
|
112
|
+
"cashback_fee_basis_points",
|
|
113
|
+
"cashback",
|
|
114
|
+
"buyback_fee_basis_points",
|
|
115
|
+
"buyback_fee",
|
|
116
|
+
"quote_amount",
|
|
117
|
+
"virtual_quote_reserves",
|
|
118
|
+
"real_quote_reserves",
|
|
119
|
+
"amount",
|
|
120
|
+
"max_sol_cost",
|
|
121
|
+
"min_sol_output",
|
|
122
|
+
"spendable_sol_in",
|
|
123
|
+
"spendable_quote_in",
|
|
124
|
+
"min_tokens_out",
|
|
125
|
+
]) {
|
|
126
|
+
putNonZero(base, key, inner);
|
|
127
|
+
}
|
|
128
|
+
for (const key of [
|
|
129
|
+
"quote_mint",
|
|
130
|
+
"global",
|
|
131
|
+
"bonding_curve",
|
|
132
|
+
"bonding_curve_v2",
|
|
133
|
+
"associated_bonding_curve",
|
|
134
|
+
"associated_user",
|
|
135
|
+
"system_program",
|
|
136
|
+
"token_program",
|
|
137
|
+
"quote_token_program",
|
|
138
|
+
"associated_token_program",
|
|
139
|
+
"creator_vault",
|
|
140
|
+
"associated_quote_fee_recipient",
|
|
141
|
+
"buyback_fee_recipient",
|
|
142
|
+
"associated_quote_buyback_fee_recipient",
|
|
143
|
+
"associated_quote_bonding_curve",
|
|
144
|
+
"associated_quote_user",
|
|
145
|
+
"associated_creator_vault",
|
|
146
|
+
"sharing_config",
|
|
147
|
+
"event_authority",
|
|
148
|
+
"program",
|
|
149
|
+
"global_volume_accumulator",
|
|
150
|
+
"user_volume_accumulator",
|
|
151
|
+
"associated_user_volume_accumulator",
|
|
152
|
+
"fee_config",
|
|
153
|
+
"fee_program",
|
|
154
|
+
]) {
|
|
155
|
+
putStringIfSet(base, key, inner);
|
|
156
|
+
}
|
|
157
|
+
if (base.account == null && inner.account != null)
|
|
158
|
+
base.account = inner.account;
|
|
159
|
+
base.is_created_buy = Boolean(base.is_created_buy) || Boolean(inner.is_created_buy);
|
|
160
|
+
}
|
|
161
|
+
function mergePumpfunCreateV2Instruction(base, inner) {
|
|
162
|
+
for (const key of ["name", "symbol", "uri"])
|
|
163
|
+
fillStringIfEmpty(base, key, inner);
|
|
164
|
+
for (const key of [
|
|
165
|
+
"mint",
|
|
166
|
+
"bonding_curve",
|
|
167
|
+
"user",
|
|
168
|
+
"creator",
|
|
169
|
+
"token_program",
|
|
170
|
+
"quote_mint",
|
|
171
|
+
"quote_vault",
|
|
172
|
+
"quote_token_program",
|
|
173
|
+
"mint_authority",
|
|
174
|
+
"associated_bonding_curve",
|
|
175
|
+
"global",
|
|
176
|
+
"system_program",
|
|
177
|
+
"associated_token_program",
|
|
178
|
+
"mayhem_program_id",
|
|
179
|
+
"global_params",
|
|
180
|
+
"sol_vault",
|
|
181
|
+
"mayhem_state",
|
|
182
|
+
"mayhem_token_vault",
|
|
183
|
+
"event_authority",
|
|
184
|
+
"program",
|
|
185
|
+
"observed_fee_recipient",
|
|
186
|
+
]) {
|
|
187
|
+
putStringIfSet(base, key, inner);
|
|
188
|
+
}
|
|
189
|
+
for (const key of [
|
|
190
|
+
"timestamp",
|
|
191
|
+
"virtual_token_reserves",
|
|
192
|
+
"virtual_sol_reserves",
|
|
193
|
+
"real_token_reserves",
|
|
194
|
+
"token_total_supply",
|
|
195
|
+
"virtual_quote_reserves",
|
|
196
|
+
]) {
|
|
197
|
+
putNonZero(base, key, inner);
|
|
198
|
+
}
|
|
199
|
+
base.is_mayhem_mode = Boolean(base.is_mayhem_mode) || Boolean(inner.is_mayhem_mode);
|
|
200
|
+
base.is_cashback_enabled = Boolean(base.is_cashback_enabled) || Boolean(inner.is_cashback_enabled);
|
|
201
|
+
if ((inner.ix_name ?? "") !== "")
|
|
202
|
+
base.ix_name = inner.ix_name;
|
|
203
|
+
}
|
|
204
|
+
function mergePumpSwapBuySellInstruction(base, inner) {
|
|
205
|
+
const ix = { ...base };
|
|
206
|
+
Object.assign(base, inner);
|
|
207
|
+
for (const key of [
|
|
208
|
+
"base_mint",
|
|
209
|
+
"quote_mint",
|
|
210
|
+
"user_base_token_account",
|
|
211
|
+
"user_quote_token_account",
|
|
212
|
+
"pool_base_token_account",
|
|
213
|
+
"pool_quote_token_account",
|
|
214
|
+
"protocol_fee_recipient",
|
|
215
|
+
"protocol_fee_recipient_token_account",
|
|
216
|
+
"coin_creator_vault_ata",
|
|
217
|
+
"coin_creator_vault_authority",
|
|
218
|
+
"base_token_program",
|
|
219
|
+
"quote_token_program",
|
|
220
|
+
"pool_v2",
|
|
221
|
+
"fee_recipient",
|
|
222
|
+
"fee_recipient_quote_token_account",
|
|
223
|
+
]) {
|
|
224
|
+
fillStringIfEmpty(base, key, ix);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
function mergeInstructionEvent(base, inner) {
|
|
228
|
+
const baseName = eventName(base);
|
|
229
|
+
const innerName = eventName(inner);
|
|
230
|
+
const baseData = eventPayload(base);
|
|
231
|
+
const innerData = eventPayload(inner);
|
|
232
|
+
if (!baseData || !innerData)
|
|
233
|
+
return;
|
|
234
|
+
const pumpfunTradeNames = new Set([
|
|
235
|
+
"PumpFunTrade",
|
|
236
|
+
"PumpFunBuy",
|
|
237
|
+
"PumpFunSell",
|
|
238
|
+
"PumpFunBuyExactSolIn",
|
|
239
|
+
]);
|
|
240
|
+
if (pumpfunTradeNames.has(baseName) && pumpfunTradeNames.has(innerName)) {
|
|
241
|
+
mergePumpfunTradeInstruction(baseData, innerData);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
if (baseName === "PumpFunCreateV2" && innerName === "PumpFunCreateV2") {
|
|
245
|
+
mergePumpfunCreateV2Instruction(baseData, innerData);
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
if ((baseName === "PumpSwapBuy" && innerName === "PumpSwapBuy") ||
|
|
249
|
+
(baseName === "PumpSwapSell" && innerName === "PumpSwapSell")) {
|
|
250
|
+
mergePumpSwapBuySellInstruction(baseData, innerData);
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
if (baseName === innerName) {
|
|
254
|
+
Object.assign(baseData, innerData);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
function mergeInstructionEvents(events) {
|
|
258
|
+
if (events.length === 0)
|
|
259
|
+
return [];
|
|
260
|
+
events.sort((a, b) => {
|
|
261
|
+
if (a.outerIdx !== b.outerIdx)
|
|
262
|
+
return a.outerIdx - b.outerIdx;
|
|
263
|
+
const ak = a.innerIdx === null ? 0 : 1 + a.innerIdx;
|
|
264
|
+
const bk = b.innerIdx === null ? 0 : 1 + b.innerIdx;
|
|
265
|
+
return ak - bk;
|
|
266
|
+
});
|
|
267
|
+
const out = [];
|
|
268
|
+
let pending = null;
|
|
269
|
+
for (const item of events) {
|
|
270
|
+
if (item.innerIdx === null) {
|
|
271
|
+
if (pending)
|
|
272
|
+
out.push(pending.event);
|
|
273
|
+
pending = { outerIdx: item.outerIdx, event: item.event };
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
if (pending && pending.outerIdx === item.outerIdx) {
|
|
277
|
+
mergeInstructionEvent(pending.event, item.event);
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
if (pending) {
|
|
281
|
+
out.push(pending.event);
|
|
282
|
+
pending = null;
|
|
283
|
+
}
|
|
284
|
+
out.push(item.event);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
if (pending)
|
|
288
|
+
out.push(pending.event);
|
|
289
|
+
return out;
|
|
290
|
+
}
|
|
291
|
+
function resolveAccounts(resolver, indices) {
|
|
292
|
+
const idxs = indices instanceof Uint8Array ? Array.from(indices) : indices;
|
|
293
|
+
return idxs.map((i) => (0, rpc_invoke_map_js_1.accountKeyToBase58)(resolver.get(i)) ?? DEFAULT_PK);
|
|
294
|
+
}
|
|
295
|
+
function parseOuterAndInnerInstructions(message, meta, signature, slot, txIndex, blockTimeUs, grpcRecvUs, filter, isCreatedBuy) {
|
|
296
|
+
const resolver = (0, rpc_invoke_map_js_1.getAccountKeyResolver)(message, meta);
|
|
297
|
+
const indexedEvents = [];
|
|
298
|
+
for (const [outerIdx, ix] of message.compiledInstructions.entries()) {
|
|
299
|
+
const programId = (0, rpc_invoke_map_js_1.accountKeyToBase58)(resolver.get(ix.programIdIndex));
|
|
300
|
+
if (!programId)
|
|
301
|
+
continue;
|
|
302
|
+
const data = (0, rpc_invoke_map_js_1.decodeIxData)(ix.data);
|
|
303
|
+
const accounts = resolveAccounts(resolver, ix.accountKeyIndexes);
|
|
304
|
+
const ev = (0, mod_js_1.parseInstructionUnified)(data, accounts, signature, slot, txIndex, blockTimeUs, grpcRecvUs, filter, programId);
|
|
305
|
+
if (ev)
|
|
306
|
+
indexedEvents.push({ outerIdx, innerIdx: null, event: ev });
|
|
307
|
+
}
|
|
308
|
+
const innerGroups = meta?.innerInstructions;
|
|
309
|
+
if (!innerGroups)
|
|
310
|
+
return mergeInstructionEvents(indexedEvents);
|
|
311
|
+
for (const group of innerGroups) {
|
|
312
|
+
for (const [innerIdx, ix] of group.instructions.entries()) {
|
|
313
|
+
const programId = (0, rpc_invoke_map_js_1.accountKeyToBase58)(resolver.get(ix.programIdIndex));
|
|
314
|
+
if (!programId)
|
|
315
|
+
continue;
|
|
316
|
+
const data = (0, rpc_invoke_map_js_1.decodeIxData)(ix.data);
|
|
317
|
+
const accounts = resolveAccounts(resolver, ix.accounts);
|
|
318
|
+
const ev = (0, inner_js_1.parseInnerCompiledInstructionIfSupported)(data, accounts, signature, slot, txIndex, blockTimeUs, grpcRecvUs, filter, programId) ??
|
|
319
|
+
(0, inner_js_1.parseInnerInstructionUnified)(data, accounts, signature, slot, txIndex, blockTimeUs, grpcRecvUs, filter, programId, isCreatedBuy);
|
|
320
|
+
if (ev)
|
|
321
|
+
indexedEvents.push({ outerIdx: group.index, innerIdx, event: ev });
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return mergeInstructionEvents(indexedEvents);
|
|
325
|
+
}
|
|
326
|
+
function recentBlockhashBytes(recentBlockhash) {
|
|
327
|
+
try {
|
|
328
|
+
return Uint8Array.from(bs58_1.default.decode(recentBlockhash));
|
|
329
|
+
}
|
|
330
|
+
catch {
|
|
331
|
+
return undefined;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
function detectPumpfunCreateInLogs(logMessages, _signature, _slot, _txIndex, _blockTimeUs, _grpcRecvUs, _recentBlockhash) {
|
|
335
|
+
return logMessages.some((log) => log.includes("Program data: G3KpTd7rY3Y"));
|
|
336
|
+
}
|
|
337
|
+
function applyRpcFills(events, msg, meta) {
|
|
338
|
+
const resolver = (0, rpc_invoke_map_js_1.getAccountKeyResolver)(msg, meta);
|
|
339
|
+
const programInvokes = (0, rpc_invoke_map_js_1.buildProgramInvokesMap)(msg, meta, resolver);
|
|
340
|
+
for (const ev of events) {
|
|
341
|
+
(0, account_dispatcher_rpc_js_1.fillAccountsFromTransactionDataRpc)(ev, msg, meta, programInvokes, resolver);
|
|
342
|
+
(0, common_filler_rpc_js_1.fillDataRpc)(ev, msg, meta, programInvokes);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
function setRecentBlockhash(events, recentBlockhash) {
|
|
346
|
+
if (!recentBlockhash)
|
|
347
|
+
return;
|
|
348
|
+
for (const ev of events) {
|
|
349
|
+
const data = eventPayload(ev);
|
|
350
|
+
if (data?.metadata)
|
|
351
|
+
data.metadata.recent_blockhash = recentBlockhash;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* 与 Rust gRPC `parse_logs` 中 `fill_accounts_from_transaction_data` + `fill_data` 对齐:
|
|
356
|
+
* 对已由日志解析出的 `DexEvent` 用交易 message + meta 补全账户等字段。
|
|
357
|
+
*/
|
|
358
|
+
function applyAccountFillsToLogEvents(events, msg, meta) {
|
|
359
|
+
applyRpcFills(events, msg, meta);
|
|
360
|
+
(0, pumpfun_fee_enrich_js_1.enrichPumpfunSameTxPostMerge)(events);
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* 解析已获取的 `VersionedTransactionResponse`(顺序:指令 → 日志 → 账户/数据填充)。
|
|
364
|
+
*/
|
|
365
|
+
function parseRpcTransaction(tx, signature, filter, options) {
|
|
366
|
+
const msg = tx.transaction?.message;
|
|
367
|
+
if (!msg || !(0, rpc_invoke_map_js_1.isCompiledVersionedMessage)(msg)) {
|
|
368
|
+
return {
|
|
369
|
+
ok: false,
|
|
370
|
+
error: {
|
|
371
|
+
kind: "ConversionError",
|
|
372
|
+
message: "交易 message 非编译形态(例如使用了 jsonParsed)。请使用默认/非 parsed 的 getTransaction 响应。",
|
|
373
|
+
},
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
const meta = tx.meta ?? null;
|
|
377
|
+
const slot = tx.slot;
|
|
378
|
+
const blockTimeUs = options?.blockTimeUs ?? (tx.blockTime != null ? tx.blockTime * 1_000_000 : undefined);
|
|
379
|
+
const grpcRecvUs = options?.grpcRecvUs ?? Math.floor(Date.now() * 1000);
|
|
380
|
+
const txIndex = options?.txIndex ?? 0;
|
|
381
|
+
const rb = recentBlockhashBytes(msg.recentBlockhash);
|
|
382
|
+
const hasPumpfunCreateLog = detectPumpfunCreateInLogs(meta?.logMessages ?? [], signature, slot, txIndex, blockTimeUs, grpcRecvUs, rb);
|
|
383
|
+
const instructionEvents = parseOuterAndInnerInstructions(msg, meta, signature, slot, txIndex, blockTimeUs, grpcRecvUs, filter, hasPumpfunCreateLog);
|
|
384
|
+
setRecentBlockhash(instructionEvents, msg.recentBlockhash);
|
|
385
|
+
const logEvents = [];
|
|
386
|
+
const activeProgramStack = [];
|
|
387
|
+
for (const log of meta?.logMessages ?? []) {
|
|
388
|
+
const invoke = (0, optimized_matcher_js_1.parseInvokeInfo)(log);
|
|
389
|
+
if (invoke) {
|
|
390
|
+
activeProgramStack.length = Math.max(0, invoke.depth - 1);
|
|
391
|
+
activeProgramStack.push(invoke.programId);
|
|
392
|
+
}
|
|
393
|
+
const e = (0, optimized_matcher_js_1.parseLogOptimizedWithProgramId)(log, signature, slot, txIndex, blockTimeUs, grpcRecvUs, filter, hasPumpfunCreateLog, rb, activeProgramStack[activeProgramStack.length - 1]);
|
|
394
|
+
if (e) {
|
|
395
|
+
logEvents.push(e);
|
|
396
|
+
}
|
|
397
|
+
const completed = (0, optimized_matcher_js_1.parseProgramCompleteInfo)(log);
|
|
398
|
+
if (completed) {
|
|
399
|
+
const idx = activeProgramStack.lastIndexOf(completed);
|
|
400
|
+
if (idx >= 0)
|
|
401
|
+
activeProgramStack.length = idx;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
applyRpcFills(instructionEvents, msg, meta);
|
|
405
|
+
applyRpcFills(logEvents, msg, meta);
|
|
406
|
+
const events = (0, log_instr_dedup_js_1.dedupeLogInstructionEvents)(logEvents, instructionEvents);
|
|
407
|
+
(0, pumpfun_fee_enrich_js_1.enrichPumpfunSameTxPostMerge)(events);
|
|
408
|
+
return {
|
|
409
|
+
ok: true,
|
|
410
|
+
events: filter ? events.map((event) => (0, types_js_1.eventTypeFilterNormalizeDexEvent)(filter, event)) : events,
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
var account_dispatcher_rpc_js_2 = require("./core/account_dispatcher_rpc.js");
|
|
414
|
+
Object.defineProperty(exports, "fillAccountsFromTransactionDataRpc", { enumerable: true, get: function () { return account_dispatcher_rpc_js_2.fillAccountsFromTransactionDataRpc; } });
|
|
415
|
+
var common_filler_rpc_js_2 = require("./core/common_filler_rpc.js");
|
|
416
|
+
Object.defineProperty(exports, "fillDataRpc", { enumerable: true, get: function () { return common_filler_rpc_js_2.fillDataRpc; } });
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* V0 交易:从链上拉取 ALT 账户,拼出与运行时一致的完整账户 key 列表(静态 + 查找表展开)。
|
|
3
|
+
*/
|
|
4
|
+
import { AddressLookupTableAccount, Connection } from "@solana/web3.js";
|
|
5
|
+
import type { ShredWasmTx } from "./instruction_parse.js";
|
|
6
|
+
/** 批量拉取 ALT,供同一 Entry 内多笔交易复用 */
|
|
7
|
+
export declare function loadAddressLookupTableAccounts(connection: Connection, lookupTableAddresses: readonly string[]): Promise<Map<string, AddressLookupTableAccount>>;
|
|
8
|
+
/** 使用已拉取的 ALT 构造完整账户表(base58);失败时退回仅静态表 */
|
|
9
|
+
export declare function fullAccountKeyStringsFromShredTx(tx: ShredWasmTx, altByAddress: Map<string, AddressLookupTableAccount>): string[];
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.loadAddressLookupTableAccounts = loadAddressLookupTableAccounts;
|
|
7
|
+
exports.fullAccountKeyStringsFromShredTx = fullAccountKeyStringsFromShredTx;
|
|
8
|
+
/**
|
|
9
|
+
* V0 交易:从链上拉取 ALT 账户,拼出与运行时一致的完整账户 key 列表(静态 + 查找表展开)。
|
|
10
|
+
*/
|
|
11
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
12
|
+
const bs58_1 = __importDefault(require("bs58"));
|
|
13
|
+
/** 批量拉取 ALT,供同一 Entry 内多笔交易复用 */
|
|
14
|
+
async function loadAddressLookupTableAccounts(connection, lookupTableAddresses) {
|
|
15
|
+
const map = new Map();
|
|
16
|
+
if (lookupTableAddresses.length === 0)
|
|
17
|
+
return map;
|
|
18
|
+
const pks = lookupTableAddresses.map((s) => new web3_js_1.PublicKey(s));
|
|
19
|
+
const infos = await connection.getMultipleAccountsInfo(pks);
|
|
20
|
+
for (let i = 0; i < pks.length; i++) {
|
|
21
|
+
const info = infos[i];
|
|
22
|
+
if (!info?.data)
|
|
23
|
+
continue;
|
|
24
|
+
const state = web3_js_1.AddressLookupTableAccount.deserialize(info.data);
|
|
25
|
+
const alt = new web3_js_1.AddressLookupTableAccount({ key: pks[i], state });
|
|
26
|
+
map.set(pks[i].toBase58(), alt);
|
|
27
|
+
}
|
|
28
|
+
return map;
|
|
29
|
+
}
|
|
30
|
+
/** 使用已拉取的 ALT 构造完整账户表(base58);失败时退回仅静态表 */
|
|
31
|
+
function fullAccountKeyStringsFromShredTx(tx, altByAddress) {
|
|
32
|
+
if (tx.messageVersion !== "v0" || !tx.addressTableLookups?.length) {
|
|
33
|
+
return tx.accounts;
|
|
34
|
+
}
|
|
35
|
+
const lookups = tx.addressTableLookups;
|
|
36
|
+
const altAccounts = [];
|
|
37
|
+
for (const l of lookups) {
|
|
38
|
+
const alt = altByAddress.get(l.accountKey);
|
|
39
|
+
if (!alt) {
|
|
40
|
+
return tx.accounts;
|
|
41
|
+
}
|
|
42
|
+
altAccounts.push(alt);
|
|
43
|
+
}
|
|
44
|
+
const header = tx.header;
|
|
45
|
+
const rb = tx.recentBlockhash;
|
|
46
|
+
if (!header || !rb || rb.length !== 32) {
|
|
47
|
+
return tx.accounts;
|
|
48
|
+
}
|
|
49
|
+
const msg = new web3_js_1.MessageV0({
|
|
50
|
+
header,
|
|
51
|
+
staticAccountKeys: tx.accounts.map((s) => new web3_js_1.PublicKey(s)),
|
|
52
|
+
recentBlockhash: bs58_1.default.encode(rb),
|
|
53
|
+
compiledInstructions: (tx.instructions ?? []).map((ix) => ({
|
|
54
|
+
programIdIndex: ix.programIdIndex,
|
|
55
|
+
accountKeyIndexes: Array.from(ix.accounts),
|
|
56
|
+
data: Buffer.from(ix.data),
|
|
57
|
+
})),
|
|
58
|
+
addressTableLookups: lookups.map((l) => ({
|
|
59
|
+
accountKey: new web3_js_1.PublicKey(l.accountKey),
|
|
60
|
+
writableIndexes: Array.from(l.writableIndexes),
|
|
61
|
+
readonlyIndexes: Array.from(l.readonlyIndexes),
|
|
62
|
+
})),
|
|
63
|
+
});
|
|
64
|
+
const keys = msg.getAccountKeys({ addressLookupTableAccounts: altAccounts });
|
|
65
|
+
const out = [];
|
|
66
|
+
for (let i = 0; i < keys.length; i++) {
|
|
67
|
+
out.push(keys.get(i).toBase58());
|
|
68
|
+
}
|
|
69
|
+
return out;
|
|
70
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { type DexEvent } from "../core/dex_event.js";
|
|
2
|
+
import type { EventTypeFilter } from "../grpc/types.js";
|
|
3
|
+
import { type ShredStreamConfig } from "./config.js";
|
|
4
|
+
/** 订阅周期内累计(用于排查「无 gRPC 包 / 解码失败 / 无 DEX 事件」) */
|
|
5
|
+
export type ShredStreamReceiveStats = {
|
|
6
|
+
entryMessagesReceived: number;
|
|
7
|
+
entryDecodeFailures: number;
|
|
8
|
+
transactionsDecoded: number;
|
|
9
|
+
dexEventsQueued: number;
|
|
10
|
+
};
|
|
11
|
+
/** 有界 FIFO 队列(容量与 Rust `ArrayQueue::new(100_000)` 一致;`clone()` 共享底层缓冲,同 `Arc<ArrayQueue>`) */
|
|
12
|
+
export declare class ShredEventQueue {
|
|
13
|
+
private static readonly CAP;
|
|
14
|
+
private readonly buf;
|
|
15
|
+
constructor(sharedBuf?: DexEvent[]);
|
|
16
|
+
/** 当前元素个数(与 Rust `ArrayQueue::len` 一致) */
|
|
17
|
+
len(): number;
|
|
18
|
+
/** 最大容量 */
|
|
19
|
+
capacity(): number;
|
|
20
|
+
push(e: DexEvent): boolean;
|
|
21
|
+
pop(): DexEvent | undefined;
|
|
22
|
+
clone(): ShredEventQueue;
|
|
23
|
+
}
|
|
24
|
+
export declare class ShredStreamClient {
|
|
25
|
+
private readonly endpoint;
|
|
26
|
+
private readonly config;
|
|
27
|
+
private readonly ServiceClient;
|
|
28
|
+
private loopAbort;
|
|
29
|
+
private loopPromise;
|
|
30
|
+
private activeCall;
|
|
31
|
+
private receiveStats;
|
|
32
|
+
private constructor();
|
|
33
|
+
static connect(endpoint: string): Promise<ShredStreamClient>;
|
|
34
|
+
/** 与 Rust `ShredStreamClient::new` 一致 */
|
|
35
|
+
static new(endpoint: string): Promise<ShredStreamClient>;
|
|
36
|
+
static connectWithConfig(endpoint: string, config: ShredStreamConfig): Promise<ShredStreamClient>;
|
|
37
|
+
/** 与 Rust `ShredStreamClient::new_with_config` 一致 */
|
|
38
|
+
static newWithConfig(endpoint: string, config: ShredStreamConfig): Promise<ShredStreamClient>;
|
|
39
|
+
/** 与 Rust `#[derive(Clone)]` 一致:多句柄共享同一连接状态(TS 中为同一对象引用) */
|
|
40
|
+
clone(): ShredStreamClient;
|
|
41
|
+
/** 当前订阅周期内 gRPC Entry 条数、解码失败次数、解码出的交易数、入队 DexEvent 数 */
|
|
42
|
+
getReceiveStats(): Readonly<ShredStreamReceiveStats>;
|
|
43
|
+
/**
|
|
44
|
+
* 与 Rust `new_with_config` 中 `ShredstreamProxyClient::connect_with_config(endpoint, &config)` 一致:
|
|
45
|
+
* `connection_timeout_ms` / `request_timeout_ms` / `max_decoding_message_size` 见 `shredstream/proto/mod.rs`。
|
|
46
|
+
*/
|
|
47
|
+
private pingConnection;
|
|
48
|
+
/**
|
|
49
|
+
* 订阅 DEX 事件(自动重连);返回队列供轮询消费(与 Rust `subscribe` 一致)。
|
|
50
|
+
* 重连循环使用订阅时刻的配置快照(与 Rust 在 `tokio::spawn` 前 `config.clone()` 一致)。
|
|
51
|
+
*/
|
|
52
|
+
subscribe(eventTypeFilter?: EventTypeFilter): Promise<ShredEventQueue>;
|
|
53
|
+
/** 与 Rust `subscribe_with_filter` 对齐:在解析热路径按事件类型预过滤。 */
|
|
54
|
+
subscribeWithFilter(eventTypeFilter?: EventTypeFilter): Promise<ShredEventQueue>;
|
|
55
|
+
/** 停止订阅并中止当前流 */
|
|
56
|
+
stop(): Promise<void>;
|
|
57
|
+
private runReconnectLoop;
|
|
58
|
+
/** 与 Rust `stream_events` + `connect_with_config`(tonic Endpoint / Grpc 消息上限)一致 */
|
|
59
|
+
private streamOnce;
|
|
60
|
+
private processEntryMessage;
|
|
61
|
+
/** 无 RPC:仅用静态账户表 */
|
|
62
|
+
private processEntryMessageSync;
|
|
63
|
+
/** 拉取 ALT 后完整账户表解析 */
|
|
64
|
+
private processEntryMessageWithAlt;
|
|
65
|
+
}
|