sol-parser-sdk 0.5.15 → 0.5.16
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 +17 -1
- package/README_CN.md +14 -1
- package/dist/accounts/mod.js +7 -0
- package/dist/core/account_dispatcher_rpc.js +24 -4
- 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/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/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/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/raydium_launchlab.js +19 -1
- package/dist/rpc_transaction.d.ts +4 -3
- package/dist/rpc_transaction.js +3 -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
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
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.StonkFunPoolRegistry = void 0;
|
|
7
|
+
/** Caller-owned migration provenance; transactions never mutate a global registry. */
|
|
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 validate(p) {
|
|
12
|
+
if (!(0, transaction_route_js_1.stonkfunModeFromPlatformConfig)(p.platform_config) ||
|
|
13
|
+
p.curve_pool === p.pool ||
|
|
14
|
+
p.base_mint === p.quote_mint)
|
|
15
|
+
throw new Error("Invalid StonkFun registry identity");
|
|
16
|
+
for (const key of [p.curve_pool, p.pool, p.base_mint, p.quote_mint])
|
|
17
|
+
if (key === transaction_route_js_1.ZERO || bs58_1.default.decode(key).length !== 32)
|
|
18
|
+
throw new Error("Invalid registry key");
|
|
19
|
+
if (bs58_1.default.decode(p.migration_signature).length !== 64 ||
|
|
20
|
+
typeof p.migration_slot !== "bigint" ||
|
|
21
|
+
p.migration_slot < 0n ||
|
|
22
|
+
p.migration_slot >= 1n << 64n)
|
|
23
|
+
throw new Error("Invalid migration provenance");
|
|
24
|
+
}
|
|
25
|
+
const equal = (a, b) => Object.keys(a).every((k) => a[k] ===
|
|
26
|
+
b[k]);
|
|
27
|
+
class StonkFunPoolRegistry {
|
|
28
|
+
pools = new Map();
|
|
29
|
+
constructor(entries = []) {
|
|
30
|
+
for (const p of entries) {
|
|
31
|
+
validate(p);
|
|
32
|
+
if (this.pools.has(p.pool))
|
|
33
|
+
throw new Error("Duplicate registry entry");
|
|
34
|
+
this.pools.set(p.pool, Object.freeze({ ...p }));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
get(pool) {
|
|
38
|
+
return this.pools.get(pool);
|
|
39
|
+
}
|
|
40
|
+
verifiedCpmmPools() {
|
|
41
|
+
return [...this.pools.keys()].sort();
|
|
42
|
+
}
|
|
43
|
+
poolsForBaseMint(mint) {
|
|
44
|
+
return this.verifiedCpmmPools()
|
|
45
|
+
.map((k) => this.pools.get(k))
|
|
46
|
+
.filter((p) => p.base_mint === mint);
|
|
47
|
+
}
|
|
48
|
+
toJSON() {
|
|
49
|
+
return {
|
|
50
|
+
pools: this.verifiedCpmmPools().map((k) => ({
|
|
51
|
+
...this.pools.get(k),
|
|
52
|
+
migration_slot: this.pools.get(k).migration_slot.toString(),
|
|
53
|
+
})),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
static fromJSON(data) {
|
|
57
|
+
return new StonkFunPoolRegistry(data.pools.map((p) => ({
|
|
58
|
+
...p,
|
|
59
|
+
migration_slot: BigInt(p.migration_slot),
|
|
60
|
+
})));
|
|
61
|
+
}
|
|
62
|
+
observeMigrations(entries, succeeded) {
|
|
63
|
+
if (!succeeded)
|
|
64
|
+
return 0;
|
|
65
|
+
const pending = new Map();
|
|
66
|
+
for (const p of entries) {
|
|
67
|
+
validate(p);
|
|
68
|
+
const prior = pending.get(p.pool) ?? this.pools.get(p.pool);
|
|
69
|
+
if (prior && !equal(prior, p))
|
|
70
|
+
throw new Error("Conflicting migration provenance");
|
|
71
|
+
pending.set(p.pool, p);
|
|
72
|
+
}
|
|
73
|
+
let count = 0;
|
|
74
|
+
for (const [k, p] of pending) {
|
|
75
|
+
if (!this.pools.has(k))
|
|
76
|
+
count++;
|
|
77
|
+
this.pools.set(k, Object.freeze({ ...p }));
|
|
78
|
+
}
|
|
79
|
+
return count;
|
|
80
|
+
}
|
|
81
|
+
observeRpcTransaction(transaction) {
|
|
82
|
+
const root = transaction, tx = root.result ?? root;
|
|
83
|
+
if (!tx.meta || typeof tx.meta !== "object")
|
|
84
|
+
throw new Error("Transaction metadata missing");
|
|
85
|
+
if (!("err" in tx.meta))
|
|
86
|
+
throw new Error("Transaction execution status missing");
|
|
87
|
+
if (tx.meta.err !== null)
|
|
88
|
+
return 0;
|
|
89
|
+
// Use the same compiled index/group validation as route analysis.
|
|
90
|
+
(0, transaction_route_js_1.analyzeRpcTransactionRoutes)(transaction);
|
|
91
|
+
let body = tx.transaction;
|
|
92
|
+
if (Array.isArray(body)) {
|
|
93
|
+
if (body.length !== 2 || body[1] !== "base64")
|
|
94
|
+
throw new Error("Expected base64 encoding");
|
|
95
|
+
body = (0, wire_transaction_js_1.decodeWireTransaction)(Buffer.from(body[0], "base64")).transaction;
|
|
96
|
+
}
|
|
97
|
+
const loaded = tx.meta.loadedAddresses ?? {}, keys = [
|
|
98
|
+
...body.message.accountKeys.map((k) => typeof k === "string" ? k : k.pubkey),
|
|
99
|
+
...(loaded.writable ?? []),
|
|
100
|
+
...(loaded.readonly ?? []),
|
|
101
|
+
];
|
|
102
|
+
const instructions = [...body.message.instructions];
|
|
103
|
+
for (const group of tx.meta.innerInstructions ?? [])
|
|
104
|
+
instructions.push(...group.instructions);
|
|
105
|
+
const entries = [];
|
|
106
|
+
for (const ix of instructions) {
|
|
107
|
+
if (ix.programIdIndex === undefined)
|
|
108
|
+
throw new Error("Expected compiled instructions");
|
|
109
|
+
const d = typeof ix.data === "string" ? bs58_1.default.decode(ix.data) : ix.data;
|
|
110
|
+
if (keys[ix.programIdIndex] !== transaction_route_js_1.ROUTE_PROGRAMS.LaunchLab ||
|
|
111
|
+
Buffer.from(d).subarray(0, 8).toString("hex") !== "885cc8671cda908c" ||
|
|
112
|
+
ix.accounts.length < 28)
|
|
113
|
+
continue;
|
|
114
|
+
const a = Array.from(ix.accounts, (k) => keys[k] ?? transaction_route_js_1.ZERO);
|
|
115
|
+
if (a[4] !== transaction_route_js_1.ROUTE_PROGRAMS.RaydiumCpmm ||
|
|
116
|
+
!(0, transaction_route_js_1.stonkfunModeFromPlatformConfig)(a[3]))
|
|
117
|
+
continue;
|
|
118
|
+
if ([a[17], a[5], a[1], a[2]].includes(transaction_route_js_1.ZERO) ||
|
|
119
|
+
a[17] === a[5] ||
|
|
120
|
+
a[1] === a[2])
|
|
121
|
+
continue;
|
|
122
|
+
if (typeof tx.slot === "number" && !Number.isSafeInteger(tx.slot))
|
|
123
|
+
throw new Error("Unsafe slot integer");
|
|
124
|
+
entries.push({
|
|
125
|
+
curve_pool: a[17],
|
|
126
|
+
pool: a[5],
|
|
127
|
+
base_mint: a[1],
|
|
128
|
+
quote_mint: a[2],
|
|
129
|
+
platform_config: a[3],
|
|
130
|
+
migration_signature: body.signatures[0],
|
|
131
|
+
migration_slot: BigInt(tx.slot),
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
return this.observeMigrations(entries, true);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
exports.StonkFunPoolRegistry = StonkFunPoolRegistry;
|