solforge 0.2.6 → 0.2.7
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/package.json +1 -1
- package/server/lib/instruction-parser.ts +242 -0
- package/server/methods/account/request-airdrop.ts +107 -84
- package/server/methods/admin/mint-to.ts +11 -38
- package/server/methods/transaction/get-transaction.ts +328 -267
- package/server/methods/transaction/inner-instructions.test.ts +63 -0
- package/server/methods/transaction/send-transaction.ts +230 -51
- package/server/rpc-server.ts +72 -48
- package/server/types.ts +56 -24
- package/src/db/schema/index.ts +1 -0
- package/src/db/schema/transactions.ts +29 -22
- package/src/db/schema/tx-account-states.ts +21 -0
- package/src/db/tx-store.ts +103 -70
- package/src/migrations-bundled.ts +8 -2
|
@@ -1,51 +1,76 @@
|
|
|
1
1
|
import { VersionedTransaction } from "@solana/web3.js";
|
|
2
2
|
import type { RpcMethodHandler } from "../../types";
|
|
3
|
+
import { parseInstruction } from "../../lib/instruction-parser";
|
|
3
4
|
|
|
4
5
|
export const getTransaction: RpcMethodHandler = async (id, params, context) => {
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
const [signature, config] = params || [];
|
|
7
|
+
const encoding = config?.encoding ?? "json";
|
|
8
|
+
const DBG = process.env.DEBUG_TX_CAPTURE === "1";
|
|
9
|
+
try {
|
|
10
|
+
if (DBG) console.debug(`[tx-capture] getTransaction request: sig=${signature} enc=${encoding}`);
|
|
11
|
+
} catch {}
|
|
7
12
|
|
|
8
13
|
try {
|
|
9
14
|
const rec = context.getRecordedTransaction(signature);
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
15
|
+
if (rec) {
|
|
16
|
+
try {
|
|
17
|
+
if (DBG)
|
|
18
|
+
console.debug(
|
|
19
|
+
`[tx-capture] getTransaction hit memory: logs=${rec.logs?.length || 0} inner=${Array.isArray((rec as any).innerInstructions) ? (rec as any).innerInstructions.length : 0}`,
|
|
20
|
+
);
|
|
21
|
+
} catch {}
|
|
22
|
+
const tx = rec.tx;
|
|
23
|
+
if (encoding === "base64") {
|
|
24
|
+
const raw = Buffer.from(tx.serialize()).toString("base64");
|
|
25
|
+
// Top-level version is required by some clients
|
|
26
|
+
const isV0 = (() => {
|
|
27
|
+
const m = tx.message as unknown as { version?: number };
|
|
28
|
+
return typeof m?.version === "number" ? m.version === 0 : true;
|
|
29
|
+
})();
|
|
30
|
+
return context.createSuccessResponse(id, {
|
|
31
|
+
slot: rec.slot,
|
|
32
|
+
transaction: [raw, "base64"],
|
|
33
|
+
version: isV0 ? 0 : "legacy",
|
|
34
|
+
meta: {
|
|
35
|
+
status: rec.err ? { Err: rec.err } : { Ok: null },
|
|
36
|
+
err: rec.err ?? null,
|
|
37
|
+
fee: rec.fee,
|
|
38
|
+
loadedAddresses: { writable: [], readonly: [] },
|
|
39
|
+
preBalances: Array.isArray(rec.preBalances) ? rec.preBalances : [],
|
|
40
|
+
postBalances: Array.isArray(rec.postBalances)
|
|
41
|
+
? rec.postBalances
|
|
42
|
+
: [],
|
|
43
|
+
innerInstructions: Array.isArray((rec as any).innerInstructions)
|
|
44
|
+
? (rec as any).innerInstructions
|
|
45
|
+
: [],
|
|
46
|
+
logMessages: rec.logs || [],
|
|
47
|
+
preTokenBalances: (() => {
|
|
48
|
+
const arr = (rec as unknown as { preTokenBalances?: unknown[] })
|
|
49
|
+
.preTokenBalances;
|
|
50
|
+
return Array.isArray(arr) ? arr : [];
|
|
51
|
+
})(),
|
|
52
|
+
postTokenBalances: (() => {
|
|
53
|
+
const arr = (rec as unknown as { postTokenBalances?: unknown[] })
|
|
54
|
+
.postTokenBalances;
|
|
55
|
+
return Array.isArray(arr) ? arr : [];
|
|
56
|
+
})(),
|
|
57
|
+
computeUnitsConsumed:
|
|
58
|
+
typeof (rec as any).computeUnits === "number"
|
|
59
|
+
? (rec as any).computeUnits
|
|
60
|
+
: null,
|
|
61
|
+
returnData: (() => {
|
|
62
|
+
const rd = (rec as any).returnData as
|
|
63
|
+
| { programId: string; dataBase64: string }
|
|
64
|
+
| null
|
|
65
|
+
| undefined;
|
|
66
|
+
if (!rd) return null;
|
|
67
|
+
return { programId: rd.programId, data: [rd.dataBase64, "base64"] };
|
|
68
|
+
})(),
|
|
69
|
+
rewards: [],
|
|
70
|
+
},
|
|
71
|
+
blockTime: rec.blockTime,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
49
74
|
|
|
50
75
|
const msg = tx.message as unknown as {
|
|
51
76
|
staticAccountKeys?: unknown[];
|
|
@@ -132,94 +157,102 @@ export const getTransaction: RpcMethodHandler = async (id, params, context) => {
|
|
|
132
157
|
},
|
|
133
158
|
},
|
|
134
159
|
version: isV0 ? 0 : "legacy",
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
160
|
+
meta: {
|
|
161
|
+
status: rec.err ? { Err: rec.err } : { Ok: null },
|
|
162
|
+
err: rec.err ?? null,
|
|
163
|
+
fee: rec.fee,
|
|
164
|
+
loadedAddresses: { writable: [], readonly: [] },
|
|
165
|
+
preBalances: Array.isArray(rec.preBalances) ? rec.preBalances : [],
|
|
166
|
+
postBalances: Array.isArray(rec.postBalances) ? rec.postBalances : [],
|
|
167
|
+
innerInstructions: Array.isArray((rec as any).innerInstructions)
|
|
168
|
+
? (rec as any).innerInstructions
|
|
169
|
+
: [],
|
|
170
|
+
logMessages: rec.logs || [],
|
|
171
|
+
preTokenBalances: (() => {
|
|
172
|
+
const arr = (rec as unknown as { preTokenBalances?: unknown[] })
|
|
173
|
+
.preTokenBalances;
|
|
174
|
+
return Array.isArray(arr) ? arr : [];
|
|
175
|
+
})(),
|
|
176
|
+
postTokenBalances: (() => {
|
|
177
|
+
const arr = (rec as unknown as { postTokenBalances?: unknown[] })
|
|
178
|
+
.postTokenBalances;
|
|
179
|
+
return Array.isArray(arr) ? arr : [];
|
|
180
|
+
})(),
|
|
181
|
+
computeUnitsConsumed:
|
|
182
|
+
typeof (rec as any).computeUnits === "number"
|
|
183
|
+
? (rec as any).computeUnits
|
|
184
|
+
: null,
|
|
185
|
+
returnData: (() => {
|
|
186
|
+
const rd = (rec as any).returnData as
|
|
187
|
+
| { programId: string; dataBase64: string }
|
|
188
|
+
| null
|
|
189
|
+
| undefined;
|
|
190
|
+
if (!rd) return null;
|
|
191
|
+
return { programId: rd.programId, data: [rd.dataBase64, "base64"] };
|
|
192
|
+
})(),
|
|
193
|
+
rewards: [],
|
|
194
|
+
},
|
|
195
|
+
blockTime: rec.blockTime,
|
|
196
|
+
};
|
|
158
197
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
(result.transaction.message as { accountKeys: unknown[] }).accountKeys =
|
|
218
|
-
accountKeysParsed;
|
|
219
|
-
(
|
|
220
|
-
result.transaction.message as { instructions: unknown[] }
|
|
221
|
-
).instructions = parsedInstructions as unknown[];
|
|
222
|
-
}
|
|
198
|
+
if (encoding === "jsonParsed") {
|
|
199
|
+
const accountKeysParsed = accountKeys.map((pk: string, i: number) => ({
|
|
200
|
+
pubkey: pk,
|
|
201
|
+
signer:
|
|
202
|
+
typeof msg.isAccountSigner === "function"
|
|
203
|
+
? !!msg.isAccountSigner(i)
|
|
204
|
+
: i < (header?.numRequiredSignatures ?? 0),
|
|
205
|
+
writable:
|
|
206
|
+
typeof msg.isAccountWritable === "function"
|
|
207
|
+
? !!msg.isAccountWritable(i)
|
|
208
|
+
: i < (header?.numRequiredSignatures ?? 0),
|
|
209
|
+
}));
|
|
210
|
+
const parsedInstructions = compiled.map((ci) => {
|
|
211
|
+
const c = ci as {
|
|
212
|
+
programIdIndex: number;
|
|
213
|
+
accountKeyIndexes?: number[];
|
|
214
|
+
accounts?: number[];
|
|
215
|
+
data: Uint8Array | number[];
|
|
216
|
+
};
|
|
217
|
+
const dataBytes: Uint8Array =
|
|
218
|
+
c.data instanceof Uint8Array ? c.data : Buffer.from(c.data);
|
|
219
|
+
const accountsIdx = Array.from(
|
|
220
|
+
c.accountKeyIndexes || c.accounts || [],
|
|
221
|
+
);
|
|
222
|
+
const programId = accountKeys[c.programIdIndex];
|
|
223
|
+
return parseInstruction(
|
|
224
|
+
programId,
|
|
225
|
+
accountsIdx,
|
|
226
|
+
context.encodeBase58(dataBytes),
|
|
227
|
+
accountKeys,
|
|
228
|
+
);
|
|
229
|
+
});
|
|
230
|
+
(result.transaction.message as { accountKeys: unknown[] }).accountKeys =
|
|
231
|
+
accountKeysParsed;
|
|
232
|
+
(
|
|
233
|
+
result.transaction.message as { instructions: unknown[] }
|
|
234
|
+
).instructions = parsedInstructions as unknown[];
|
|
235
|
+
// Parse inner instructions using the same parser
|
|
236
|
+
try {
|
|
237
|
+
const inner = (result.meta as any)?.innerInstructions as
|
|
238
|
+
| Array<{ index: number; instructions: any[] }>
|
|
239
|
+
| undefined;
|
|
240
|
+
if (Array.isArray(inner)) {
|
|
241
|
+
const parsedInner = inner.map((group) => ({
|
|
242
|
+
index: group.index,
|
|
243
|
+
instructions: (group.instructions || []).map((ii) => {
|
|
244
|
+
const accountsIdx = Array.isArray(ii.accounts)
|
|
245
|
+
? ii.accounts
|
|
246
|
+
: [];
|
|
247
|
+
const dataB58 = typeof ii.data === "string" ? ii.data : String(ii.data ?? "");
|
|
248
|
+
const pid = accountKeys[ii.programIdIndex ?? 0] || accountKeys[0];
|
|
249
|
+
return parseInstruction(pid, accountsIdx, dataB58, accountKeys);
|
|
250
|
+
}),
|
|
251
|
+
}));
|
|
252
|
+
(result.meta as any).innerInstructions = parsedInner;
|
|
253
|
+
}
|
|
254
|
+
} catch {}
|
|
255
|
+
}
|
|
223
256
|
|
|
224
257
|
return context.createSuccessResponse(id, result);
|
|
225
258
|
}
|
|
@@ -227,37 +260,54 @@ export const getTransaction: RpcMethodHandler = async (id, params, context) => {
|
|
|
227
260
|
// Fallback: persistent store
|
|
228
261
|
try {
|
|
229
262
|
const row = await context.store?.getTransaction(signature);
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
263
|
+
if (row) {
|
|
264
|
+
try {
|
|
265
|
+
if (DBG)
|
|
266
|
+
console.debug(
|
|
267
|
+
`[tx-capture] getTransaction hit sqlite: slot=${row.slot} logs=${JSON.parse(row.logsJson || '[]').length} inner=${JSON.parse(row.innerInstructionsJson || '[]').length}`,
|
|
268
|
+
);
|
|
269
|
+
} catch {}
|
|
270
|
+
const errVal = row.errJson ? JSON.parse(row.errJson) : null;
|
|
271
|
+
const preBalances = JSON.parse(row.preBalancesJson || "[]");
|
|
272
|
+
const postBalances = JSON.parse(row.postBalancesJson || "[]");
|
|
273
|
+
const logs = JSON.parse(row.logsJson || "[]");
|
|
274
|
+
const inner = JSON.parse(row.innerInstructionsJson || "[]");
|
|
275
|
+
const versionVal =
|
|
276
|
+
row.version === "0" || row.version === 0 ? 0 : row.version;
|
|
277
|
+
if (encoding === "base64") {
|
|
278
|
+
return context.createSuccessResponse(id, {
|
|
279
|
+
slot: Number(row.slot),
|
|
280
|
+
transaction: [row.rawBase64, "base64"],
|
|
281
|
+
version: versionVal,
|
|
282
|
+
meta: {
|
|
283
|
+
status: errVal ? { Err: errVal } : { Ok: null },
|
|
284
|
+
err: errVal,
|
|
285
|
+
fee: Number(row.fee),
|
|
286
|
+
loadedAddresses: { writable: [], readonly: [] },
|
|
287
|
+
preBalances,
|
|
288
|
+
postBalances,
|
|
289
|
+
innerInstructions: Array.isArray(inner) ? inner : [],
|
|
290
|
+
logMessages: logs,
|
|
291
|
+
preTokenBalances: JSON.parse(row.preTokenBalancesJson || "[]"),
|
|
292
|
+
postTokenBalances: JSON.parse(row.postTokenBalancesJson || "[]"),
|
|
293
|
+
computeUnitsConsumed:
|
|
294
|
+
row.computeUnits != null ? Number(row.computeUnits) : null,
|
|
295
|
+
returnData: (() => {
|
|
296
|
+
if (row.returnDataProgramId && row.returnDataBase64)
|
|
297
|
+
return {
|
|
298
|
+
programId: row.returnDataProgramId,
|
|
299
|
+
data: [row.returnDataBase64, "base64"],
|
|
300
|
+
};
|
|
301
|
+
return null;
|
|
302
|
+
})(),
|
|
303
|
+
rewards: [],
|
|
304
|
+
},
|
|
305
|
+
blockTime: row.blockTime ? Number(row.blockTime) : null,
|
|
306
|
+
});
|
|
307
|
+
} else if (encoding === "jsonParsed") {
|
|
308
|
+
// Build jsonParsed similar to in-memory path
|
|
309
|
+
const raw = Buffer.from(row.rawBase64, "base64");
|
|
310
|
+
const tx = VersionedTransaction.deserialize(raw);
|
|
261
311
|
const msg = tx.message as unknown as {
|
|
262
312
|
staticAccountKeys?: unknown[];
|
|
263
313
|
accountKeys?: unknown[];
|
|
@@ -293,54 +343,26 @@ export const getTransaction: RpcMethodHandler = async (id, params, context) => {
|
|
|
293
343
|
: Array.isArray(msg.instructions)
|
|
294
344
|
? msg.instructions
|
|
295
345
|
: [];
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
data.byteLength,
|
|
317
|
-
);
|
|
318
|
-
const discriminator = dv.getUint32(0, true);
|
|
319
|
-
if (
|
|
320
|
-
discriminator === 2 &&
|
|
321
|
-
(ci.accountKeyIndexes?.length ?? 0) >= 2
|
|
322
|
-
) {
|
|
323
|
-
const lamports = Number(dv.getBigUint64(4, true));
|
|
324
|
-
const source = accountKeys[c.accountKeyIndexes?.[0]];
|
|
325
|
-
const destination = accountKeys[c.accountKeyIndexes?.[1]];
|
|
326
|
-
parsed = {
|
|
327
|
-
type: "transfer",
|
|
328
|
-
info: { source, destination, lamports },
|
|
329
|
-
};
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
} catch {}
|
|
333
|
-
if (parsed) return { program: "system", programId, parsed };
|
|
334
|
-
return {
|
|
335
|
-
programId,
|
|
336
|
-
accounts: (c.accountKeyIndexes || []).map(
|
|
337
|
-
(ix: number) => accountKeys[ix],
|
|
338
|
-
),
|
|
339
|
-
data: context.encodeBase58(
|
|
340
|
-
c.data instanceof Uint8Array ? c.data : Buffer.from(c.data),
|
|
341
|
-
),
|
|
342
|
-
};
|
|
343
|
-
});
|
|
346
|
+
const parsedInstructions = compiled.map((ci) => {
|
|
347
|
+
const c = ci as {
|
|
348
|
+
programIdIndex: number;
|
|
349
|
+
accountKeyIndexes?: number[];
|
|
350
|
+
accounts?: number[];
|
|
351
|
+
data: Uint8Array | number[];
|
|
352
|
+
};
|
|
353
|
+
const dataBytes: Uint8Array =
|
|
354
|
+
c.data instanceof Uint8Array ? c.data : Buffer.from(c.data);
|
|
355
|
+
const accountsIdx = Array.from(
|
|
356
|
+
c.accountKeyIndexes || c.accounts || [],
|
|
357
|
+
);
|
|
358
|
+
const programId = accountKeys[c.programIdIndex];
|
|
359
|
+
return parseInstruction(
|
|
360
|
+
programId,
|
|
361
|
+
accountsIdx,
|
|
362
|
+
context.encodeBase58(dataBytes),
|
|
363
|
+
accountKeys,
|
|
364
|
+
);
|
|
365
|
+
});
|
|
344
366
|
const accountKeysParsed = accountKeys.map(
|
|
345
367
|
(pk: string, i: number) => ({
|
|
346
368
|
pubkey: pk,
|
|
@@ -354,36 +376,65 @@ export const getTransaction: RpcMethodHandler = async (id, params, context) => {
|
|
|
354
376
|
: i < (header?.numRequiredSignatures ?? 0),
|
|
355
377
|
}),
|
|
356
378
|
);
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
379
|
+
const result = {
|
|
380
|
+
slot: Number(row.slot),
|
|
381
|
+
transaction: {
|
|
382
|
+
signatures: [signature],
|
|
383
|
+
message: {
|
|
384
|
+
accountKeys: accountKeysParsed,
|
|
385
|
+
header,
|
|
386
|
+
recentBlockhash: msg.recentBlockhash || "",
|
|
387
|
+
instructions: parsedInstructions,
|
|
388
|
+
addressTableLookups: msg.addressTableLookups || [],
|
|
389
|
+
},
|
|
390
|
+
},
|
|
391
|
+
version: row.version === "0" || row.version === 0 ? 0 : row.version,
|
|
392
|
+
meta: {
|
|
393
|
+
status: errVal ? { Err: errVal } : { Ok: null },
|
|
394
|
+
err: errVal,
|
|
395
|
+
fee: Number(row.fee),
|
|
396
|
+
loadedAddresses: { writable: [], readonly: [] },
|
|
397
|
+
preBalances,
|
|
398
|
+
postBalances,
|
|
399
|
+
innerInstructions: Array.isArray(inner) ? inner : [],
|
|
400
|
+
logMessages: logs,
|
|
401
|
+
preTokenBalances: JSON.parse(row.preTokenBalancesJson || "[]"),
|
|
402
|
+
postTokenBalances: JSON.parse(row.postTokenBalancesJson || "[]"),
|
|
403
|
+
computeUnitsConsumed:
|
|
404
|
+
row.computeUnits != null ? Number(row.computeUnits) : null,
|
|
405
|
+
returnData: (() => {
|
|
406
|
+
if (row.returnDataProgramId && row.returnDataBase64)
|
|
407
|
+
return {
|
|
408
|
+
programId: row.returnDataProgramId,
|
|
409
|
+
data: [row.returnDataBase64, "base64"],
|
|
410
|
+
};
|
|
411
|
+
return null;
|
|
412
|
+
})(),
|
|
413
|
+
rewards: [],
|
|
414
|
+
},
|
|
415
|
+
blockTime: row.blockTime ? Number(row.blockTime) : null,
|
|
416
|
+
};
|
|
417
|
+
// Also parse inner instructions from DB row
|
|
418
|
+
try {
|
|
419
|
+
const innerSrc = JSON.parse(row.innerInstructionsJson || "[]");
|
|
420
|
+
const innerParsed = (innerSrc as any[]).map((group) => ({
|
|
421
|
+
index: Number(group.index || 0),
|
|
422
|
+
instructions: Array.isArray(group.instructions)
|
|
423
|
+
? group.instructions.map((ii: any) =>
|
|
424
|
+
parseInstruction(
|
|
425
|
+
accountKeys[ii.programIdIndex ?? 0] || accountKeys[0],
|
|
426
|
+
Array.isArray(ii.accounts) ? ii.accounts : [],
|
|
427
|
+
typeof ii.data === "string" ? ii.data : String(ii.data ?? ""),
|
|
428
|
+
accountKeys,
|
|
429
|
+
),
|
|
430
|
+
)
|
|
431
|
+
: [],
|
|
432
|
+
}));
|
|
433
|
+
(result as any).meta.innerInstructions = innerParsed;
|
|
434
|
+
} catch {}
|
|
435
|
+
|
|
436
|
+
return context.createSuccessResponse(id, result);
|
|
437
|
+
} else {
|
|
387
438
|
const raw = Buffer.from(row.rawBase64, "base64");
|
|
388
439
|
const tx = VersionedTransaction.deserialize(raw);
|
|
389
440
|
const msg = tx.message as unknown as {
|
|
@@ -434,36 +485,46 @@ export const getTransaction: RpcMethodHandler = async (id, params, context) => {
|
|
|
434
485
|
),
|
|
435
486
|
};
|
|
436
487
|
});
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
488
|
+
const result = {
|
|
489
|
+
slot: Number(row.slot),
|
|
490
|
+
transaction: {
|
|
491
|
+
signatures: [signature],
|
|
492
|
+
message: {
|
|
493
|
+
accountKeys,
|
|
494
|
+
header,
|
|
495
|
+
recentBlockhash: msg.recentBlockhash || "",
|
|
496
|
+
instructions,
|
|
497
|
+
addressTableLookups: msg.addressTableLookups || [],
|
|
498
|
+
},
|
|
499
|
+
},
|
|
500
|
+
version: versionVal,
|
|
501
|
+
meta: {
|
|
502
|
+
status: errVal ? { Err: errVal } : { Ok: null },
|
|
503
|
+
err: errVal,
|
|
504
|
+
fee: Number(row.fee),
|
|
505
|
+
loadedAddresses: { writable: [], readonly: [] },
|
|
506
|
+
preBalances,
|
|
507
|
+
postBalances,
|
|
508
|
+
innerInstructions: Array.isArray(inner) ? inner : [],
|
|
509
|
+
logMessages: logs,
|
|
510
|
+
preTokenBalances: JSON.parse(row.preTokenBalancesJson || "[]"),
|
|
511
|
+
postTokenBalances: JSON.parse(row.postTokenBalancesJson || "[]"),
|
|
512
|
+
computeUnitsConsumed:
|
|
513
|
+
row.computeUnits != null ? Number(row.computeUnits) : null,
|
|
514
|
+
returnData: (() => {
|
|
515
|
+
if (row.returnDataProgramId && row.returnDataBase64)
|
|
516
|
+
return {
|
|
517
|
+
programId: row.returnDataProgramId,
|
|
518
|
+
data: [row.returnDataBase64, "base64"],
|
|
519
|
+
};
|
|
520
|
+
return null;
|
|
521
|
+
})(),
|
|
522
|
+
rewards: [],
|
|
523
|
+
},
|
|
524
|
+
blockTime: row.blockTime ? Number(row.blockTime) : null,
|
|
525
|
+
};
|
|
526
|
+
return context.createSuccessResponse(id, result);
|
|
527
|
+
}
|
|
467
528
|
}
|
|
468
529
|
} catch {}
|
|
469
530
|
|