sol-parser-sdk 0.5.15 → 0.5.17
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/NATIVE_ALIGNMENT.md +312 -0
- package/NATIVE_DAMM_FACTORY_ALIGNMENT_20261004.md +16 -0
- package/NATIVE_DAMM_FACTORY_EVIDENCE_20261004.json +55 -0
- package/NATIVE_MIGRATION.md +38 -0
- package/NATIVE_PUMPFUN_NATIVE_DEBIT_ALIGNMENT_20261004.md +18 -0
- package/NATIVE_PUMPFUN_NATIVE_DEBIT_EVIDENCE_20261004.json +57 -0
- package/NATIVE_PUMPFUN_SETTLEMENT_ALIGNMENT_20261004.md +11 -0
- package/NATIVE_PUMPFUN_SETTLEMENT_EVIDENCE_20261004.json +70 -0
- package/README.md +24 -1
- package/README_CN.md +21 -1
- package/dist/accounts/mod.js +7 -0
- package/dist/core/account_dispatcher_rpc.js +50 -6
- package/dist/core/account_fill_pumpfun.js +7 -16
- package/dist/core/account_fill_raydium.js +12 -2
- package/dist/core/account_fill_raydium_launchlab.js +6 -0
- package/dist/core/clock.js +1 -1
- package/dist/core/dex_event.d.ts +30 -0
- package/dist/core/metadata.d.ts +9 -5
- package/dist/core/metadata.js +28 -4
- package/dist/core/unified_parser.d.ts +7 -7
- package/dist/grpc/block_meta.d.ts +9 -0
- package/dist/grpc/block_meta.js +26 -0
- package/dist/grpc/client.d.ts +24 -9
- package/dist/grpc/client.js +129 -67
- package/dist/grpc/geyser_connect.d.ts +3 -3
- package/dist/grpc/geyser_connect.js +13 -15
- package/dist/grpc/native_client.d.ts +26 -0
- package/dist/grpc/native_client.js +101 -0
- package/dist/grpc/order_buffer.d.ts +1 -1
- package/dist/grpc/order_buffer.js +10 -9
- package/dist/grpc/program_ids.js +2 -0
- package/dist/grpc/protocol/LICENSE +202 -0
- package/dist/grpc/protocol/NOTICE +4 -0
- package/dist/grpc/protocol/geyser.d.ts +342 -0
- package/dist/grpc/protocol/geyser.js +37 -0
- package/dist/grpc/protocol/geyser.proto +326 -0
- package/dist/grpc/protocol/solana-storage.d.ts +139 -0
- package/dist/grpc/protocol/solana-storage.js +14 -0
- package/dist/grpc/protocol/solana-storage.proto +151 -0
- package/dist/grpc/rpc_to_grpc.d.ts +1 -1
- package/dist/grpc/rpc_to_grpc.js +3 -2
- package/dist/grpc/subscribe_builder.d.ts +5 -3
- package/dist/grpc/subscribe_builder.js +11 -3
- package/dist/grpc/transaction_meta.d.ts +1 -1
- package/dist/grpc/types.d.ts +8 -8
- package/dist/grpc/types.js +7 -2
- package/dist/grpc/yellowstone_parse.d.ts +3 -3
- package/dist/grpc/yellowstone_parse.js +6 -8
- package/dist/grpc/yellowstone_transaction_adapter.d.ts +1 -1
- package/dist/grpc/yellowstone_transaction_adapter.js +1 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +23 -5
- package/dist/instr/inner.d.ts +2 -2
- package/dist/instr/inner.js +1 -1
- package/dist/instr/meteora_damm_ix.d.ts +1 -1
- package/dist/instr/meteora_dlmm_ix.d.ts +1 -1
- package/dist/instr/meteora_pools_ix.d.ts +1 -1
- package/dist/instr/mod.d.ts +1 -1
- package/dist/instr/orca_whirlpool_ix.d.ts +1 -1
- package/dist/instr/pump_fees_ix.d.ts +1 -1
- package/dist/instr/pumpfun_ix.d.ts +1 -1
- package/dist/instr/pumpfun_ix.js +3 -3
- package/dist/instr/pumpswap_ix.d.ts +1 -1
- package/dist/instr/raydium_amm_v4_ix.d.ts +1 -1
- package/dist/instr/raydium_amm_v4_ix.js +9 -5
- package/dist/instr/raydium_clmm_ix.d.ts +1 -1
- package/dist/instr/raydium_cpmm_ix.d.ts +1 -1
- package/dist/instr/raydium_launchlab_ix.d.ts +1 -1
- package/dist/instr/raydium_launchlab_ix.js +62 -2
- package/dist/instr/utils.d.ts +2 -2
- package/dist/instr/utils.js +2 -7
- package/dist/liquidity_snapshot.d.ts +54 -0
- package/dist/liquidity_snapshot.js +85 -0
- package/dist/logs/meteora_damm.d.ts +1 -1
- package/dist/logs/meteora_damm.js +4 -2
- package/dist/logs/meteora_dlmm.d.ts +1 -1
- package/dist/logs/optimized_matcher.d.ts +3 -3
- package/dist/logs/pump.js +11 -0
- package/dist/logs/raydium_launchlab.js +19 -1
- package/dist/rpc_transaction.d.ts +4 -3
- package/dist/rpc_transaction.js +6 -2
- package/dist/shredstream/client.js +3 -7
- package/dist/shredstream/entries_decode.js +9 -85
- package/dist/shredstream/instruction_parse.d.ts +3 -3
- package/dist/shredstream/proto_types.d.ts +1 -1
- package/dist/shredstream/wire_to_shred_tx.d.ts +1 -1
- package/dist/shredstream/wire_to_shred_tx.js +9 -44
- package/dist/simulation_route.d.ts +6 -0
- package/dist/simulation_route.js +242 -0
- package/dist/stonkfun_registry.d.ts +30 -0
- package/dist/stonkfun_registry.js +137 -0
- package/dist/transaction_route.d.ts +84 -0
- package/dist/transaction_route.js +477 -0
- package/dist/wire_transaction.d.ts +35 -0
- package/dist/wire_transaction.js +191 -0
- package/package.json +7 -4
|
@@ -13,9 +13,10 @@ export declare function applyAccountFillsToLogEvents(events: DexEvent[], msg: Me
|
|
|
13
13
|
* 解析已获取的 `VersionedTransactionResponse`(顺序:指令 → 日志 → 账户/数据填充)。
|
|
14
14
|
*/
|
|
15
15
|
export declare function parseRpcTransaction(tx: VersionedTransactionResponse, signature: string, filter?: EventTypeFilter, options?: {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
slot?: bigint | string | number;
|
|
17
|
+
grpcRecvUs?: bigint | string | number;
|
|
18
|
+
txIndex?: bigint | string | number;
|
|
19
|
+
blockTimeUs?: bigint | string | number;
|
|
19
20
|
}): {
|
|
20
21
|
ok: true;
|
|
21
22
|
events: DexEvent[];
|
package/dist/rpc_transaction.js
CHANGED
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.fillDataRpc = exports.fillAccountsFromTransactionDataRpc = void 0;
|
|
7
7
|
exports.applyAccountFillsToLogEvents = applyAccountFillsToLogEvents;
|
|
8
8
|
exports.parseRpcTransaction = parseRpcTransaction;
|
|
9
|
+
const metadata_js_1 = require("./core/metadata.js");
|
|
9
10
|
/**
|
|
10
11
|
* RPC 交易解析:外层 + 内层指令 → 日志 → `fillAccountsFromTransactionDataRpc` → `fillDataRpc`。
|
|
11
12
|
*/
|
|
@@ -472,6 +473,9 @@ function applyAccountFillsToLogEvents(events, msg, meta) {
|
|
|
472
473
|
* 解析已获取的 `VersionedTransactionResponse`(顺序:指令 → 日志 → 账户/数据填充)。
|
|
473
474
|
*/
|
|
474
475
|
function parseRpcTransaction(tx, signature, filter, options) {
|
|
476
|
+
// Failed transactions roll back every instruction, including earlier create logs.
|
|
477
|
+
if (tx.meta?.err != null)
|
|
478
|
+
return { ok: true, events: [] };
|
|
475
479
|
const msg = tx.transaction?.message;
|
|
476
480
|
if (!msg || !(0, rpc_invoke_map_js_1.isCompiledVersionedMessage)(msg)) {
|
|
477
481
|
return {
|
|
@@ -483,8 +487,8 @@ function parseRpcTransaction(tx, signature, filter, options) {
|
|
|
483
487
|
};
|
|
484
488
|
}
|
|
485
489
|
const meta = tx.meta ?? null;
|
|
486
|
-
const slot = tx.slot;
|
|
487
|
-
const blockTimeUs = options?.blockTimeUs ?? (tx.blockTime != null ? tx.blockTime *
|
|
490
|
+
const slot = (0, metadata_js_1.exactU64)(options?.slot ?? tx.slot, "slot");
|
|
491
|
+
const blockTimeUs = options?.blockTimeUs ?? (tx.blockTime != null ? (0, metadata_js_1.exactI64)(tx.blockTime) * 1000000n : undefined);
|
|
488
492
|
const grpcRecvUs = options?.grpcRecvUs ?? Math.floor(Date.now() * 1000);
|
|
489
493
|
const txIndex = options?.txIndex ?? 0;
|
|
490
494
|
const rb = recentBlockhashBytes(msg.recentBlockhash);
|
|
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.ShredStreamClient = exports.ShredEventQueue = void 0;
|
|
37
|
+
const metadata_js_1 = require("../core/metadata.js");
|
|
37
38
|
/**
|
|
38
39
|
* ShredStream 客户端:与 Rust `shredstream/client.rs` 对齐(gRPC + bincode 解码 + `parseTransactionEvents`)。
|
|
39
40
|
*/
|
|
@@ -120,7 +121,7 @@ function setGrpcRecvUsMut(event, grpcRecvUs) {
|
|
|
120
121
|
return;
|
|
121
122
|
const inner = event[key];
|
|
122
123
|
if (inner?.metadata)
|
|
123
|
-
inner.metadata.grpc_recv_us = grpcRecvUs;
|
|
124
|
+
inner.metadata.grpc_recv_us = (0, metadata_js_1.exactI64)(grpcRecvUs);
|
|
124
125
|
}
|
|
125
126
|
class ShredStreamClient {
|
|
126
127
|
endpoint;
|
|
@@ -394,10 +395,5 @@ class ShredStreamClient {
|
|
|
394
395
|
}
|
|
395
396
|
exports.ShredStreamClient = ShredStreamClient;
|
|
396
397
|
function toSlotNumber(slot) {
|
|
397
|
-
|
|
398
|
-
return slot;
|
|
399
|
-
if (typeof slot === "bigint")
|
|
400
|
-
return Number(slot);
|
|
401
|
-
const n = Number(slot);
|
|
402
|
-
return Number.isFinite(n) ? Math.floor(n) : 0;
|
|
398
|
+
return (0, metadata_js_1.exactU64)(slot, "ShredStream slot");
|
|
403
399
|
}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.bincodeVecEntryCount = bincodeVecEntryCount;
|
|
4
7
|
exports.decodeCompactU16 = decodeCompactU16;
|
|
@@ -6,6 +9,8 @@ exports.parseTransaction = parseTransaction;
|
|
|
6
9
|
exports.decodeEntriesBincodeFlat = decodeEntriesBincodeFlat;
|
|
7
10
|
exports.decodeEntriesBincodeNested = decodeEntriesBincodeNested;
|
|
8
11
|
exports.decodeShredstreamEntriesBincode = decodeShredstreamEntriesBincode;
|
|
12
|
+
const bs58_1 = __importDefault(require("bs58"));
|
|
13
|
+
const wire_transaction_js_1 = require("../wire_transaction.js");
|
|
9
14
|
const wire_to_shred_tx_js_1 = require("./wire_to_shred_tx.js");
|
|
10
15
|
const MAX_VEC_ENTRIES = 100_000;
|
|
11
16
|
function readU64LE(buf, offset) {
|
|
@@ -43,94 +48,13 @@ function decodeCompactU16(buf, pos) {
|
|
|
43
48
|
}
|
|
44
49
|
/** 返回 (txWireLength, signatures);失败返回 null */
|
|
45
50
|
function parseTransaction(buf, pos) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
return
|
|
49
|
-
const sigCountEnc = decodeCompactU16(buf, pos);
|
|
50
|
-
if (!sigCountEnc)
|
|
51
|
-
return null;
|
|
52
|
-
let p = pos + sigCountEnc.bytes;
|
|
53
|
-
const sigCount = sigCountEnc.value;
|
|
54
|
-
const sigsEnd = p + sigCount * 64;
|
|
55
|
-
if (sigsEnd > buf.length)
|
|
56
|
-
return null;
|
|
57
|
-
const sigs = [];
|
|
58
|
-
for (let i = 0; i < sigCount; i++) {
|
|
59
|
-
sigs.push(buf.subarray(p, p + 64));
|
|
60
|
-
p += 64;
|
|
51
|
+
try {
|
|
52
|
+
const { transaction, length } = (0, wire_transaction_js_1.decodeWireTransaction)(buf, pos, false);
|
|
53
|
+
return { txLen: length, sigs: transaction.signatures.map(s => bs58_1.default.decode(s)) };
|
|
61
54
|
}
|
|
62
|
-
|
|
63
|
-
return null;
|
|
64
|
-
const msgFirst = buf[p];
|
|
65
|
-
const isV0 = msgFirst >= 0x80;
|
|
66
|
-
if (isV0)
|
|
67
|
-
p += 1;
|
|
68
|
-
p += 3;
|
|
69
|
-
if (p > buf.length)
|
|
70
|
-
return null;
|
|
71
|
-
const acctEnc = decodeCompactU16(buf, p);
|
|
72
|
-
if (!acctEnc)
|
|
73
|
-
return null;
|
|
74
|
-
p += acctEnc.bytes;
|
|
75
|
-
p += acctEnc.value * 32;
|
|
76
|
-
if (p > buf.length)
|
|
77
|
-
return null;
|
|
78
|
-
p += 32;
|
|
79
|
-
if (p > buf.length)
|
|
80
|
-
return null;
|
|
81
|
-
const ixCountEnc = decodeCompactU16(buf, p);
|
|
82
|
-
if (!ixCountEnc)
|
|
55
|
+
catch {
|
|
83
56
|
return null;
|
|
84
|
-
p += ixCountEnc.bytes;
|
|
85
|
-
const ixCount = ixCountEnc.value;
|
|
86
|
-
for (let ix = 0; ix < ixCount; ix++) {
|
|
87
|
-
p += 1;
|
|
88
|
-
if (p > buf.length)
|
|
89
|
-
return null;
|
|
90
|
-
const acctLenEnc = decodeCompactU16(buf, p);
|
|
91
|
-
if (!acctLenEnc)
|
|
92
|
-
return null;
|
|
93
|
-
p += acctLenEnc.bytes;
|
|
94
|
-
p += acctLenEnc.value;
|
|
95
|
-
if (p > buf.length)
|
|
96
|
-
return null;
|
|
97
|
-
const dataLenEnc = decodeCompactU16(buf, p);
|
|
98
|
-
if (!dataLenEnc)
|
|
99
|
-
return null;
|
|
100
|
-
p += dataLenEnc.bytes;
|
|
101
|
-
p += dataLenEnc.value;
|
|
102
|
-
if (p > buf.length)
|
|
103
|
-
return null;
|
|
104
|
-
}
|
|
105
|
-
if (isV0) {
|
|
106
|
-
if (p >= buf.length)
|
|
107
|
-
return null;
|
|
108
|
-
const atlCountEnc = decodeCompactU16(buf, p);
|
|
109
|
-
if (!atlCountEnc)
|
|
110
|
-
return null;
|
|
111
|
-
p += atlCountEnc.bytes;
|
|
112
|
-
const atlCount = atlCountEnc.value;
|
|
113
|
-
for (let atl = 0; atl < atlCount; atl++) {
|
|
114
|
-
p += 32;
|
|
115
|
-
if (p > buf.length)
|
|
116
|
-
return null;
|
|
117
|
-
const wLenEnc = decodeCompactU16(buf, p);
|
|
118
|
-
if (!wLenEnc)
|
|
119
|
-
return null;
|
|
120
|
-
p += wLenEnc.bytes;
|
|
121
|
-
p += wLenEnc.value;
|
|
122
|
-
if (p > buf.length)
|
|
123
|
-
return null;
|
|
124
|
-
const rLenEnc = decodeCompactU16(buf, p);
|
|
125
|
-
if (!rLenEnc)
|
|
126
|
-
return null;
|
|
127
|
-
p += rLenEnc.bytes;
|
|
128
|
-
p += rLenEnc.value;
|
|
129
|
-
if (p > buf.length)
|
|
130
|
-
return null;
|
|
131
|
-
}
|
|
132
57
|
}
|
|
133
|
-
return { txLen: p - start, sigs };
|
|
134
58
|
}
|
|
135
59
|
class BatchDecoder {
|
|
136
60
|
buffer = new Uint8Array(0);
|
|
@@ -21,7 +21,7 @@ export type ShredWasmTx = {
|
|
|
21
21
|
accounts: string[];
|
|
22
22
|
instructions?: ShredWasmCompiledIx[];
|
|
23
23
|
/** 缺省则按仅静态账户处理 */
|
|
24
|
-
messageVersion?: "legacy" | "v0";
|
|
24
|
+
messageVersion?: "legacy" | "v0" | "v1";
|
|
25
25
|
header?: MessageHeader;
|
|
26
26
|
recentBlockhash?: Uint8Array;
|
|
27
27
|
addressTableLookups?: ShredAddressTableLookup[];
|
|
@@ -29,6 +29,6 @@ export type ShredWasmTx = {
|
|
|
29
29
|
/**
|
|
30
30
|
* 使用已解析的完整账户表(静态+ALT)解析外层指令。
|
|
31
31
|
*/
|
|
32
|
-
export declare function dexEventsFromShredWasmTxWithFullKeys(tx: ShredWasmTx, fullAccountKeys: string[], slot: number, txIndex: number, grpcRecvUs: number, eventTypeFilter?: EventTypeFilter): DexEvent[];
|
|
32
|
+
export declare function dexEventsFromShredWasmTxWithFullKeys(tx: ShredWasmTx, fullAccountKeys: string[], slot: number | bigint | string, txIndex: number | bigint | string, grpcRecvUs: number | bigint | string, eventTypeFilter?: EventTypeFilter): DexEvent[];
|
|
33
33
|
/** 仅静态账户表(无 RPC 时;V0+ALT 缺失账户以默认 pubkey 占位) */
|
|
34
|
-
export declare function dexEventsFromShredWasmTx(tx: ShredWasmTx, slot: number, txIndex: number, grpcRecvUs: number, eventTypeFilter?: EventTypeFilter): DexEvent[];
|
|
34
|
+
export declare function dexEventsFromShredWasmTx(tx: ShredWasmTx, slot: number | bigint | string, txIndex: number | bigint | string, grpcRecvUs: number | bigint | string, eventTypeFilter?: EventTypeFilter): DexEvent[];
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { ShredWasmTx } from
|
|
1
|
+
import type { ShredWasmTx } from './instruction_parse.js';
|
|
2
2
|
export declare function wireBytesToShredWasmTx(raw: Uint8Array): ShredWasmTx | null;
|
|
@@ -4,54 +4,19 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.wireBytesToShredWasmTx = wireBytesToShredWasmTx;
|
|
7
|
-
/**
|
|
8
|
-
* 线格式交易字节 → `ShredWasmTx`(与原 wasm-pack 展开字段对齐,供 `parseInstructionUnified`)。
|
|
9
|
-
*/
|
|
10
|
-
const web3_js_1 = require("@solana/web3.js");
|
|
7
|
+
/** Native wire decoding shared with RPC routes, including V1 without ALT. */
|
|
11
8
|
const bs58_1 = __importDefault(require("bs58"));
|
|
9
|
+
const wire_transaction_js_1 = require("../wire_transaction.js");
|
|
12
10
|
function wireBytesToShredWasmTx(raw) {
|
|
13
11
|
try {
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
if (!sig0)
|
|
12
|
+
const { transaction: tx } = (0, wire_transaction_js_1.decodeWireTransaction)(raw), msg = tx.message;
|
|
13
|
+
if (!tx.signatures[0])
|
|
17
14
|
return null;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
writableIndexes: new Uint8Array(l.writableIndexes),
|
|
24
|
-
readonlyIndexes: new Uint8Array(l.readonlyIndexes),
|
|
25
|
-
}));
|
|
26
|
-
const instructions = msg.compiledInstructions.map((ix) => ({
|
|
27
|
-
programIdIndex: ix.programIdIndex,
|
|
28
|
-
accounts: new Uint8Array(ix.accountKeyIndexes),
|
|
29
|
-
data: new Uint8Array(ix.data),
|
|
30
|
-
}));
|
|
31
|
-
return {
|
|
32
|
-
signature,
|
|
33
|
-
accounts: msg.staticAccountKeys.map((k) => k.toBase58()),
|
|
34
|
-
instructions,
|
|
35
|
-
messageVersion: "v0",
|
|
36
|
-
header: msg.header,
|
|
37
|
-
recentBlockhash: Uint8Array.from(bs58_1.default.decode(msg.recentBlockhash)),
|
|
38
|
-
addressTableLookups: lookups,
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
const m = msg;
|
|
42
|
-
const instructions = m.compiledInstructions.map((ix) => ({
|
|
43
|
-
programIdIndex: ix.programIdIndex,
|
|
44
|
-
accounts: new Uint8Array(ix.accountKeyIndexes),
|
|
45
|
-
data: new Uint8Array(ix.data),
|
|
46
|
-
}));
|
|
47
|
-
return {
|
|
48
|
-
signature,
|
|
49
|
-
accounts: m.staticAccountKeys.map((k) => k.toBase58()),
|
|
50
|
-
instructions,
|
|
51
|
-
messageVersion: "legacy",
|
|
52
|
-
header: m.header,
|
|
53
|
-
recentBlockhash: Uint8Array.from(bs58_1.default.decode(m.recentBlockhash)),
|
|
54
|
-
};
|
|
15
|
+
return { signature: tx.signatures[0], accounts: msg.accountKeys,
|
|
16
|
+
instructions: msg.instructions.map(ix => ({ programIdIndex: ix.programIdIndex, accounts: Uint8Array.from(ix.accounts), data: bs58_1.default.decode(ix.data) })),
|
|
17
|
+
messageVersion: tx.version === 'legacy' ? 'legacy' : tx.version === 0 ? 'v0' : 'v1', header: msg.header,
|
|
18
|
+
recentBlockhash: bs58_1.default.decode(msg.recentBlockhash),
|
|
19
|
+
addressTableLookups: msg.addressTableLookups.map(l => ({ ...l, writableIndexes: Uint8Array.from(l.writableIndexes), readonlyIndexes: Uint8Array.from(l.readonlyIndexes) })) };
|
|
55
20
|
}
|
|
56
21
|
catch {
|
|
57
22
|
return null;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type TransactionRoute } from "./transaction_route.js";
|
|
2
|
+
/** Original wire plus simulateTransaction response. Parsed SPL transfers and ATA setup.
|
|
3
|
+
* Unsupported parsed CPI fail explicitly; raw/compiled CPI are preserved.
|
|
4
|
+
* V0 ALT requires the existing compiled route API and loadedAddresses.
|
|
5
|
+
*/
|
|
6
|
+
export declare function analyzeSimulationRoutes(wire: Uint8Array, response: unknown, graduatedPools?: readonly string[]): TransactionRoute;
|
|
@@ -0,0 +1,242 @@
|
|
|
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.analyzeSimulationRoutes = analyzeSimulationRoutes;
|
|
7
|
+
/** Explicit simulation evidence adapter. No RPC or transaction reserialization. */
|
|
8
|
+
const bs58_1 = __importDefault(require("bs58"));
|
|
9
|
+
const wire_transaction_js_1 = require("./wire_transaction.js");
|
|
10
|
+
const transaction_route_js_1 = require("./transaction_route.js");
|
|
11
|
+
function unsigned(value, bits) {
|
|
12
|
+
if (typeof value === "number" && !Number.isSafeInteger(value))
|
|
13
|
+
throw Error("Unsafe simulation integer");
|
|
14
|
+
if ((typeof value !== "number" && typeof value !== "string") ||
|
|
15
|
+
!/^[0-9]+$/.test(String(value)))
|
|
16
|
+
throw Error("Invalid simulation integer");
|
|
17
|
+
const n = BigInt(value);
|
|
18
|
+
if (n < 0n || n >= 1n << BigInt(bits))
|
|
19
|
+
throw Error("Simulation integer outside range");
|
|
20
|
+
return n;
|
|
21
|
+
}
|
|
22
|
+
/** Original wire plus simulateTransaction response. Parsed SPL transfers and ATA setup.
|
|
23
|
+
* Unsupported parsed CPI fail explicitly; raw/compiled CPI are preserved.
|
|
24
|
+
* V0 ALT requires the existing compiled route API and loadedAddresses.
|
|
25
|
+
*/
|
|
26
|
+
function analyzeSimulationRoutes(wire, response, graduatedPools = []) {
|
|
27
|
+
const tx = (0, wire_transaction_js_1.decodeWireTransaction)(wire).transaction;
|
|
28
|
+
if (tx.message.addressTableLookups.length)
|
|
29
|
+
throw Error("V0 ALT addresses unavailable; use compiled route input with loadedAddresses");
|
|
30
|
+
const root = response, value = root?.result?.value;
|
|
31
|
+
if (root?.error ||
|
|
32
|
+
!value ||
|
|
33
|
+
typeof value !== "object" ||
|
|
34
|
+
!("err" in value) ||
|
|
35
|
+
!("innerInstructions" in value))
|
|
36
|
+
throw Error("Simulation response missing execution metadata");
|
|
37
|
+
if (value.innerInstructions !== null &&
|
|
38
|
+
!Array.isArray(value.innerInstructions))
|
|
39
|
+
throw Error("Invalid simulation inner instructions");
|
|
40
|
+
const keys = tx.message.accountKeys;
|
|
41
|
+
const index = (key) => {
|
|
42
|
+
if (typeof key !== "string")
|
|
43
|
+
throw Error("Missing simulation account key");
|
|
44
|
+
const n = keys.indexOf(key);
|
|
45
|
+
if (n < 0)
|
|
46
|
+
throw Error("Simulation account absent from transaction");
|
|
47
|
+
return n;
|
|
48
|
+
};
|
|
49
|
+
const validIndex = (n) => {
|
|
50
|
+
if (typeof n !== "number" ||
|
|
51
|
+
!Number.isInteger(n) ||
|
|
52
|
+
n < 0 ||
|
|
53
|
+
n >= keys.length)
|
|
54
|
+
throw Error("Invalid simulation account index");
|
|
55
|
+
return n;
|
|
56
|
+
};
|
|
57
|
+
const seen = new Set();
|
|
58
|
+
const groups = (value.innerInstructions ?? []).map((group) => {
|
|
59
|
+
if (!group ||
|
|
60
|
+
typeof group !== "object" ||
|
|
61
|
+
!Number.isInteger(group.index) ||
|
|
62
|
+
group.index < 0 ||
|
|
63
|
+
group.index >= tx.message.instructions.length ||
|
|
64
|
+
seen.has(group.index) ||
|
|
65
|
+
!Array.isArray(group.instructions))
|
|
66
|
+
throw Error("Invalid simulation instruction group");
|
|
67
|
+
seen.add(group.index);
|
|
68
|
+
return {
|
|
69
|
+
index: group.index,
|
|
70
|
+
instructions: group.instructions.map((ix) => {
|
|
71
|
+
if (!ix || typeof ix !== "object")
|
|
72
|
+
throw Error("Invalid simulation instruction");
|
|
73
|
+
if (ix.stackHeight !== undefined &&
|
|
74
|
+
ix.stackHeight !== null &&
|
|
75
|
+
(!Number.isInteger(ix.stackHeight) || ix.stackHeight < 2))
|
|
76
|
+
throw Error("Invalid simulation stack height");
|
|
77
|
+
const stackHeight = ix.stackHeight ?? null;
|
|
78
|
+
if (ix.programIdIndex !== undefined) {
|
|
79
|
+
if (ix.parsed !== undefined ||
|
|
80
|
+
typeof ix.data !== "string" ||
|
|
81
|
+
!Array.isArray(ix.accounts))
|
|
82
|
+
throw Error("Invalid compiled simulation instruction");
|
|
83
|
+
bs58_1.default.decode(ix.data);
|
|
84
|
+
return {
|
|
85
|
+
programIdIndex: validIndex(ix.programIdIndex),
|
|
86
|
+
accounts: ix.accounts.map(validIndex),
|
|
87
|
+
data: ix.data,
|
|
88
|
+
stackHeight,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
const programIdIndex = index(ix.programId);
|
|
92
|
+
if (ix.parsed === undefined) {
|
|
93
|
+
if (typeof ix.data !== "string" || !Array.isArray(ix.accounts))
|
|
94
|
+
throw Error("Invalid raw simulation instruction");
|
|
95
|
+
bs58_1.default.decode(ix.data);
|
|
96
|
+
return {
|
|
97
|
+
programIdIndex,
|
|
98
|
+
accounts: ix.accounts.map(index),
|
|
99
|
+
data: ix.data,
|
|
100
|
+
stackHeight,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
if (!ix.parsed ||
|
|
104
|
+
typeof ix.parsed !== "object" ||
|
|
105
|
+
Array.isArray(ix.parsed) ||
|
|
106
|
+
!ix.parsed.info ||
|
|
107
|
+
typeof ix.parsed.info !== "object" ||
|
|
108
|
+
Array.isArray(ix.parsed.info))
|
|
109
|
+
throw Error("Unsupported parsed simulation instruction");
|
|
110
|
+
const setup = simulationAccountSetup(ix.programId, ix.parsed.type, ix.parsed.info);
|
|
111
|
+
if (setup)
|
|
112
|
+
return {
|
|
113
|
+
programIdIndex,
|
|
114
|
+
accounts: setup.accounts.map(index),
|
|
115
|
+
data: bs58_1.default.encode(setup.data),
|
|
116
|
+
stackHeight,
|
|
117
|
+
};
|
|
118
|
+
if (ix.programId !== transaction_route_js_1.TOKEN && ix.programId !== transaction_route_js_1.TOKEN_2022)
|
|
119
|
+
throw Error("Unsupported parsed simulation program");
|
|
120
|
+
const { type, info } = ix.parsed;
|
|
121
|
+
if (!info ||
|
|
122
|
+
!["transfer", "transferChecked", "transferCheckedWithFee"].includes(type))
|
|
123
|
+
throw Error("Unsupported parsed simulation instruction");
|
|
124
|
+
const authority = info.authority ?? info.multisigAuthority, signers = info.signers ?? [];
|
|
125
|
+
if (!Array.isArray(signers))
|
|
126
|
+
throw Error("Invalid simulation signers");
|
|
127
|
+
let accounts, data;
|
|
128
|
+
if (type === "transfer") {
|
|
129
|
+
accounts = [info.source, info.destination, authority, ...signers];
|
|
130
|
+
data = Buffer.alloc(9);
|
|
131
|
+
data[0] = 3;
|
|
132
|
+
data.writeBigUInt64LE(unsigned(info.amount, 64), 1);
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
const withFee = type === "transferCheckedWithFee";
|
|
136
|
+
if (withFee && ix.programId !== transaction_route_js_1.TOKEN_2022)
|
|
137
|
+
throw Error("Transfer fee requires Token-2022");
|
|
138
|
+
if (!info.tokenAmount ||
|
|
139
|
+
typeof info.tokenAmount !== "object" ||
|
|
140
|
+
Array.isArray(info.tokenAmount))
|
|
141
|
+
throw Error("Invalid simulation token amount");
|
|
142
|
+
const amount = unsigned(info.tokenAmount?.amount, 64), decimals = Number(unsigned(info.tokenAmount?.decimals, 8));
|
|
143
|
+
accounts = [
|
|
144
|
+
info.source,
|
|
145
|
+
info.mint,
|
|
146
|
+
info.destination,
|
|
147
|
+
authority,
|
|
148
|
+
...signers,
|
|
149
|
+
];
|
|
150
|
+
data = Buffer.alloc(withFee ? 19 : 10);
|
|
151
|
+
if (withFee) {
|
|
152
|
+
data[0] = 26;
|
|
153
|
+
data[1] = 1;
|
|
154
|
+
data.writeBigUInt64LE(amount, 2);
|
|
155
|
+
data[10] = decimals;
|
|
156
|
+
data.writeBigUInt64LE(unsigned(info.feeAmount, 64), 11);
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
data[0] = 12;
|
|
160
|
+
data.writeBigUInt64LE(amount, 1);
|
|
161
|
+
data[9] = decimals;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return {
|
|
165
|
+
programIdIndex,
|
|
166
|
+
accounts: accounts.map(index),
|
|
167
|
+
data: bs58_1.default.encode(data),
|
|
168
|
+
stackHeight,
|
|
169
|
+
};
|
|
170
|
+
}),
|
|
171
|
+
};
|
|
172
|
+
});
|
|
173
|
+
return (0, transaction_route_js_1.analyzeRpcTransactionRoutes)({ transaction: tx, meta: { ...value, innerInstructions: groups } }, graduatedPools);
|
|
174
|
+
}
|
|
175
|
+
/** Reconstruct only understood setup layouts; extension names are deliberately bounded. */
|
|
176
|
+
function simulationAccountSetup(program, type, info) {
|
|
177
|
+
const pubkey = (key) => {
|
|
178
|
+
if (typeof key !== "string")
|
|
179
|
+
throw Error("Invalid simulation public key");
|
|
180
|
+
const bytes = Buffer.from(bs58_1.default.decode(key));
|
|
181
|
+
if (bytes.length !== 32)
|
|
182
|
+
throw Error("Invalid simulation public key");
|
|
183
|
+
return bytes;
|
|
184
|
+
};
|
|
185
|
+
if (program === transaction_route_js_1.ZERO && type === "createAccount") {
|
|
186
|
+
const data = Buffer.alloc(52);
|
|
187
|
+
data.writeBigUInt64LE(unsigned(info.lamports, 64), 4);
|
|
188
|
+
data.writeBigUInt64LE(unsigned(info.space, 64), 12);
|
|
189
|
+
pubkey(info.owner).copy(data, 20);
|
|
190
|
+
return { accounts: [info.source, info.newAccount], data };
|
|
191
|
+
}
|
|
192
|
+
if (program === transaction_route_js_1.ZERO && (type === "transfer" || type === "allocate")) {
|
|
193
|
+
const data = Buffer.alloc(12);
|
|
194
|
+
data.writeUInt32LE(type === "transfer" ? 2 : 8, 0);
|
|
195
|
+
data.writeBigUInt64LE(unsigned(type === "transfer" ? info.lamports : info.space, 64), 4);
|
|
196
|
+
return { accounts: type === "transfer" ? [info.source, info.destination] : [info.account], data };
|
|
197
|
+
}
|
|
198
|
+
if (program === transaction_route_js_1.ZERO && type === "assign") {
|
|
199
|
+
const data = Buffer.alloc(36);
|
|
200
|
+
data.writeUInt32LE(1, 0);
|
|
201
|
+
pubkey(info.owner).copy(data, 4);
|
|
202
|
+
return { accounts: [info.account], data };
|
|
203
|
+
}
|
|
204
|
+
if (program !== transaction_route_js_1.TOKEN && program !== transaction_route_js_1.TOKEN_2022)
|
|
205
|
+
return null;
|
|
206
|
+
if (typeof type === "string" && ["mintTo", "mintToChecked", "burn", "burnChecked"].includes(type)) {
|
|
207
|
+
const minting = type.startsWith("mintTo"), checked = type.endsWith("Checked");
|
|
208
|
+
const authority = minting ? (info.mintAuthority ?? info.multisigMintAuthority) : (info.authority ?? info.multisigAuthority);
|
|
209
|
+
const signers = info.signers === undefined ? [] : info.signers;
|
|
210
|
+
if (!Array.isArray(signers))
|
|
211
|
+
throw Error("Invalid simulation signers");
|
|
212
|
+
const amount = checked ? info.tokenAmount : info;
|
|
213
|
+
if (!amount || typeof amount !== "object" || Array.isArray(amount))
|
|
214
|
+
throw Error("Invalid simulation token amount");
|
|
215
|
+
const data = Buffer.alloc(checked ? 10 : 9);
|
|
216
|
+
data[0] = checked ? (minting ? 14 : 15) : (minting ? 7 : 8);
|
|
217
|
+
data.writeBigUInt64LE(unsigned(amount.amount, 64), 1);
|
|
218
|
+
if (checked)
|
|
219
|
+
data[9] = Number(unsigned(amount.decimals, 8));
|
|
220
|
+
return { accounts: [...(minting ? [info.mint, info.account] : [info.account, info.mint]), authority, ...signers], data };
|
|
221
|
+
}
|
|
222
|
+
if (type === "initializeImmutableOwner")
|
|
223
|
+
return { accounts: [info.account], data: Buffer.from([22]) };
|
|
224
|
+
if (type === "initializeAccount3")
|
|
225
|
+
return {
|
|
226
|
+
accounts: [info.account, info.mint],
|
|
227
|
+
data: Buffer.concat([Buffer.from([18]), pubkey(info.owner)]),
|
|
228
|
+
};
|
|
229
|
+
if (type === "getAccountDataSize") {
|
|
230
|
+
if (!Array.isArray(info.extensionTypes))
|
|
231
|
+
throw Error("Invalid simulation extension types");
|
|
232
|
+
const data = Buffer.alloc(1 + info.extensionTypes.length * 2);
|
|
233
|
+
data[0] = 21;
|
|
234
|
+
info.extensionTypes.forEach((extension, i) => {
|
|
235
|
+
if (extension !== "immutableOwner")
|
|
236
|
+
throw Error("Unsupported simulation extension type");
|
|
237
|
+
data.writeUInt16LE(7, 1 + 2 * i);
|
|
238
|
+
});
|
|
239
|
+
return { accounts: [info.mint], data };
|
|
240
|
+
}
|
|
241
|
+
return null;
|
|
242
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface StonkFunGraduatedPool {
|
|
2
|
+
curve_pool: string;
|
|
3
|
+
pool: string;
|
|
4
|
+
base_mint: string;
|
|
5
|
+
quote_mint: string;
|
|
6
|
+
platform_config: string;
|
|
7
|
+
migration_signature: string;
|
|
8
|
+
migration_slot: bigint;
|
|
9
|
+
}
|
|
10
|
+
export declare class StonkFunPoolRegistry {
|
|
11
|
+
private pools;
|
|
12
|
+
constructor(entries?: Iterable<StonkFunGraduatedPool>);
|
|
13
|
+
get(pool: string): Readonly<StonkFunGraduatedPool> | undefined;
|
|
14
|
+
verifiedCpmmPools(): string[];
|
|
15
|
+
poolsForBaseMint(mint: string): Readonly<StonkFunGraduatedPool>[];
|
|
16
|
+
toJSON(): {
|
|
17
|
+
pools: {
|
|
18
|
+
migration_slot: string;
|
|
19
|
+
curve_pool: string;
|
|
20
|
+
pool: string;
|
|
21
|
+
base_mint: string;
|
|
22
|
+
quote_mint: string;
|
|
23
|
+
platform_config: string;
|
|
24
|
+
migration_signature: string;
|
|
25
|
+
}[];
|
|
26
|
+
};
|
|
27
|
+
static fromJSON(data: ReturnType<StonkFunPoolRegistry["toJSON"]>): StonkFunPoolRegistry;
|
|
28
|
+
observeMigrations(entries: Iterable<StonkFunGraduatedPool>, succeeded: boolean): number;
|
|
29
|
+
observeRpcTransaction(transaction: unknown): number;
|
|
30
|
+
}
|