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,645 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.YellowstoneGrpc = void 0;
|
|
40
|
+
/**
|
|
41
|
+
* Yellowstone gRPC 客户端实现 - 基于 @triton-one/yellowstone-grpc
|
|
42
|
+
*/
|
|
43
|
+
const yellowstone_grpc_1 = __importStar(require("@triton-one/yellowstone-grpc"));
|
|
44
|
+
const bs58_1 = __importDefault(require("bs58"));
|
|
45
|
+
const metadata_js_1 = require("../core/metadata.js");
|
|
46
|
+
const mod_js_1 = require("../accounts/mod.js");
|
|
47
|
+
const geyser_connect_js_1 = require("./geyser_connect.js");
|
|
48
|
+
const order_buffer_js_1 = require("./order_buffer.js");
|
|
49
|
+
const subscribe_builder_js_1 = require("./subscribe_builder.js");
|
|
50
|
+
const yellowstone_parse_js_1 = require("./yellowstone_parse.js");
|
|
51
|
+
const types_js_1 = require("./types.js");
|
|
52
|
+
class AsyncEventQueue {
|
|
53
|
+
maxSize;
|
|
54
|
+
items = [];
|
|
55
|
+
waiters = [];
|
|
56
|
+
closed = false;
|
|
57
|
+
constructor(maxSize) {
|
|
58
|
+
this.maxSize = maxSize;
|
|
59
|
+
}
|
|
60
|
+
push(item) {
|
|
61
|
+
if (this.closed)
|
|
62
|
+
return;
|
|
63
|
+
const waiter = this.waiters.shift();
|
|
64
|
+
if (waiter) {
|
|
65
|
+
waiter({ value: item, done: false });
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (this.items.length < this.maxSize) {
|
|
69
|
+
this.items.push(item);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
close() {
|
|
73
|
+
if (this.closed)
|
|
74
|
+
return;
|
|
75
|
+
this.closed = true;
|
|
76
|
+
for (const waiter of this.waiters.splice(0)) {
|
|
77
|
+
waiter({ value: undefined, done: true });
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
next() {
|
|
81
|
+
const item = this.items.shift();
|
|
82
|
+
if (item !== undefined) {
|
|
83
|
+
return Promise.resolve({ value: item, done: false });
|
|
84
|
+
}
|
|
85
|
+
if (this.closed) {
|
|
86
|
+
return Promise.resolve({ value: undefined, done: true });
|
|
87
|
+
}
|
|
88
|
+
return new Promise((resolve) => this.waiters.push(resolve));
|
|
89
|
+
}
|
|
90
|
+
[Symbol.asyncIterator]() {
|
|
91
|
+
return this;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/** Yellowstone gRPC 客户端包装器 */
|
|
95
|
+
class YellowstoneGrpc {
|
|
96
|
+
client;
|
|
97
|
+
config;
|
|
98
|
+
connected = false;
|
|
99
|
+
subscribers = new Map();
|
|
100
|
+
dexSubscribers = new Map();
|
|
101
|
+
constructor(endpoint, xToken, config = (0, types_js_1.defaultClientConfig)()) {
|
|
102
|
+
this.config = config;
|
|
103
|
+
const gc = (0, geyser_connect_js_1.defaultGeyserConnectConfig)();
|
|
104
|
+
this.client = new yellowstone_grpc_1.default(endpoint, xToken || undefined, (0, geyser_connect_js_1.geyserGrpcChannelOptions)({
|
|
105
|
+
...gc,
|
|
106
|
+
keepAliveIntervalMs: config.keep_alive_interval_ms,
|
|
107
|
+
keepAliveTimeoutMs: config.keep_alive_timeout_ms,
|
|
108
|
+
}));
|
|
109
|
+
}
|
|
110
|
+
/** 连接到 gRPC 服务器 */
|
|
111
|
+
async connect() {
|
|
112
|
+
if (this.connected) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
this.connected = true;
|
|
116
|
+
}
|
|
117
|
+
/** 断开连接 */
|
|
118
|
+
async disconnect() {
|
|
119
|
+
for (const [, sub] of this.subscribers) {
|
|
120
|
+
sub.cancel();
|
|
121
|
+
}
|
|
122
|
+
this.subscribers.clear();
|
|
123
|
+
for (const [, sub] of this.dexSubscribers) {
|
|
124
|
+
sub.cancel();
|
|
125
|
+
}
|
|
126
|
+
this.dexSubscribers.clear();
|
|
127
|
+
this.connected = false;
|
|
128
|
+
}
|
|
129
|
+
/** 检查是否已连接 */
|
|
130
|
+
isConnected() {
|
|
131
|
+
return this.connected;
|
|
132
|
+
}
|
|
133
|
+
/** 获取客户端配置 */
|
|
134
|
+
getConfig() {
|
|
135
|
+
return this.config;
|
|
136
|
+
}
|
|
137
|
+
/** 转换 SlotStatus */
|
|
138
|
+
convertSlotStatus(status) {
|
|
139
|
+
const map = {
|
|
140
|
+
0: "Processed",
|
|
141
|
+
1: "Confirmed",
|
|
142
|
+
2: "Finalized",
|
|
143
|
+
3: "FirstShredReceived",
|
|
144
|
+
4: "Completed",
|
|
145
|
+
5: "CreatedBank",
|
|
146
|
+
6: "Dead",
|
|
147
|
+
};
|
|
148
|
+
return map[status] ?? "Processed";
|
|
149
|
+
}
|
|
150
|
+
/** 转换订阅更新 */
|
|
151
|
+
convertUpdate(update) {
|
|
152
|
+
const result = {
|
|
153
|
+
filters: update.filters,
|
|
154
|
+
};
|
|
155
|
+
const createdAtUs = YellowstoneGrpc.timestampToMicros(update.createdAt ?? update.created_at);
|
|
156
|
+
if (createdAtUs !== undefined)
|
|
157
|
+
result.createdAtUs = createdAtUs;
|
|
158
|
+
if (update.account) {
|
|
159
|
+
const acc = update.account;
|
|
160
|
+
result.account = {
|
|
161
|
+
slot: acc.slot,
|
|
162
|
+
isStartup: acc.isStartup,
|
|
163
|
+
};
|
|
164
|
+
if (acc.account) {
|
|
165
|
+
result.account.account = {
|
|
166
|
+
pubkey: acc.account.pubkey,
|
|
167
|
+
lamports: acc.account.lamports,
|
|
168
|
+
owner: acc.account.owner,
|
|
169
|
+
executable: acc.account.executable,
|
|
170
|
+
rentEpoch: acc.account.rentEpoch,
|
|
171
|
+
data: acc.account.data,
|
|
172
|
+
writeVersion: acc.account.writeVersion,
|
|
173
|
+
txnSignature: acc.account.txnSignature,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if (update.slot) {
|
|
178
|
+
const slot = update.slot;
|
|
179
|
+
result.slot = {
|
|
180
|
+
slot: slot.slot,
|
|
181
|
+
status: this.convertSlotStatus(slot.status),
|
|
182
|
+
};
|
|
183
|
+
if (slot.parent !== undefined) {
|
|
184
|
+
result.slot.parent = slot.parent;
|
|
185
|
+
}
|
|
186
|
+
if (slot.deadError !== undefined) {
|
|
187
|
+
result.slot.deadError = slot.deadError;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (update.transaction) {
|
|
191
|
+
const tx = update.transaction;
|
|
192
|
+
result.transaction = {
|
|
193
|
+
slot: tx.slot,
|
|
194
|
+
};
|
|
195
|
+
if (tx.transaction) {
|
|
196
|
+
result.transaction.transaction = {
|
|
197
|
+
signature: tx.transaction.signature,
|
|
198
|
+
isVote: tx.transaction.isVote,
|
|
199
|
+
transactionRaw: tx.transaction.transaction,
|
|
200
|
+
metaRaw: tx.transaction.meta,
|
|
201
|
+
index: tx.transaction.index,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
if (update.block) {
|
|
206
|
+
const block = update.block;
|
|
207
|
+
result.block = {
|
|
208
|
+
slot: block.slot,
|
|
209
|
+
blockhash: block.blockhash,
|
|
210
|
+
parentSlot: block.parentSlot,
|
|
211
|
+
parentBlockhash: block.parentBlockhash,
|
|
212
|
+
executedTransactionCount: block.executedTransactionCount,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
if (update.blockMeta) {
|
|
216
|
+
const meta = update.blockMeta;
|
|
217
|
+
result.blockMeta = {
|
|
218
|
+
slot: meta.slot,
|
|
219
|
+
blockhash: meta.blockhash,
|
|
220
|
+
parentSlot: meta.parentSlot,
|
|
221
|
+
parentBlockhash: meta.parentBlockhash,
|
|
222
|
+
executedTransactionCount: meta.executedTransactionCount,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
if (update.ping) {
|
|
226
|
+
result.ping = {};
|
|
227
|
+
}
|
|
228
|
+
if (update.pong) {
|
|
229
|
+
result.pong = {
|
|
230
|
+
id: update.pong.id,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
return result;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* 应答 Geyser 在 SubscribeUpdate 中下发的 ping(与 `solana-streamer` / Rust 侧一致)。
|
|
237
|
+
* 若不回复,公共节点或 LB 可能在超时后 RST_STREAM(HTTP/2 CANCEL)。
|
|
238
|
+
*/
|
|
239
|
+
subscribePingPongRequest() {
|
|
240
|
+
return {
|
|
241
|
+
accounts: {},
|
|
242
|
+
slots: {},
|
|
243
|
+
transactions: {},
|
|
244
|
+
transactionsStatus: {},
|
|
245
|
+
entry: {},
|
|
246
|
+
blocks: {},
|
|
247
|
+
blocksMeta: {},
|
|
248
|
+
commitment: yellowstone_grpc_1.CommitmentLevel.CONFIRMED,
|
|
249
|
+
accountsDataSlice: [],
|
|
250
|
+
ping: { id: 1 },
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
static toBytes(value) {
|
|
254
|
+
if (!value)
|
|
255
|
+
return new Uint8Array();
|
|
256
|
+
return value instanceof Uint8Array ? value : Uint8Array.from(value);
|
|
257
|
+
}
|
|
258
|
+
static toBigInt(value) {
|
|
259
|
+
return typeof value === "bigint" ? value : BigInt(value);
|
|
260
|
+
}
|
|
261
|
+
static protobufNumber(value) {
|
|
262
|
+
if (typeof value === "bigint")
|
|
263
|
+
return Number(value);
|
|
264
|
+
if (typeof value === "number")
|
|
265
|
+
return value;
|
|
266
|
+
if (typeof value === "string")
|
|
267
|
+
return Number(value);
|
|
268
|
+
if (value && typeof value === "object") {
|
|
269
|
+
const longLike = value;
|
|
270
|
+
if (typeof longLike.toNumber === "function")
|
|
271
|
+
return longLike.toNumber();
|
|
272
|
+
if (typeof longLike.toString === "function")
|
|
273
|
+
return Number(longLike.toString());
|
|
274
|
+
}
|
|
275
|
+
return Number.NaN;
|
|
276
|
+
}
|
|
277
|
+
static timestampToMicros(value) {
|
|
278
|
+
if (!value || typeof value !== "object")
|
|
279
|
+
return undefined;
|
|
280
|
+
const ts = value;
|
|
281
|
+
if (ts.seconds === undefined)
|
|
282
|
+
return undefined;
|
|
283
|
+
const seconds = YellowstoneGrpc.protobufNumber(ts.seconds);
|
|
284
|
+
const nanos = Number(ts.nanos ?? 0);
|
|
285
|
+
if (!Number.isFinite(seconds) || !Number.isFinite(nanos))
|
|
286
|
+
return undefined;
|
|
287
|
+
return Math.trunc(seconds * 1_000_000 + nanos / 1_000);
|
|
288
|
+
}
|
|
289
|
+
parseAccountEvent(update, grpcRecvUs, eventTypeFilter, blockTimeUs) {
|
|
290
|
+
const acc = update.account;
|
|
291
|
+
if (!acc)
|
|
292
|
+
return null;
|
|
293
|
+
const signatureBytes = YellowstoneGrpc.toBytes(acc.txnSignature);
|
|
294
|
+
const account = {
|
|
295
|
+
pubkey: bs58_1.default.encode(YellowstoneGrpc.toBytes(acc.pubkey)),
|
|
296
|
+
executable: acc.executable,
|
|
297
|
+
lamports: YellowstoneGrpc.toBigInt(acc.lamports),
|
|
298
|
+
owner: bs58_1.default.encode(YellowstoneGrpc.toBytes(acc.owner)),
|
|
299
|
+
rent_epoch: YellowstoneGrpc.toBigInt(acc.rentEpoch),
|
|
300
|
+
data: YellowstoneGrpc.toBytes(acc.data),
|
|
301
|
+
};
|
|
302
|
+
const metadata = (0, metadata_js_1.makeMetadata)(signatureBytes.length > 0 ? bs58_1.default.encode(signatureBytes) : "", Number(update.slot), 0, blockTimeUs, grpcRecvUs);
|
|
303
|
+
return (0, mod_js_1.parseAccountUnified)(account, metadata, eventTypeFilter);
|
|
304
|
+
}
|
|
305
|
+
initialSubscribeRequest(filter) {
|
|
306
|
+
return {
|
|
307
|
+
transactions: {
|
|
308
|
+
client: {
|
|
309
|
+
accountInclude: filter.account_include,
|
|
310
|
+
accountExclude: filter.account_exclude,
|
|
311
|
+
accountRequired: filter.account_required,
|
|
312
|
+
vote: filter.vote,
|
|
313
|
+
failed: filter.failed,
|
|
314
|
+
signature: filter.signature,
|
|
315
|
+
},
|
|
316
|
+
},
|
|
317
|
+
accounts: {},
|
|
318
|
+
slots: {},
|
|
319
|
+
transactionsStatus: {},
|
|
320
|
+
entry: {},
|
|
321
|
+
blocks: {},
|
|
322
|
+
blocksMeta: {},
|
|
323
|
+
commitment: yellowstone_grpc_1.CommitmentLevel.CONFIRMED,
|
|
324
|
+
accountsDataSlice: [],
|
|
325
|
+
ping: undefined,
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
/** 订阅交易 */
|
|
329
|
+
async subscribeTransactions(filter, callbacks) {
|
|
330
|
+
const id = `sub_${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
|
331
|
+
let isCancelled = false;
|
|
332
|
+
const streamHolder = { current: null };
|
|
333
|
+
const cancel = () => {
|
|
334
|
+
isCancelled = true;
|
|
335
|
+
streamHolder.current?.end();
|
|
336
|
+
streamHolder.current = null;
|
|
337
|
+
};
|
|
338
|
+
this.subscribers.set(id, { filter, callbacks, cancel });
|
|
339
|
+
(async () => {
|
|
340
|
+
const autoReconnect = callbacks.autoReconnect !== false;
|
|
341
|
+
const maxBackoffMs = 60_000;
|
|
342
|
+
let backoffMs = this.config.retry_delay_ms;
|
|
343
|
+
try {
|
|
344
|
+
while (!isCancelled) {
|
|
345
|
+
try {
|
|
346
|
+
const stream = await this.client.subscribe();
|
|
347
|
+
streamHolder.current = stream;
|
|
348
|
+
await new Promise((resolve, reject) => {
|
|
349
|
+
stream.write(this.initialSubscribeRequest(filter), (err) => {
|
|
350
|
+
if (err)
|
|
351
|
+
reject(err);
|
|
352
|
+
else
|
|
353
|
+
resolve();
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
backoffMs = this.config.retry_delay_ms;
|
|
357
|
+
await new Promise((resolve, reject) => {
|
|
358
|
+
const cleanup = () => {
|
|
359
|
+
stream.removeAllListeners();
|
|
360
|
+
if (streamHolder.current === stream) {
|
|
361
|
+
streamHolder.current = null;
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
stream.on("data", (update) => {
|
|
365
|
+
if (isCancelled)
|
|
366
|
+
return;
|
|
367
|
+
if (update.ping) {
|
|
368
|
+
stream.write(this.subscribePingPongRequest(), (werr) => {
|
|
369
|
+
if (werr && callbacks.onError && !isCancelled) {
|
|
370
|
+
callbacks.onError(werr instanceof Error ? werr : new Error(String(werr)));
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
if (!callbacks.onUpdate)
|
|
376
|
+
return;
|
|
377
|
+
try {
|
|
378
|
+
const converted = this.convertUpdate(update);
|
|
379
|
+
callbacks.onUpdate(converted);
|
|
380
|
+
}
|
|
381
|
+
catch (err) {
|
|
382
|
+
const e = err instanceof Error ? err : new Error(String(err));
|
|
383
|
+
callbacks.onError?.(e);
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
stream.on("error", (err) => {
|
|
387
|
+
cleanup();
|
|
388
|
+
reject(err);
|
|
389
|
+
});
|
|
390
|
+
stream.on("end", () => {
|
|
391
|
+
cleanup();
|
|
392
|
+
resolve();
|
|
393
|
+
});
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
catch (err) {
|
|
397
|
+
if (isCancelled)
|
|
398
|
+
break;
|
|
399
|
+
const e = err instanceof Error ? err : new Error(String(err));
|
|
400
|
+
callbacks.onError?.(e);
|
|
401
|
+
if (!autoReconnect)
|
|
402
|
+
break;
|
|
403
|
+
await new Promise((r) => setTimeout(r, backoffMs));
|
|
404
|
+
backoffMs = Math.min(backoffMs * 2, maxBackoffMs);
|
|
405
|
+
continue;
|
|
406
|
+
}
|
|
407
|
+
if (isCancelled)
|
|
408
|
+
break;
|
|
409
|
+
if (!autoReconnect) {
|
|
410
|
+
callbacks.onEnd?.();
|
|
411
|
+
break;
|
|
412
|
+
}
|
|
413
|
+
await new Promise((r) => setTimeout(r, backoffMs));
|
|
414
|
+
backoffMs = Math.min(backoffMs * 2, maxBackoffMs);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
finally {
|
|
418
|
+
streamHolder.current?.end();
|
|
419
|
+
streamHolder.current = null;
|
|
420
|
+
this.subscribers.delete(id);
|
|
421
|
+
}
|
|
422
|
+
})();
|
|
423
|
+
return {
|
|
424
|
+
id,
|
|
425
|
+
cancel: () => {
|
|
426
|
+
cancel();
|
|
427
|
+
this.subscribers.delete(id);
|
|
428
|
+
},
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* 订阅并直接产出 `DexEvent`。
|
|
433
|
+
*
|
|
434
|
+
* 交易更新走统一交易解析(外层/内层指令 + 日志 + 数据填充);账户更新走 `parseAccountUnified`。
|
|
435
|
+
* 事件队列满时丢弃新事件,避免回调阻塞 gRPC 读循环,保持低延迟。
|
|
436
|
+
*/
|
|
437
|
+
async subscribeDexEvents(transactionFilters = [], accountFilters = [], eventTypeFilter, options) {
|
|
438
|
+
await this.connect();
|
|
439
|
+
const id = `dex_${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
|
440
|
+
const events = new AsyncEventQueue(Math.max(1, this.config.buffer_size));
|
|
441
|
+
const errors = new AsyncEventQueue(Math.max(1, this.config.buffer_size));
|
|
442
|
+
const order = new order_buffer_js_1.OrderDispatcher(this.config);
|
|
443
|
+
const emitEvent = (event) => events.push(event);
|
|
444
|
+
let flushTimer;
|
|
445
|
+
if (order.needsTimer) {
|
|
446
|
+
const intervalMs = this.config.order_mode === "MicroBatch"
|
|
447
|
+
? Math.max(1, Math.ceil(this.config.micro_batch_us / 1000))
|
|
448
|
+
: Math.max(1, Math.floor(this.config.order_timeout_ms / 2));
|
|
449
|
+
flushTimer = setInterval(() => order.flushDue(emitEvent), intervalMs);
|
|
450
|
+
}
|
|
451
|
+
let isCancelled = false;
|
|
452
|
+
let currentTransactionFilters = transactionFilters;
|
|
453
|
+
let currentAccountFilters = accountFilters;
|
|
454
|
+
const streamHolder = { current: null };
|
|
455
|
+
const cancel = () => {
|
|
456
|
+
isCancelled = true;
|
|
457
|
+
streamHolder.current?.end();
|
|
458
|
+
streamHolder.current = null;
|
|
459
|
+
if (flushTimer)
|
|
460
|
+
clearInterval(flushTimer);
|
|
461
|
+
events.close();
|
|
462
|
+
errors.close();
|
|
463
|
+
};
|
|
464
|
+
const update = async (nextTxFilters, nextAccFilters) => {
|
|
465
|
+
currentTransactionFilters = nextTxFilters;
|
|
466
|
+
currentAccountFilters = nextAccFilters;
|
|
467
|
+
const stream = streamHolder.current;
|
|
468
|
+
if (!stream)
|
|
469
|
+
return;
|
|
470
|
+
await new Promise((resolve, reject) => {
|
|
471
|
+
stream.write((0, subscribe_builder_js_1.buildSubscribeRequest)(currentTransactionFilters, currentAccountFilters), (err) => {
|
|
472
|
+
if (err)
|
|
473
|
+
reject(err);
|
|
474
|
+
else
|
|
475
|
+
resolve();
|
|
476
|
+
});
|
|
477
|
+
});
|
|
478
|
+
};
|
|
479
|
+
this.dexSubscribers.set(id, { cancel, update });
|
|
480
|
+
(async () => {
|
|
481
|
+
const autoReconnect = options?.autoReconnect !== false;
|
|
482
|
+
const maxBackoffMs = 60_000;
|
|
483
|
+
let backoffMs = this.config.retry_delay_ms;
|
|
484
|
+
try {
|
|
485
|
+
while (!isCancelled) {
|
|
486
|
+
try {
|
|
487
|
+
const stream = await this.client.subscribe();
|
|
488
|
+
streamHolder.current = stream;
|
|
489
|
+
await new Promise((resolve, reject) => {
|
|
490
|
+
stream.write((0, subscribe_builder_js_1.buildSubscribeRequest)(currentTransactionFilters, currentAccountFilters), (err) => {
|
|
491
|
+
if (err)
|
|
492
|
+
reject(err);
|
|
493
|
+
else
|
|
494
|
+
resolve();
|
|
495
|
+
});
|
|
496
|
+
});
|
|
497
|
+
backoffMs = this.config.retry_delay_ms;
|
|
498
|
+
await new Promise((resolve, reject) => {
|
|
499
|
+
const cleanup = () => {
|
|
500
|
+
stream.removeAllListeners();
|
|
501
|
+
if (streamHolder.current === stream) {
|
|
502
|
+
streamHolder.current = null;
|
|
503
|
+
}
|
|
504
|
+
};
|
|
505
|
+
stream.on("data", (update) => {
|
|
506
|
+
if (isCancelled)
|
|
507
|
+
return;
|
|
508
|
+
order.flushDue(emitEvent);
|
|
509
|
+
if (update.ping) {
|
|
510
|
+
stream.write(this.subscribePingPongRequest(), (werr) => {
|
|
511
|
+
if (werr && !isCancelled) {
|
|
512
|
+
errors.push(werr instanceof Error ? werr : new Error(String(werr)));
|
|
513
|
+
}
|
|
514
|
+
});
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
try {
|
|
518
|
+
const grpcRecvUs = Math.floor(Date.now() * 1000);
|
|
519
|
+
const converted = this.convertUpdate(update);
|
|
520
|
+
const tx = converted.transaction?.transaction;
|
|
521
|
+
if (tx) {
|
|
522
|
+
const fallbackSlot = YellowstoneGrpc.protobufNumber(converted.transaction?.slot ?? 0);
|
|
523
|
+
const fallbackTxIndex = YellowstoneGrpc.protobufNumber(tx.index ?? 0);
|
|
524
|
+
const txEvents = (0, yellowstone_parse_js_1.parseDexEventsFromGrpcTransactionInfo)(tx, converted.transaction?.slot ?? 0n, { blockTimeUs: converted.createdAtUs, grpcRecvUs, eventTypeFilter });
|
|
525
|
+
order.pushTransactionEvents(txEvents, fallbackSlot, fallbackTxIndex, emitEvent);
|
|
526
|
+
}
|
|
527
|
+
if (converted.account) {
|
|
528
|
+
const ev = this.parseAccountEvent(converted.account, grpcRecvUs, eventTypeFilter, converted.createdAtUs);
|
|
529
|
+
if (ev)
|
|
530
|
+
emitEvent(ev);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
catch (err) {
|
|
534
|
+
errors.push(err instanceof Error ? err : new Error(String(err)));
|
|
535
|
+
}
|
|
536
|
+
});
|
|
537
|
+
stream.on("error", (err) => {
|
|
538
|
+
cleanup();
|
|
539
|
+
reject(err);
|
|
540
|
+
});
|
|
541
|
+
stream.on("end", () => {
|
|
542
|
+
cleanup();
|
|
543
|
+
resolve();
|
|
544
|
+
});
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
catch (err) {
|
|
548
|
+
if (isCancelled)
|
|
549
|
+
break;
|
|
550
|
+
errors.push(err instanceof Error ? err : new Error(String(err)));
|
|
551
|
+
if (!autoReconnect)
|
|
552
|
+
break;
|
|
553
|
+
await new Promise((r) => setTimeout(r, backoffMs));
|
|
554
|
+
backoffMs = Math.min(backoffMs * 2, maxBackoffMs);
|
|
555
|
+
continue;
|
|
556
|
+
}
|
|
557
|
+
if (isCancelled || !autoReconnect)
|
|
558
|
+
break;
|
|
559
|
+
await new Promise((r) => setTimeout(r, backoffMs));
|
|
560
|
+
backoffMs = Math.min(backoffMs * 2, maxBackoffMs);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
finally {
|
|
564
|
+
streamHolder.current?.end();
|
|
565
|
+
streamHolder.current = null;
|
|
566
|
+
if (flushTimer)
|
|
567
|
+
clearInterval(flushTimer);
|
|
568
|
+
order.flushAll(emitEvent);
|
|
569
|
+
events.close();
|
|
570
|
+
errors.close();
|
|
571
|
+
this.dexSubscribers.delete(id);
|
|
572
|
+
}
|
|
573
|
+
})();
|
|
574
|
+
return Object.assign(events, {
|
|
575
|
+
id,
|
|
576
|
+
errors,
|
|
577
|
+
cancel: () => {
|
|
578
|
+
cancel();
|
|
579
|
+
this.dexSubscribers.delete(id);
|
|
580
|
+
},
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
/** 取消订阅 */
|
|
584
|
+
unsubscribe(subId) {
|
|
585
|
+
const sub = this.subscribers.get(subId);
|
|
586
|
+
if (sub) {
|
|
587
|
+
sub.cancel();
|
|
588
|
+
this.subscribers.delete(subId);
|
|
589
|
+
}
|
|
590
|
+
const dexSub = this.dexSubscribers.get(subId);
|
|
591
|
+
if (dexSub) {
|
|
592
|
+
dexSub.cancel();
|
|
593
|
+
this.dexSubscribers.delete(subId);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
/** 动态更新当前 DEX 订阅过滤器(与 Rust update_subscription 语义对齐)。 */
|
|
597
|
+
async updateSubscription(transactionFilters, accountFilters) {
|
|
598
|
+
const active = this.dexSubscribers.values().next().value;
|
|
599
|
+
if (!active?.update) {
|
|
600
|
+
throw new Error("No active DEX subscription");
|
|
601
|
+
}
|
|
602
|
+
await active.update(transactionFilters, accountFilters);
|
|
603
|
+
}
|
|
604
|
+
async update_subscription(transactionFilters, accountFilters) {
|
|
605
|
+
await this.updateSubscription(transactionFilters, accountFilters);
|
|
606
|
+
}
|
|
607
|
+
/** 获取最新区块哈希 */
|
|
608
|
+
async getLatestBlockhash(commitment) {
|
|
609
|
+
const resp = await this.client.getLatestBlockhash(commitment);
|
|
610
|
+
return {
|
|
611
|
+
slot: Number(resp.slot),
|
|
612
|
+
blockhash: resp.blockhash,
|
|
613
|
+
lastValidBlockHeight: Number(resp.lastValidBlockHeight),
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
/** 获取区块高度 */
|
|
617
|
+
async getBlockHeight(commitment) {
|
|
618
|
+
const resp = await this.client.getBlockHeight(commitment);
|
|
619
|
+
return Number(resp);
|
|
620
|
+
}
|
|
621
|
+
/** 获取当前 Slot */
|
|
622
|
+
async getSlot(commitment) {
|
|
623
|
+
const resp = await this.client.getSlot(commitment);
|
|
624
|
+
return Number(resp);
|
|
625
|
+
}
|
|
626
|
+
/** 获取服务器版本 */
|
|
627
|
+
async getVersion() {
|
|
628
|
+
const resp = await this.client.getVersion();
|
|
629
|
+
return String(resp);
|
|
630
|
+
}
|
|
631
|
+
/** 验证区块哈希是否有效 */
|
|
632
|
+
async isBlockhashValid(blockhash, commitment) {
|
|
633
|
+
const resp = await this.client.isBlockhashValid(blockhash, commitment);
|
|
634
|
+
return {
|
|
635
|
+
slot: Number(resp.slot),
|
|
636
|
+
valid: resp.valid,
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
/** 发送 Ping 请求 */
|
|
640
|
+
async ping(count) {
|
|
641
|
+
const resp = await this.client.ping(count);
|
|
642
|
+
return Number(resp);
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
exports.YellowstoneGrpc = YellowstoneGrpc;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.YellowstoneGrpc = void 0;
|
|
4
|
+
var client_js_1 = require("./client.js");
|
|
5
|
+
Object.defineProperty(exports, "YellowstoneGrpc", { enumerable: true, get: function () { return client_js_1.YellowstoneGrpc; } });
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 与 Rust `grpc::event_parser`(`pub use crate::core as event_parser`)对应:核心解析子集再导出。
|
|
3
|
+
*/
|
|
4
|
+
export { parseTransactionEvents, parseLogsOnly, parseTransactionWithListener, parseTransactionEventsStreaming, parseLogsStreaming, parseTransactionWithStreamingListener, parseLog, nowUs, type EventListener, type StreamingEventListener, } from "../core/unified_parser.js";
|
|
5
|
+
export type { DexEvent } from "../core/dex_event.js";
|
|
6
|
+
export type { EventMetadata } from "../core/metadata.js";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.nowUs = exports.parseLog = exports.parseTransactionWithStreamingListener = exports.parseLogsStreaming = exports.parseTransactionEventsStreaming = exports.parseTransactionWithListener = exports.parseLogsOnly = exports.parseTransactionEvents = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* 与 Rust `grpc::event_parser`(`pub use crate::core as event_parser`)对应:核心解析子集再导出。
|
|
6
|
+
*/
|
|
7
|
+
var unified_parser_js_1 = require("../core/unified_parser.js");
|
|
8
|
+
Object.defineProperty(exports, "parseTransactionEvents", { enumerable: true, get: function () { return unified_parser_js_1.parseTransactionEvents; } });
|
|
9
|
+
Object.defineProperty(exports, "parseLogsOnly", { enumerable: true, get: function () { return unified_parser_js_1.parseLogsOnly; } });
|
|
10
|
+
Object.defineProperty(exports, "parseTransactionWithListener", { enumerable: true, get: function () { return unified_parser_js_1.parseTransactionWithListener; } });
|
|
11
|
+
Object.defineProperty(exports, "parseTransactionEventsStreaming", { enumerable: true, get: function () { return unified_parser_js_1.parseTransactionEventsStreaming; } });
|
|
12
|
+
Object.defineProperty(exports, "parseLogsStreaming", { enumerable: true, get: function () { return unified_parser_js_1.parseLogsStreaming; } });
|
|
13
|
+
Object.defineProperty(exports, "parseTransactionWithStreamingListener", { enumerable: true, get: function () { return unified_parser_js_1.parseTransactionWithStreamingListener; } });
|
|
14
|
+
Object.defineProperty(exports, "parseLog", { enumerable: true, get: function () { return unified_parser_js_1.parseLog; } });
|
|
15
|
+
Object.defineProperty(exports, "nowUs", { enumerable: true, get: function () { return unified_parser_js_1.nowUs; } });
|