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.
Files changed (91) 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 +17 -1
  10. package/README_CN.md +14 -1
  11. package/dist/accounts/mod.js +7 -0
  12. package/dist/core/account_dispatcher_rpc.js +24 -4
  13. package/dist/core/account_fill_raydium.js +12 -2
  14. package/dist/core/account_fill_raydium_launchlab.js +6 -0
  15. package/dist/core/clock.js +1 -1
  16. package/dist/core/dex_event.d.ts +30 -0
  17. package/dist/core/metadata.d.ts +9 -5
  18. package/dist/core/metadata.js +28 -4
  19. package/dist/core/unified_parser.d.ts +7 -7
  20. package/dist/grpc/block_meta.d.ts +9 -0
  21. package/dist/grpc/block_meta.js +26 -0
  22. package/dist/grpc/client.d.ts +24 -9
  23. package/dist/grpc/client.js +129 -67
  24. package/dist/grpc/geyser_connect.d.ts +3 -3
  25. package/dist/grpc/geyser_connect.js +13 -15
  26. package/dist/grpc/native_client.d.ts +26 -0
  27. package/dist/grpc/native_client.js +101 -0
  28. package/dist/grpc/order_buffer.d.ts +1 -1
  29. package/dist/grpc/order_buffer.js +10 -9
  30. package/dist/grpc/program_ids.js +2 -0
  31. package/dist/grpc/protocol/LICENSE +202 -0
  32. package/dist/grpc/protocol/NOTICE +4 -0
  33. package/dist/grpc/protocol/geyser.d.ts +342 -0
  34. package/dist/grpc/protocol/geyser.js +37 -0
  35. package/dist/grpc/protocol/geyser.proto +326 -0
  36. package/dist/grpc/protocol/solana-storage.d.ts +139 -0
  37. package/dist/grpc/protocol/solana-storage.js +14 -0
  38. package/dist/grpc/protocol/solana-storage.proto +151 -0
  39. package/dist/grpc/rpc_to_grpc.d.ts +1 -1
  40. package/dist/grpc/subscribe_builder.d.ts +5 -3
  41. package/dist/grpc/subscribe_builder.js +11 -3
  42. package/dist/grpc/transaction_meta.d.ts +1 -1
  43. package/dist/grpc/types.d.ts +8 -8
  44. package/dist/grpc/types.js +7 -2
  45. package/dist/grpc/yellowstone_parse.d.ts +3 -3
  46. package/dist/grpc/yellowstone_parse.js +6 -8
  47. package/dist/grpc/yellowstone_transaction_adapter.d.ts +1 -1
  48. package/dist/index.d.ts +11 -1
  49. package/dist/index.js +23 -5
  50. package/dist/instr/inner.d.ts +2 -2
  51. package/dist/instr/inner.js +1 -1
  52. package/dist/instr/meteora_damm_ix.d.ts +1 -1
  53. package/dist/instr/meteora_dlmm_ix.d.ts +1 -1
  54. package/dist/instr/meteora_pools_ix.d.ts +1 -1
  55. package/dist/instr/mod.d.ts +1 -1
  56. package/dist/instr/orca_whirlpool_ix.d.ts +1 -1
  57. package/dist/instr/pump_fees_ix.d.ts +1 -1
  58. package/dist/instr/pumpfun_ix.d.ts +1 -1
  59. package/dist/instr/pumpswap_ix.d.ts +1 -1
  60. package/dist/instr/raydium_amm_v4_ix.d.ts +1 -1
  61. package/dist/instr/raydium_amm_v4_ix.js +9 -5
  62. package/dist/instr/raydium_clmm_ix.d.ts +1 -1
  63. package/dist/instr/raydium_cpmm_ix.d.ts +1 -1
  64. package/dist/instr/raydium_launchlab_ix.d.ts +1 -1
  65. package/dist/instr/raydium_launchlab_ix.js +62 -2
  66. package/dist/instr/utils.d.ts +2 -2
  67. package/dist/instr/utils.js +2 -7
  68. package/dist/liquidity_snapshot.d.ts +54 -0
  69. package/dist/liquidity_snapshot.js +85 -0
  70. package/dist/logs/meteora_damm.d.ts +1 -1
  71. package/dist/logs/meteora_damm.js +4 -2
  72. package/dist/logs/meteora_dlmm.d.ts +1 -1
  73. package/dist/logs/optimized_matcher.d.ts +3 -3
  74. package/dist/logs/raydium_launchlab.js +19 -1
  75. package/dist/rpc_transaction.d.ts +4 -3
  76. package/dist/rpc_transaction.js +3 -2
  77. package/dist/shredstream/client.js +3 -7
  78. package/dist/shredstream/entries_decode.js +9 -85
  79. package/dist/shredstream/instruction_parse.d.ts +3 -3
  80. package/dist/shredstream/proto_types.d.ts +1 -1
  81. package/dist/shredstream/wire_to_shred_tx.d.ts +1 -1
  82. package/dist/shredstream/wire_to_shred_tx.js +9 -44
  83. package/dist/simulation_route.d.ts +6 -0
  84. package/dist/simulation_route.js +242 -0
  85. package/dist/stonkfun_registry.d.ts +30 -0
  86. package/dist/stonkfun_registry.js +137 -0
  87. package/dist/transaction_route.d.ts +84 -0
  88. package/dist/transaction_route.js +477 -0
  89. package/dist/wire_transaction.d.ts +35 -0
  90. package/dist/wire_transaction.js +191 -0
  91. package/package.json +7 -4
@@ -0,0 +1,84 @@
1
+ export declare const ZERO = "11111111111111111111111111111111";
2
+ export declare const TOKEN = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
3
+ export declare const TOKEN_2022 = "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb";
4
+ export declare const WSOL = "So11111111111111111111111111111111111111112";
5
+ export declare const STONKFUN_STANDARD_PLATFORM_CONFIG = "4E876qZTE9FJMrBzgVtBrSrzz2TLivB5Y5QXPjB4gZL7";
6
+ export declare const STONKFUN_REWARD_PLATFORM_CONFIG = "6BwHHDg3u1854jC8PDLXvR4spTcLNaoBxLJNGC4nTESt";
7
+ export type StonkFunMode = "Standard" | "Reward";
8
+ export declare function stonkfunModeFromPlatformConfig(key: string): StonkFunMode | null;
9
+ export declare const ROUTE_PROGRAMS: {
10
+ readonly PumpFun: "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P";
11
+ readonly RaydiumClmm: "CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK";
12
+ readonly RaydiumCpmm: "CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C";
13
+ readonly RaydiumAmmV4: "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8";
14
+ readonly LaunchLab: "LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj";
15
+ readonly OrcaWhirlpool: "whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc";
16
+ readonly MeteoraDammV2: "cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG";
17
+ readonly MeteoraDlmm: "LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo";
18
+ readonly PumpSwap: "pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA";
19
+ };
20
+ export type SwapProtocol = keyof typeof ROUTE_PROGRAMS;
21
+ export interface InstructionPosition {
22
+ outer_index: number;
23
+ inner_index: number | null;
24
+ stack_height: number | null;
25
+ }
26
+ export interface RouteSwapLeg {
27
+ position: InstructionPosition;
28
+ program: string;
29
+ protocol: SwapProtocol;
30
+ pool: string;
31
+ trader: string;
32
+ input_account: string;
33
+ output_account: string;
34
+ input_mint: string | null;
35
+ output_mint: string | null;
36
+ amount_specified_is_input: boolean;
37
+ specified_amount: bigint;
38
+ other_amount_threshold: bigint;
39
+ actual_input_amount: bigint | null;
40
+ actual_output_amount: bigint | null;
41
+ stonkfun_mode: StonkFunMode | null;
42
+ stonkfun_graduated: boolean;
43
+ }
44
+ export interface RouteTokenTransfer {
45
+ position: InstructionPosition;
46
+ program: string;
47
+ source: string;
48
+ destination: string;
49
+ mint: string | null;
50
+ amount: bigint;
51
+ withheld_fee: bigint | null;
52
+ }
53
+ export interface RouteUnknownInvocation {
54
+ position: InstructionPosition;
55
+ program: string;
56
+ has_token_transfers: boolean;
57
+ has_known_swap_descendants: boolean;
58
+ }
59
+ export type NativeTokenAction = "SyncNative" | {
60
+ Fund: {
61
+ source: string;
62
+ lamports: bigint;
63
+ };
64
+ } | {
65
+ Close: {
66
+ destination: string;
67
+ authority: string;
68
+ };
69
+ };
70
+ export interface RouteNativeTokenAction {
71
+ position: InstructionPosition;
72
+ account: string;
73
+ action: NativeTokenAction;
74
+ }
75
+ export interface TransactionRoute {
76
+ signature: string;
77
+ succeeded: boolean;
78
+ legs: RouteSwapLeg[];
79
+ transfers: RouteTokenTransfer[];
80
+ native_token_actions: RouteNativeTokenAction[];
81
+ unknown_invocations: RouteUnknownInvocation[];
82
+ }
83
+ /** JSON-encoded or base64-encoded RPC response; amounts are exact bigint. */
84
+ export declare function analyzeRpcTransactionRoutes(transaction: unknown, graduatedStonkfunPools?: Iterable<string>): TransactionRoute;
@@ -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
+ };