sol-parser-sdk 0.5.14 → 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.
Files changed (108) hide show
  1. package/NATIVE_ALIGNMENT.md +312 -0
  2. package/NATIVE_DAMM_FACTORY_ALIGNMENT_20261004.md +16 -0
  3. package/NATIVE_DAMM_FACTORY_EVIDENCE_20261004.json +55 -0
  4. package/NATIVE_MIGRATION.md +38 -0
  5. package/NATIVE_PUMPFUN_NATIVE_DEBIT_ALIGNMENT_20261004.md +18 -0
  6. package/NATIVE_PUMPFUN_NATIVE_DEBIT_EVIDENCE_20261004.json +57 -0
  7. package/NATIVE_PUMPFUN_SETTLEMENT_ALIGNMENT_20261004.md +11 -0
  8. package/NATIVE_PUMPFUN_SETTLEMENT_EVIDENCE_20261004.json +70 -0
  9. package/README.md +24 -1
  10. package/README_CN.md +21 -1
  11. package/dist/accounts/mod.js +7 -0
  12. package/dist/accounts/pumpfun.js +17 -0
  13. package/dist/accounts/pumpswap.js +18 -3
  14. package/dist/core/account_dispatcher_rpc.js +24 -4
  15. package/dist/core/account_fill_meteora.d.ts +1 -1
  16. package/dist/core/account_fill_meteora.js +12 -1
  17. package/dist/core/account_fill_raydium.js +12 -2
  18. package/dist/core/account_fill_raydium_launchlab.js +54 -0
  19. package/dist/core/clock.js +1 -1
  20. package/dist/core/common_filler_rpc.d.ts +2 -2
  21. package/dist/core/common_filler_rpc.js +66 -0
  22. package/dist/core/dex_event.d.ts +157 -0
  23. package/dist/core/metadata.d.ts +9 -5
  24. package/dist/core/metadata.js +28 -4
  25. package/dist/core/unified_parser.d.ts +7 -7
  26. package/dist/grpc/block_meta.d.ts +9 -0
  27. package/dist/grpc/block_meta.js +26 -0
  28. package/dist/grpc/client.d.ts +24 -9
  29. package/dist/grpc/client.js +129 -67
  30. package/dist/grpc/geyser_connect.d.ts +3 -3
  31. package/dist/grpc/geyser_connect.js +13 -15
  32. package/dist/grpc/log_instr_dedup.js +6 -0
  33. package/dist/grpc/native_client.d.ts +26 -0
  34. package/dist/grpc/native_client.js +101 -0
  35. package/dist/grpc/order_buffer.d.ts +1 -1
  36. package/dist/grpc/order_buffer.js +10 -9
  37. package/dist/grpc/program_ids.js +2 -0
  38. package/dist/grpc/protocol/LICENSE +202 -0
  39. package/dist/grpc/protocol/NOTICE +4 -0
  40. package/dist/grpc/protocol/geyser.d.ts +342 -0
  41. package/dist/grpc/protocol/geyser.js +37 -0
  42. package/dist/grpc/protocol/geyser.proto +326 -0
  43. package/dist/grpc/protocol/solana-storage.d.ts +139 -0
  44. package/dist/grpc/protocol/solana-storage.js +14 -0
  45. package/dist/grpc/protocol/solana-storage.proto +151 -0
  46. package/dist/grpc/rpc_to_grpc.d.ts +1 -1
  47. package/dist/grpc/subscribe_builder.d.ts +5 -3
  48. package/dist/grpc/subscribe_builder.js +11 -3
  49. package/dist/grpc/transaction_meta.d.ts +1 -1
  50. package/dist/grpc/types.d.ts +8 -8
  51. package/dist/grpc/types.js +15 -2
  52. package/dist/grpc/yellowstone_parse.d.ts +3 -3
  53. package/dist/grpc/yellowstone_parse.js +6 -8
  54. package/dist/grpc/yellowstone_transaction_adapter.d.ts +1 -1
  55. package/dist/index.d.ts +11 -1
  56. package/dist/index.js +23 -5
  57. package/dist/instr/inner.d.ts +2 -2
  58. package/dist/instr/inner.js +1 -1
  59. package/dist/instr/meteora_damm_ix.d.ts +1 -1
  60. package/dist/instr/meteora_damm_ix.js +41 -79
  61. package/dist/instr/meteora_dlmm_ix.d.ts +1 -1
  62. package/dist/instr/meteora_dlmm_ix.js +10 -0
  63. package/dist/instr/meteora_pools_ix.d.ts +1 -1
  64. package/dist/instr/mod.d.ts +1 -1
  65. package/dist/instr/orca_whirlpool_ix.d.ts +1 -1
  66. package/dist/instr/pump_fees_ix.d.ts +1 -1
  67. package/dist/instr/pumpfun_ix.d.ts +1 -1
  68. package/dist/instr/pumpfun_ix.js +16 -0
  69. package/dist/instr/pumpswap_ix.d.ts +1 -1
  70. package/dist/instr/pumpswap_ix.js +13 -5
  71. package/dist/instr/raydium_amm_v4_ix.d.ts +1 -1
  72. package/dist/instr/raydium_amm_v4_ix.js +9 -5
  73. package/dist/instr/raydium_clmm_ix.d.ts +1 -1
  74. package/dist/instr/raydium_cpmm_ix.d.ts +1 -1
  75. package/dist/instr/raydium_launchlab_ix.d.ts +1 -1
  76. package/dist/instr/raydium_launchlab_ix.js +62 -2
  77. package/dist/instr/utils.d.ts +2 -2
  78. package/dist/instr/utils.js +2 -7
  79. package/dist/liquidity_snapshot.d.ts +54 -0
  80. package/dist/liquidity_snapshot.js +85 -0
  81. package/dist/logs/meteora_damm.d.ts +17 -1
  82. package/dist/logs/meteora_damm.js +386 -12
  83. package/dist/logs/meteora_dlmm.d.ts +1 -1
  84. package/dist/logs/meteora_dlmm.js +10 -0
  85. package/dist/logs/optimized_matcher.d.ts +3 -3
  86. package/dist/logs/optimized_matcher.js +35 -1
  87. package/dist/logs/program_log_discriminators.d.ts +5 -0
  88. package/dist/logs/program_log_discriminators.js +5 -0
  89. package/dist/logs/pump.js +10 -0
  90. package/dist/logs/pump_amm.js +22 -1
  91. package/dist/logs/raydium_launchlab.js +19 -1
  92. package/dist/rpc_transaction.d.ts +4 -3
  93. package/dist/rpc_transaction.js +3 -2
  94. package/dist/shredstream/client.js +3 -7
  95. package/dist/shredstream/entries_decode.js +9 -85
  96. package/dist/shredstream/instruction_parse.d.ts +3 -3
  97. package/dist/shredstream/proto_types.d.ts +1 -1
  98. package/dist/shredstream/wire_to_shred_tx.d.ts +1 -1
  99. package/dist/shredstream/wire_to_shred_tx.js +9 -44
  100. package/dist/simulation_route.d.ts +6 -0
  101. package/dist/simulation_route.js +242 -0
  102. package/dist/stonkfun_registry.d.ts +30 -0
  103. package/dist/stonkfun_registry.js +137 -0
  104. package/dist/transaction_route.d.ts +84 -0
  105. package/dist/transaction_route.js +477 -0
  106. package/dist/wire_transaction.d.ts +35 -0
  107. package/dist/wire_transaction.js +191 -0
  108. package/package.json +7 -4
@@ -0,0 +1,477 @@
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.ROUTE_PROGRAMS = exports.STONKFUN_REWARD_PLATFORM_CONFIG = exports.STONKFUN_STANDARD_PLATFORM_CONFIG = exports.WSOL = exports.TOKEN_2022 = exports.TOKEN = exports.ZERO = void 0;
7
+ exports.stonkfunModeFromPlatformConfig = stonkfunModeFromPlatformConfig;
8
+ exports.analyzeRpcTransactionRoutes = analyzeRpcTransactionRoutes;
9
+ /** Opt-in execution evidence, aligned with Rust sol-parser-sdk 0.7.7. */
10
+ const bs58_1 = __importDefault(require("bs58"));
11
+ const wire_transaction_js_1 = require("./wire_transaction.js");
12
+ exports.ZERO = "11111111111111111111111111111111";
13
+ exports.TOKEN = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
14
+ exports.TOKEN_2022 = "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb";
15
+ exports.WSOL = "So11111111111111111111111111111111111111112";
16
+ exports.STONKFUN_STANDARD_PLATFORM_CONFIG = "4E876qZTE9FJMrBzgVtBrSrzz2TLivB5Y5QXPjB4gZL7";
17
+ exports.STONKFUN_REWARD_PLATFORM_CONFIG = "6BwHHDg3u1854jC8PDLXvR4spTcLNaoBxLJNGC4nTESt";
18
+ function stonkfunModeFromPlatformConfig(key) {
19
+ return key === exports.STONKFUN_STANDARD_PLATFORM_CONFIG
20
+ ? "Standard"
21
+ : key === exports.STONKFUN_REWARD_PLATFORM_CONFIG
22
+ ? "Reward"
23
+ : null;
24
+ }
25
+ exports.ROUTE_PROGRAMS = {
26
+ PumpFun: '6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P',
27
+ RaydiumClmm: "CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK",
28
+ RaydiumCpmm: "CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C",
29
+ RaydiumAmmV4: "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8",
30
+ LaunchLab: "LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj",
31
+ OrcaWhirlpool: "whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc",
32
+ MeteoraDammV2: "cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG",
33
+ MeteoraDlmm: "LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo",
34
+ PumpSwap: "pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA",
35
+ };
36
+ const hex = (values) => Buffer.from(values).toString("hex");
37
+ const SWAP = hex([248, 198, 158, 145, 225, 117, 135, 200]), V2 = hex([43, 4, 237, 11, 26, 201, 30, 98]);
38
+ const CPI = hex([143, 190, 90, 218, 196, 30, 51, 222]), CPO = hex([55, 217, 98, 86, 163, 74, 180, 173]);
39
+ const DLI = new Set([SWAP, hex([65, 75, 63, 76, 235, 91, 91, 136])]), DLO = new Set([
40
+ hex([250, 73, 101, 33, 38, 207, 75, 184]),
41
+ hex([43, 215, 247, 132, 137, 60, 243, 81]),
42
+ ]);
43
+ const LAB = new Map([
44
+ [hex([250, 234, 13, 123, 213, 156, 19, 236]), [true, true]],
45
+ [hex([24, 211, 116, 40, 105, 3, 153, 56]), [true, false]],
46
+ [hex([149, 39, 222, 155, 211, 124, 152, 26]), [false, true]],
47
+ [hex([95, 200, 71, 34, 8, 9, 11, 166]), [false, false]],
48
+ ]);
49
+ const PUMP = new Map([
50
+ [hex([198, 46, 21, 82, 180, 217, 232, 112]), [true, true]],
51
+ [hex([102, 6, 61, 18, 1, 218, 235, 234]), [true, false]],
52
+ [hex([51, 230, 133, 164, 1, 127, 131, 173]), [false, true]],
53
+ ]);
54
+ const CURVE_V2 = new Map([
55
+ [hex([194, 171, 28, 70, 104, 77, 91, 47]), [true, true]],
56
+ [hex([184, 23, 238, 97, 103, 197, 211, 61]), [true, false]],
57
+ [hex([93, 246, 130, 60, 231, 233, 64, 178]), [false, true]],
58
+ ]);
59
+ const CURVE_LEGACY = new Map([
60
+ [hex([56, 252, 116, 8, 158, 223, 205, 95]), [true, true]],
61
+ [hex([102, 6, 61, 18, 1, 218, 235, 234]), [true, false]],
62
+ [hex([51, 230, 133, 164, 1, 127, 131, 173]), [false, true]],
63
+ ]);
64
+ const account = (ix, i) => ix.accounts[i] ?? exports.ZERO;
65
+ function swap(ix, mints, graduated) {
66
+ const d = ix.data, n = ix.accounts.length, disc = d.subarray(0, 8).toString("hex"), a = (i) => account(ix, i);
67
+ const protocol = Object.keys(exports.ROUTE_PROGRAMS).find((p) => exports.ROUTE_PROGRAMS[p] === ix.program);
68
+ let pool, user, source, dest, pair = null, mode = null, exact = true, offset = 8, invert = false;
69
+ if (protocol === "RaydiumClmm" &&
70
+ (disc === SWAP || disc === V2) &&
71
+ n >= 10 &&
72
+ d.length >= 41) {
73
+ pool = a(2);
74
+ user = a(0);
75
+ source = a(3);
76
+ dest = a(4);
77
+ exact = d[40] !== 0;
78
+ if (disc === V2 && n >= 13)
79
+ pair = [a(11), a(12)];
80
+ }
81
+ else if (protocol === "OrcaWhirlpool" &&
82
+ (disc === SWAP || disc === V2) &&
83
+ d.length >= 42) {
84
+ const v2 = disc === V2, dir = d[41] !== 0;
85
+ if (n < (v2 ? 15 : 11))
86
+ return null;
87
+ pool = a(v2 ? 4 : 2);
88
+ user = a(v2 ? 3 : 1);
89
+ const x = v2 ? 7 : 3, y = v2 ? 9 : 5;
90
+ source = a(dir ? x : y);
91
+ dest = a(dir ? y : x);
92
+ exact = d[40] !== 0;
93
+ if (v2)
94
+ pair = dir ? [a(5), a(6)] : [a(6), a(5)];
95
+ }
96
+ else if (protocol === "RaydiumCpmm" &&
97
+ (disc === CPI || disc === CPO) &&
98
+ n >= 13) {
99
+ pool = a(3);
100
+ user = a(0);
101
+ source = a(4);
102
+ dest = a(5);
103
+ pair = [a(10), a(11)];
104
+ exact = disc === CPI;
105
+ invert = !exact;
106
+ }
107
+ else if (protocol === "MeteoraDammV2" && (disc === SWAP || disc === "414b3f4ceb5b5b88") && n >= 11) {
108
+ if (d.length < 24)
109
+ return null;
110
+ if (disc !== SWAP) {
111
+ if (d.length < 25 || d[24] > 2)
112
+ return null;
113
+ exact = d[24] !== 2;
114
+ }
115
+ pool = a(1);
116
+ user = a(8);
117
+ source = a(2);
118
+ dest = a(3);
119
+ // Resolve direction using user-account evidence.
120
+ }
121
+ else if (protocol === "MeteoraDlmm" &&
122
+ (DLI.has(disc) || DLO.has(disc)) &&
123
+ n >= 11) {
124
+ pool = a(0);
125
+ user = a(10);
126
+ source = a(4);
127
+ dest = a(5);
128
+ exact = DLI.has(disc);
129
+ invert = !exact;
130
+ }
131
+ else if ((protocol === "LaunchLab" || protocol === "PumpSwap") &&
132
+ (protocol === "LaunchLab" ? LAB : PUMP).has(disc)) {
133
+ const [buy, input] = (protocol === "LaunchLab" ? LAB : PUMP).get(disc);
134
+ exact = input;
135
+ if (n < (protocol === "LaunchLab" ? 18 : 21))
136
+ return null;
137
+ source = a(buy ? 6 : 5);
138
+ dest = a(buy ? 5 : 6);
139
+ if (protocol === "LaunchLab") {
140
+ pool = a(4);
141
+ user = a(0);
142
+ pair = buy ? [a(10), a(9)] : [a(9), a(10)];
143
+ mode = stonkfunModeFromPlatformConfig(a(3));
144
+ }
145
+ else {
146
+ pool = a(0);
147
+ user = a(1);
148
+ pair = buy ? [a(4), a(3)] : [a(3), a(4)];
149
+ }
150
+ }
151
+ else if (protocol === 'PumpFun' && CURVE_V2.has(disc) && n >= 16) {
152
+ const [buy, input] = CURVE_V2.get(disc);
153
+ exact = input;
154
+ pool = a(10);
155
+ user = a(13);
156
+ source = a(buy ? 15 : 14);
157
+ dest = a(buy ? 14 : 15);
158
+ pair = buy ? [a(2), a(1)] : [a(1), a(2)];
159
+ if (a(2) === exports.WSOL) {
160
+ if (buy)
161
+ source = user;
162
+ else
163
+ dest = user;
164
+ }
165
+ }
166
+ else if (protocol === 'PumpFun' && CURVE_LEGACY.has(disc) && n >= 12) {
167
+ const [buy, input] = CURVE_LEGACY.get(disc);
168
+ exact = input;
169
+ pool = a(3);
170
+ user = a(6);
171
+ source = a(buy ? 6 : 5);
172
+ dest = a(buy ? 5 : 6);
173
+ pair = buy ? [exports.WSOL, a(2)] : [a(2), exports.WSOL];
174
+ }
175
+ else if (protocol === "RaydiumAmmV4" &&
176
+ d.length >= 17 &&
177
+ [9, 11, 16, 17].includes(d[0])) {
178
+ const modern = d[0] === 16 || d[0] === 17;
179
+ if (n < (modern ? 8 : 17))
180
+ return null;
181
+ pool = a(1);
182
+ user = a(modern ? 7 : n - 1);
183
+ source = a(modern ? 5 : n - 3);
184
+ dest = a(modern ? 6 : n - 2);
185
+ offset = 1;
186
+ exact = d[0] === 9 || d[0] === 16;
187
+ invert = !exact;
188
+ }
189
+ else
190
+ return null;
191
+ if (d.length < offset + 16)
192
+ return null;
193
+ const first = d.readBigUInt64LE(offset), second = d.readBigUInt64LE(offset + 8);
194
+ return {
195
+ position: ix.position,
196
+ program: ix.program,
197
+ protocol: protocol,
198
+ pool,
199
+ trader: user,
200
+ input_account: source,
201
+ output_account: dest,
202
+ input_mint: mints.get(source) ?? (pair && pair[0] !== exports.ZERO ? pair[0] : null),
203
+ output_mint: mints.get(dest) ?? (pair && pair[1] !== exports.ZERO ? pair[1] : null),
204
+ amount_specified_is_input: exact,
205
+ specified_amount: invert ? second : first,
206
+ other_amount_threshold: invert ? first : second,
207
+ actual_input_amount: null,
208
+ actual_output_amount: null,
209
+ stonkfun_mode: mode,
210
+ stonkfun_graduated: protocol === "RaydiumCpmm" && graduated.has(pool),
211
+ };
212
+ }
213
+ const token = (ix) => ix.program === exports.TOKEN || ix.program === exports.TOKEN_2022;
214
+ const checked = (ix) => token(ix) &&
215
+ ix.data.length >= 10 &&
216
+ ix.data[0] === 12 &&
217
+ ix.accounts.length >= 4;
218
+ const withFee = (ix) => ix.program === exports.TOKEN_2022 &&
219
+ ix.data.length >= 19 &&
220
+ ix.data[0] === 26 &&
221
+ ix.data[1] === 1 &&
222
+ ix.accounts.length >= 4;
223
+ function transfer(ix, mints) {
224
+ if (!token(ix) || !ix.data.length)
225
+ return null;
226
+ let dest, offset, fee;
227
+ if (checked(ix)) {
228
+ dest = 2;
229
+ offset = 1;
230
+ fee = ix.program === exports.TOKEN ? 0n : null;
231
+ }
232
+ else if (withFee(ix)) {
233
+ dest = 2;
234
+ offset = 2;
235
+ fee = ix.data.readBigUInt64LE(11);
236
+ }
237
+ else if (ix.data[0] === 3 &&
238
+ ix.data.length >= 9 &&
239
+ ix.accounts.length >= 3) {
240
+ dest = 1;
241
+ offset = 1;
242
+ fee = 0n;
243
+ }
244
+ else
245
+ return null;
246
+ return {
247
+ position: ix.position,
248
+ program: ix.program,
249
+ source: account(ix, 0),
250
+ destination: account(ix, dest),
251
+ mint: mints.get(account(ix, 0)) ?? null,
252
+ amount: ix.data.readBigUInt64LE(offset),
253
+ withheld_fee: fee,
254
+ };
255
+ }
256
+ function descendant(parent, child) {
257
+ return (parent.outer_index === child.outer_index &&
258
+ (parent.inner_index === null
259
+ ? child.inner_index !== null
260
+ : child.inner_index !== null &&
261
+ child.inner_index > parent.inner_index &&
262
+ parent.stack_height !== null &&
263
+ child.stack_height !== null &&
264
+ child.stack_height > parent.stack_height));
265
+ }
266
+ const U64_MAX = (1n << 64n) - 1n;
267
+ function pumpfunNativeDebit(ix, children, leg) {
268
+ if (leg.protocol !== 'PumpFun' || ix.accounts.length < 17 || account(ix, 2) !== exports.WSOL || leg.input_account !== leg.trader || ix.position.stack_height === null)
269
+ return null;
270
+ const recipients = new Set([6, 8, 10, 16].map(i => account(ix, i)));
271
+ let total = 0n, paidPool = false;
272
+ for (const child of children) {
273
+ if (child.program !== exports.ZERO || child.data.length !== 12 || child.data.readUInt32LE(0) !== 2 || child.accounts.length < 2 || account(child, 0) !== leg.trader)
274
+ continue;
275
+ if (child.position.stack_height !== ix.position.stack_height + 1)
276
+ return null;
277
+ if (!recipients.has(account(child, 1)))
278
+ return null;
279
+ paidPool ||= account(child, 1) === leg.pool;
280
+ total += child.data.readBigUInt64LE(4);
281
+ if (total > U64_MAX)
282
+ return null;
283
+ }
284
+ return paidPool ? total : null;
285
+ }
286
+ function sum(values) {
287
+ if (!values.length || values.some((v) => v === null))
288
+ return null;
289
+ const value = values.reduce((n, v) => n + v, 0n);
290
+ return value <= U64_MAX ? value : null;
291
+ }
292
+ /** JSON-encoded or base64-encoded RPC response; amounts are exact bigint. */
293
+ function analyzeRpcTransactionRoutes(transaction, graduatedStonkfunPools = []) {
294
+ const root = transaction, tx = root.result ?? root;
295
+ if (!tx || !tx.meta || typeof tx.meta !== "object")
296
+ throw new Error("Transaction metadata missing");
297
+ if (!("err" in tx.meta))
298
+ throw new Error("Transaction execution status missing");
299
+ let body = tx.transaction;
300
+ if (Array.isArray(body)) {
301
+ if (body.length !== 2 || body[1] !== "base64")
302
+ throw new Error("Expected base64 wire encoding");
303
+ body = (0, wire_transaction_js_1.decodeWireTransaction)(Buffer.from(body[0], "base64")).transaction;
304
+ }
305
+ const message = body.message, meta = tx.meta;
306
+ if (!message || typeof message !== "object")
307
+ throw new Error("Expected compiled transaction");
308
+ const loaded = meta.loadedAddresses ?? {}, keys = message.accountKeys.map((k) => typeof k === "string" ? k : (k.pubkey ?? k.toBase58()));
309
+ keys.push(...(loaded.writable ?? []), ...(loaded.readonly ?? []));
310
+ const key = (i) => {
311
+ if (!Number.isInteger(i) || i < 0 || i >= keys.length)
312
+ throw Error("Invalid compiled account index");
313
+ return keys[i];
314
+ };
315
+ const groups = meta.innerInstructions ?? [], seen = new Set();
316
+ if (!Array.isArray(groups))
317
+ throw Error("Invalid compiled instruction groups");
318
+ for (const group of groups) {
319
+ if (!group || !Number.isInteger(group.index) || group.index < 0 ||
320
+ group.index >= message.instructions.length || seen.has(group.index) ||
321
+ !Array.isArray(group.instructions))
322
+ throw Error("Invalid compiled instruction group");
323
+ seen.add(group.index);
324
+ for (const ix of group.instructions)
325
+ if (!ix || (ix.stackHeight != null && (!Number.isInteger(ix.stackHeight) || ix.stackHeight < 2)))
326
+ throw Error("Invalid compiled stack height");
327
+ }
328
+ const invocations = [];
329
+ message.instructions.forEach((outer, i) => {
330
+ const batch = [
331
+ [outer, { outer_index: i, inner_index: null, stack_height: 1 }],
332
+ ];
333
+ for (const group of groups)
334
+ if (group.index === i)
335
+ group.instructions.forEach((ix, j) => batch.push([
336
+ ix,
337
+ {
338
+ outer_index: i,
339
+ inner_index: j,
340
+ stack_height: ix.stackHeight ?? null,
341
+ },
342
+ ]));
343
+ for (const [ix, position] of batch) {
344
+ if (ix.programIdIndex === undefined)
345
+ throw new Error("Expected compiled instructions, not jsonParsed");
346
+ const data = typeof ix.data === "string" ? bs58_1.default.decode(ix.data) : ix.data;
347
+ invocations.push({
348
+ position,
349
+ program: key(ix.programIdIndex),
350
+ accounts: Array.from(ix.accounts, (k) => key(k)),
351
+ data: Buffer.from(data),
352
+ });
353
+ }
354
+ });
355
+ const mints = new Map();
356
+ for (const balance of [
357
+ ...(meta.preTokenBalances ?? []),
358
+ ...(meta.postTokenBalances ?? []),
359
+ ]) {
360
+ if (bs58_1.default.decode(balance.mint).length === 32)
361
+ mints.set(key(balance.accountIndex), balance.mint);
362
+ }
363
+ for (const ix of invocations) {
364
+ if (checked(ix) || withFee(ix)) {
365
+ mints.set(account(ix, 0), account(ix, 1));
366
+ mints.set(account(ix, 2), account(ix, 1));
367
+ }
368
+ if (token(ix) &&
369
+ ix.accounts.length >= 2 &&
370
+ ((ix.data.length === 1 && ix.data[0] === 1) ||
371
+ (ix.data.length === 33 && [16, 18].includes(ix.data[0]))))
372
+ mints.set(account(ix, 0), account(ix, 1));
373
+ }
374
+ for (;;) {
375
+ const before = mints.size;
376
+ for (const ix of invocations)
377
+ if (token(ix) &&
378
+ ix.data.length >= 9 &&
379
+ ix.data[0] === 3 &&
380
+ ix.accounts.length >= 3) {
381
+ const mint = mints.get(account(ix, 0)) ?? mints.get(account(ix, 1));
382
+ if (mint) {
383
+ if (!mints.has(account(ix, 0)))
384
+ mints.set(account(ix, 0), mint);
385
+ if (!mints.has(account(ix, 1)))
386
+ mints.set(account(ix, 1), mint);
387
+ }
388
+ }
389
+ if (mints.size === before)
390
+ break;
391
+ }
392
+ mints.delete(exports.ZERO);
393
+ const route = {
394
+ signature: body.signatures?.[0] ?? bs58_1.default.encode(new Uint8Array(64)),
395
+ succeeded: meta.err == null,
396
+ legs: [],
397
+ transfers: [],
398
+ native_token_actions: [],
399
+ unknown_invocations: [],
400
+ };
401
+ const graduated = new Set(graduatedStonkfunPools);
402
+ const known = new Set([
403
+ exports.TOKEN,
404
+ exports.TOKEN_2022,
405
+ exports.ZERO,
406
+ "ComputeBudget111111111111111111111111111111",
407
+ "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
408
+ "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr",
409
+ ]);
410
+ invocations.forEach((ix, i) => {
411
+ const own = transfer(ix, mints);
412
+ if (own)
413
+ route.transfers.push(own);
414
+ const children = [];
415
+ for (const child of invocations.slice(i + 1)) {
416
+ if (!descendant(ix.position, child.position))
417
+ break;
418
+ children.push(child);
419
+ }
420
+ const nested = children
421
+ .map((c) => transfer(c, mints))
422
+ .filter((x) => x !== null), leg = swap(ix, mints, graduated);
423
+ if (leg) {
424
+ if (route.succeeded) {
425
+ leg.actual_input_amount = sum(nested
426
+ .filter((t) => t.source === leg.input_account)
427
+ .map((t) => t.amount));
428
+ leg.actual_output_amount = sum(nested
429
+ .filter((t) => t.destination === leg.output_account)
430
+ .map((t) => t.withheld_fee === null || t.withheld_fee > t.amount
431
+ ? null
432
+ : t.amount - t.withheld_fee));
433
+ }
434
+ route.legs.push(leg);
435
+ if (route.succeeded && leg.protocol === 'PumpFun' && leg.input_mint === exports.WSOL && leg.input_account === leg.trader)
436
+ leg.actual_input_amount = pumpfunNativeDebit(ix, children, leg);
437
+ }
438
+ else if (!known.has(ix.program))
439
+ route.unknown_invocations.push({
440
+ position: ix.position,
441
+ program: ix.program,
442
+ has_token_transfers: nested.length > 0,
443
+ has_known_swap_descendants: children.some((c) => swap(c, mints, graduated) !== null),
444
+ });
445
+ let target = null, action = null;
446
+ if (ix.program === exports.ZERO &&
447
+ ix.data.length === 12 &&
448
+ ix.data.readUInt32LE(0) === 2 &&
449
+ ix.accounts.length >= 2) {
450
+ target = account(ix, 1);
451
+ action = {
452
+ Fund: { source: account(ix, 0), lamports: ix.data.readBigUInt64LE(4) },
453
+ };
454
+ }
455
+ else if (token(ix)) {
456
+ if (ix.data.length === 1 && ix.data[0] === 17 && ix.accounts.length) {
457
+ target = account(ix, 0);
458
+ action = "SyncNative";
459
+ }
460
+ else if (ix.data.length === 1 &&
461
+ ix.data[0] === 9 &&
462
+ ix.accounts.length >= 3) {
463
+ target = account(ix, 0);
464
+ action = {
465
+ Close: { destination: account(ix, 1), authority: account(ix, 2) },
466
+ };
467
+ }
468
+ }
469
+ if (target && action && mints.get(target) === exports.WSOL)
470
+ route.native_token_actions.push({
471
+ position: ix.position,
472
+ account: target,
473
+ action,
474
+ });
475
+ });
476
+ return route;
477
+ }
@@ -0,0 +1,35 @@
1
+ export interface WireInstruction {
2
+ programIdIndex: number;
3
+ accounts: number[];
4
+ data: string;
5
+ }
6
+ export interface WireMessage {
7
+ header: {
8
+ numRequiredSignatures: number;
9
+ numReadonlySignedAccounts: number;
10
+ numReadonlyUnsignedAccounts: number;
11
+ };
12
+ accountKeys: string[];
13
+ recentBlockhash: string;
14
+ instructions: WireInstruction[];
15
+ addressTableLookups: {
16
+ accountKey: string;
17
+ writableIndexes: number[];
18
+ readonlyIndexes: number[];
19
+ }[];
20
+ config?: {
21
+ priorityFee?: bigint;
22
+ computeUnitLimit?: number;
23
+ loadedAccountsDataSizeLimit?: number;
24
+ heapSize?: number;
25
+ };
26
+ }
27
+ export interface DecodedWireTransaction {
28
+ signatures: string[];
29
+ message: WireMessage;
30
+ version: "legacy" | 0 | 1;
31
+ }
32
+ export declare function decodeWireTransaction(data: Uint8Array, offset?: number, requireComplete?: boolean): {
33
+ transaction: DecodedWireTransaction;
34
+ length: number;
35
+ };
@@ -0,0 +1,191 @@
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.decodeWireTransaction = decodeWireTransaction;
7
+ /** Native canonical Solana Legacy, V0 and V1 decoder; no Rust runtime. */
8
+ const bs58_1 = __importDefault(require("bs58"));
9
+ class Reader {
10
+ data;
11
+ pos;
12
+ constructor(data, offset) {
13
+ this.data = data;
14
+ this.pos = offset;
15
+ }
16
+ take(n) {
17
+ if (!Number.isSafeInteger(n) || n < 0 || this.pos + n > this.data.length)
18
+ throw new Error("Truncated transaction");
19
+ const value = this.data.slice(this.pos, this.pos + n);
20
+ this.pos += n;
21
+ return value;
22
+ }
23
+ uint(n = 1) {
24
+ const bytes = this.take(n);
25
+ let value = 0;
26
+ for (let i = n - 1; i >= 0; i--)
27
+ value = value * 256 + bytes[i];
28
+ return value;
29
+ }
30
+ u64() {
31
+ const b = this.take(8);
32
+ let value = 0n;
33
+ for (let i = 7; i >= 0; i--)
34
+ value = value * 256n + BigInt(b[i]);
35
+ return value;
36
+ }
37
+ short() {
38
+ let value = 0;
39
+ for (let i = 0; i < 3; i++) {
40
+ const b = this.uint();
41
+ if (i === 2 && b > 3)
42
+ throw new Error("Invalid short-u16");
43
+ value |= (b & 127) << (7 * i);
44
+ if (!(b & 128)) {
45
+ if (i && b === 0)
46
+ throw new Error("Noncanonical short-u16");
47
+ return value;
48
+ }
49
+ }
50
+ throw new Error("Invalid short-u16");
51
+ }
52
+ }
53
+ function decodeWireTransaction(data, offset = 0, requireComplete = true) {
54
+ if (!Number.isInteger(offset) || offset < 0 || offset >= data.length)
55
+ throw new Error("Invalid wire offset");
56
+ const r = new Reader(data, offset);
57
+ let version = "legacy";
58
+ let signatures = [];
59
+ let header;
60
+ let keys;
61
+ let hash;
62
+ let instructions = [];
63
+ const lookups = [];
64
+ let config;
65
+ if (data[offset] === 129) {
66
+ r.take(1);
67
+ version = 1;
68
+ header = r.take(3);
69
+ const mask = r.uint(4);
70
+ hash = r.take(32);
71
+ if (mask & ~31 || ((mask & 3) !== 0 && (mask & 3) !== 3))
72
+ throw new Error("Invalid V1 config mask");
73
+ const count = r.uint(), keyCount = r.uint();
74
+ if (count > 64 || keyCount > 64 || header[0] > 12)
75
+ throw new Error("V1 transaction limit exceeded");
76
+ keys = Array.from({ length: keyCount }, () => r.take(32));
77
+ config = {};
78
+ if (mask & 3)
79
+ config.priorityFee = r.u64();
80
+ if (mask & 4)
81
+ config.computeUnitLimit = r.uint(4);
82
+ if (mask & 8)
83
+ config.loadedAccountsDataSizeLimit = r.uint(4);
84
+ if (mask & 16)
85
+ config.heapSize = r.uint(4);
86
+ if (config.heapSize !== undefined &&
87
+ (config.heapSize < 32768 ||
88
+ config.heapSize > 262144 ||
89
+ config.heapSize % 1024))
90
+ throw new Error("Invalid heap size");
91
+ const headers = Array.from({ length: count }, () => [r.uint(), r.uint(), r.uint(2)]);
92
+ instructions = headers.map(([programIdIndex, n, length]) => ({
93
+ programIdIndex,
94
+ accounts: Array.from(r.take(n)),
95
+ data: bs58_1.default.encode(r.take(length)),
96
+ }));
97
+ signatures = Array.from({ length: header[0] }, () => r.take(64));
98
+ if (r.pos - offset > 4096)
99
+ throw new Error("V1 transaction exceeds 4096 bytes");
100
+ }
101
+ else {
102
+ const sigCount = r.short();
103
+ if (sigCount > 127)
104
+ throw new Error("Too many signatures");
105
+ signatures = Array.from({ length: sigCount }, () => r.take(64));
106
+ const first = r.uint();
107
+ if (first & 128) {
108
+ if (first !== 128)
109
+ throw new Error("Unknown transaction version");
110
+ version = 0;
111
+ header = r.take(3);
112
+ }
113
+ else
114
+ header = Uint8Array.from([first, ...r.take(2)]);
115
+ const keyCount = r.short();
116
+ if (keyCount > 256)
117
+ throw new Error("Too many account keys");
118
+ keys = Array.from({ length: keyCount }, () => r.take(32));
119
+ hash = r.take(32);
120
+ const count = r.short();
121
+ for (let i = 0; i < count; i++) {
122
+ const programIdIndex = r.uint();
123
+ const accounts = Array.from(r.take(r.short()));
124
+ const payload = r.take(r.short());
125
+ instructions.push({
126
+ programIdIndex,
127
+ accounts,
128
+ data: bs58_1.default.encode(payload),
129
+ });
130
+ }
131
+ if (version === 0) {
132
+ const count = r.short();
133
+ for (let i = 0; i < count; i++) {
134
+ const key = r.take(32);
135
+ const writableIndexes = Array.from(r.take(r.short()));
136
+ const readonlyIndexes = Array.from(r.take(r.short()));
137
+ lookups.push({
138
+ accountKey: bs58_1.default.encode(key),
139
+ writableIndexes,
140
+ readonlyIndexes,
141
+ });
142
+ }
143
+ }
144
+ if (signatures.length !== header[0])
145
+ throw new Error("Signature count does not match header");
146
+ }
147
+ if (header[0] > keys.length ||
148
+ header[1] > header[0] ||
149
+ header[2] > keys.length - header[0])
150
+ throw new Error("Invalid message header");
151
+ if (version === 1) {
152
+ if (header[1] >= header[0])
153
+ throw new Error("V1 requires a writable fee payer");
154
+ if (new Set(keys.map((k) => bs58_1.default.encode(k))).size !== keys.length)
155
+ throw new Error("Duplicate V1 accounts");
156
+ for (const ix of instructions)
157
+ if (ix.programIdIndex === 0 ||
158
+ ix.programIdIndex >= keys.length ||
159
+ ix.accounts.some((i) => i >= keys.length))
160
+ throw new Error("Invalid V1 instruction index");
161
+ }
162
+ const accountCount = keys.length + lookups.reduce((n, l) => n + l.writableIndexes.length + l.readonlyIndexes.length, 0);
163
+ if (accountCount > 256)
164
+ throw new Error("Too many resolved account keys");
165
+ for (const ix of instructions)
166
+ if (ix.programIdIndex >= keys.length || ix.accounts.some(i => i >= accountCount))
167
+ throw new Error("Invalid instruction index");
168
+ if (requireComplete && r.pos !== data.length)
169
+ throw new Error("Trailing transaction bytes");
170
+ const message = {
171
+ header: {
172
+ numRequiredSignatures: header[0],
173
+ numReadonlySignedAccounts: header[1],
174
+ numReadonlyUnsignedAccounts: header[2],
175
+ },
176
+ accountKeys: keys.map((k) => bs58_1.default.encode(k)),
177
+ recentBlockhash: bs58_1.default.encode(hash),
178
+ instructions,
179
+ addressTableLookups: lookups,
180
+ };
181
+ if (config)
182
+ message.config = config;
183
+ return {
184
+ transaction: {
185
+ signatures: signatures.map((s) => bs58_1.default.encode(s)),
186
+ message,
187
+ version,
188
+ },
189
+ length: r.pos - offset,
190
+ };
191
+ }