@oobe-protocol-labs/synapse-sap-sdk 0.4.1 → 0.4.2

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 (64) hide show
  1. package/dist/cjs/core/client.js +23 -0
  2. package/dist/cjs/core/client.js.map +1 -1
  3. package/dist/cjs/index.js +15 -1
  4. package/dist/cjs/index.js.map +1 -1
  5. package/dist/cjs/parser/client.js +146 -0
  6. package/dist/cjs/parser/client.js.map +1 -0
  7. package/dist/cjs/parser/complete.js +177 -0
  8. package/dist/cjs/parser/complete.js.map +1 -0
  9. package/dist/cjs/parser/index.js +57 -0
  10. package/dist/cjs/parser/index.js.map +1 -0
  11. package/dist/cjs/parser/inner.js +185 -0
  12. package/dist/cjs/parser/inner.js.map +1 -0
  13. package/dist/cjs/parser/instructions.js +114 -0
  14. package/dist/cjs/parser/instructions.js.map +1 -0
  15. package/dist/cjs/parser/transaction.js +153 -0
  16. package/dist/cjs/parser/transaction.js.map +1 -0
  17. package/dist/cjs/parser/types.js +14 -0
  18. package/dist/cjs/parser/types.js.map +1 -0
  19. package/dist/esm/core/client.js +23 -0
  20. package/dist/esm/core/client.js.map +1 -1
  21. package/dist/esm/index.js +3 -0
  22. package/dist/esm/index.js.map +1 -1
  23. package/dist/esm/parser/client.js +142 -0
  24. package/dist/esm/parser/client.js.map +1 -0
  25. package/dist/esm/parser/complete.js +173 -0
  26. package/dist/esm/parser/complete.js.map +1 -0
  27. package/dist/esm/parser/index.js +43 -0
  28. package/dist/esm/parser/index.js.map +1 -0
  29. package/dist/esm/parser/inner.js +180 -0
  30. package/dist/esm/parser/inner.js.map +1 -0
  31. package/dist/esm/parser/instructions.js +109 -0
  32. package/dist/esm/parser/instructions.js.map +1 -0
  33. package/dist/esm/parser/transaction.js +149 -0
  34. package/dist/esm/parser/transaction.js.map +1 -0
  35. package/dist/esm/parser/types.js +13 -0
  36. package/dist/esm/parser/types.js.map +1 -0
  37. package/dist/types/core/client.d.ts +19 -0
  38. package/dist/types/core/client.d.ts.map +1 -1
  39. package/dist/types/index.d.ts +3 -0
  40. package/dist/types/index.d.ts.map +1 -1
  41. package/dist/types/parser/client.d.ts +123 -0
  42. package/dist/types/parser/client.d.ts.map +1 -0
  43. package/dist/types/parser/complete.d.ts +90 -0
  44. package/dist/types/parser/complete.d.ts.map +1 -0
  45. package/dist/types/parser/index.d.ts +40 -0
  46. package/dist/types/parser/index.d.ts.map +1 -0
  47. package/dist/types/parser/inner.d.ts +114 -0
  48. package/dist/types/parser/inner.d.ts.map +1 -0
  49. package/dist/types/parser/instructions.d.ts +76 -0
  50. package/dist/types/parser/instructions.d.ts.map +1 -0
  51. package/dist/types/parser/transaction.d.ts +77 -0
  52. package/dist/types/parser/transaction.d.ts.map +1 -0
  53. package/dist/types/parser/types.d.ts +154 -0
  54. package/dist/types/parser/types.d.ts.map +1 -0
  55. package/package.json +6 -1
  56. package/src/core/client.ts +25 -0
  57. package/src/index.ts +25 -0
  58. package/src/parser/client.ts +211 -0
  59. package/src/parser/complete.ts +232 -0
  60. package/src/parser/index.ts +71 -0
  61. package/src/parser/inner.ts +255 -0
  62. package/src/parser/instructions.ts +135 -0
  63. package/src/parser/transaction.ts +200 -0
  64. package/src/parser/types.ts +182 -0
@@ -0,0 +1,200 @@
1
+ /**
2
+ * @module parser/transaction
3
+ * @description Decode SAP instruction names from a raw `TransactionResponse`.
4
+ *
5
+ * This is "Case 2A": you have a transaction response object obtained
6
+ * from `connection.getTransaction(signature, ...)` and need to extract
7
+ * the SAP instruction names, arguments, and account keys.
8
+ *
9
+ * The function handles both legacy and versioned (v0) transactions
10
+ * by decompiling the message into `TransactionInstruction[]` and then
11
+ * filtering for instructions whose `programId` matches the SAP program.
12
+ *
13
+ * @category Parser
14
+ * @since v0.5.0
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * import { parseSapInstructionsFromTransaction } from "@synapse-sap/sdk/parser";
19
+ * import { SAP_PROGRAM_ID } from "@synapse-sap/sdk";
20
+ *
21
+ * const tx = await connection.getTransaction(sig, {
22
+ * commitment: "confirmed",
23
+ * maxSupportedTransactionVersion: 0,
24
+ * });
25
+ * if (!tx) throw new Error("Transaction not found");
26
+ *
27
+ * const decoded = parseSapInstructionsFromTransaction(
28
+ * tx,
29
+ * program.coder.instruction,
30
+ * SAP_PROGRAM_ID,
31
+ * );
32
+ * for (const ix of decoded) {
33
+ * console.log(ix.name, ix.args);
34
+ * }
35
+ * ```
36
+ */
37
+
38
+ import {
39
+ TransactionMessage,
40
+ AddressLookupTableAccount,
41
+ type PublicKey,
42
+ type TransactionInstruction,
43
+ type VersionedTransactionResponse,
44
+ type TransactionResponse,
45
+ } from "@solana/web3.js";
46
+ import type { DecodedSapInstruction, SapInstructionCoder } from "./types";
47
+
48
+ // ================================================================
49
+ // Public API
50
+ // ================================================================
51
+
52
+ /**
53
+ * Extract and decode SAP instructions from a transaction response.
54
+ *
55
+ * Supports both legacy (`TransactionResponse`) and versioned
56
+ * (`VersionedTransactionResponse`) formats. For versioned
57
+ * transactions that use address lookup tables, pass the resolved
58
+ * lookup table accounts so that `TransactionMessage.decompile`
59
+ * can reconstruct the full account list.
60
+ *
61
+ * @param tx - The transaction response from `connection.getTransaction`.
62
+ * @param coder - An Anchor instruction coder built from the SAP IDL.
63
+ * @param sapProgramId - The SAP program public key to filter by.
64
+ * @param addressLookupTables - Resolved lookup table accounts for v0 transactions.
65
+ * Required when the transaction uses address lookup tables; omit for legacy txs.
66
+ * @returns An array of decoded SAP instructions found in the transaction.
67
+ *
68
+ * @throws {Error} When the transaction message cannot be decompiled.
69
+ *
70
+ * @category Parser
71
+ * @since v0.5.0
72
+ */
73
+ export function parseSapInstructionsFromTransaction(
74
+ tx: TransactionResponse | VersionedTransactionResponse,
75
+ coder: SapInstructionCoder,
76
+ sapProgramId: PublicKey,
77
+ addressLookupTables?: AddressLookupTableAccount[],
78
+ ): DecodedSapInstruction[] {
79
+ const instructions = decompileTransaction(tx, addressLookupTables);
80
+ return decodeSapInstructions(instructions, coder, sapProgramId);
81
+ }
82
+
83
+ /**
84
+ * Extract only the SAP instruction names from a transaction response.
85
+ *
86
+ * Lighter-weight alternative to {@link parseSapInstructionsFromTransaction}
87
+ * when you only need the instruction names without decoded arguments.
88
+ *
89
+ * @param tx - The transaction response.
90
+ * @param coder - An Anchor instruction coder built from the SAP IDL.
91
+ * @param sapProgramId - The SAP program public key.
92
+ * @param addressLookupTables - Resolved lookup table accounts for v0 transactions.
93
+ * @returns An array of instruction name strings.
94
+ *
95
+ * @category Parser
96
+ * @since v0.5.0
97
+ */
98
+ export function parseSapInstructionNamesFromTransaction(
99
+ tx: TransactionResponse | VersionedTransactionResponse,
100
+ coder: SapInstructionCoder,
101
+ sapProgramId: PublicKey,
102
+ addressLookupTables?: AddressLookupTableAccount[],
103
+ ): string[] {
104
+ return parseSapInstructionsFromTransaction(
105
+ tx,
106
+ coder,
107
+ sapProgramId,
108
+ addressLookupTables,
109
+ ).map((ix) => ix.name);
110
+ }
111
+
112
+ // ================================================================
113
+ // Internal helpers
114
+ // ================================================================
115
+
116
+ /**
117
+ * Decompile a transaction response into an array of `TransactionInstruction`.
118
+ *
119
+ * Handles both legacy messages (which already contain full account keys)
120
+ * and versioned v0 messages (which require address lookup table resolution).
121
+ *
122
+ * @internal
123
+ */
124
+ function decompileTransaction(
125
+ tx: TransactionResponse | VersionedTransactionResponse,
126
+ addressLookupTables?: AddressLookupTableAccount[],
127
+ ): TransactionInstruction[] {
128
+ const message = tx.transaction.message;
129
+
130
+ // Versioned transactions expose `version` on the response object.
131
+ // Legacy transactions have either `version = "legacy"` or no field at all.
132
+ const isVersioned =
133
+ "version" in tx && tx.version !== undefined && tx.version !== "legacy";
134
+
135
+ if (isVersioned) {
136
+ // VersionedMessage requires decompile with optional lookup tables
137
+ const decompiledMessage = TransactionMessage.decompile(
138
+ message as import("@solana/web3.js").VersionedMessage,
139
+ addressLookupTables?.length
140
+ ? { addressLookupTableAccounts: addressLookupTables }
141
+ : undefined,
142
+ );
143
+ return decompiledMessage.instructions;
144
+ }
145
+
146
+ // Legacy message: decompile directly
147
+ const decompiledMessage = TransactionMessage.decompile(
148
+ message as import("@solana/web3.js").VersionedMessage,
149
+ );
150
+ return decompiledMessage.instructions;
151
+ }
152
+
153
+ /**
154
+ * Decode a list of raw `TransactionInstruction` into typed SAP results.
155
+ *
156
+ * Filters for instructions whose `programId` matches the SAP program,
157
+ * then runs each through the Anchor instruction coder.
158
+ *
159
+ * @internal
160
+ */
161
+ function decodeSapInstructions(
162
+ instructions: TransactionInstruction[],
163
+ coder: SapInstructionCoder,
164
+ sapProgramId: PublicKey,
165
+ ): DecodedSapInstruction[] {
166
+ const results: DecodedSapInstruction[] = [];
167
+
168
+ for (const ix of instructions) {
169
+ if (!ix.programId.equals(sapProgramId)) continue;
170
+
171
+ const decoded = safeDecodeInstruction(coder, ix.data);
172
+ results.push({
173
+ name: decoded?.name ?? "unknown",
174
+ args: decoded?.data ?? null,
175
+ accounts: ix.keys.map((k) => k.pubkey),
176
+ raw: ix,
177
+ });
178
+ }
179
+
180
+ return results;
181
+ }
182
+
183
+ /**
184
+ * Attempt to decode instruction data, returning `null` on failure
185
+ * instead of throwing. This prevents a single malformed instruction
186
+ * from breaking the entire parse pipeline.
187
+ *
188
+ * @internal
189
+ */
190
+ function safeDecodeInstruction(
191
+ coder: SapInstructionCoder,
192
+ data: Buffer | Uint8Array,
193
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
194
+ ): { name: string; data: Record<string, any> } | null {
195
+ try {
196
+ return coder.decode(Buffer.from(data));
197
+ } catch {
198
+ return null;
199
+ }
200
+ }
@@ -0,0 +1,182 @@
1
+ /**
2
+ * @module parser/types
3
+ * @description Type definitions for SAP v2 transaction parsing.
4
+ *
5
+ * Provides strongly-typed interfaces for decoded instruction data,
6
+ * account metadata, inner (CPI) instructions, and the full parsed
7
+ * transaction result used by indexers and explorers.
8
+ *
9
+ * @category Parser
10
+ * @since v0.5.0
11
+ */
12
+
13
+ import type { PublicKey, TransactionInstruction } from "@solana/web3.js";
14
+ import type { ParsedEvent, SapEventName } from "../events";
15
+
16
+ // ================================================================
17
+ // Decoded Instruction
18
+ // ================================================================
19
+
20
+ /**
21
+ * A single SAP instruction decoded from on-chain transaction data.
22
+ *
23
+ * Contains the human-readable instruction name (as declared in the
24
+ * Anchor IDL), the decoded argument object, the ordered list of
25
+ * account keys, and the raw instruction for advanced consumers.
26
+ *
27
+ * @interface DecodedSapInstruction
28
+ * @category Parser
29
+ * @since v0.5.0
30
+ */
31
+ export interface DecodedSapInstruction {
32
+ /** Instruction name matching the Anchor IDL method (e.g. `"registerAgent"`). */
33
+ readonly name: string;
34
+ /**
35
+ * Decoded arguments object. Keys match the Anchor IDL argument names.
36
+ * Returns `null` when decoding fails (e.g. IDL mismatch).
37
+ */
38
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
39
+ readonly args: Record<string, any> | null;
40
+ /** Ordered list of account public keys passed to the instruction. */
41
+ readonly accounts: PublicKey[];
42
+ /** The original `TransactionInstruction`, useful for re-simulation or forwarding. */
43
+ readonly raw: TransactionInstruction;
44
+ }
45
+
46
+ // ================================================================
47
+ // Inner (CPI) Instruction
48
+ // ================================================================
49
+
50
+ /**
51
+ * An inner instruction produced by cross-program invocation (CPI)
52
+ * within a SAP transaction.
53
+ *
54
+ * Inner instructions are indexed by the outer instruction position
55
+ * that triggered them. Each entry includes the decoded SAP name
56
+ * when the inner call targets the SAP program, or `null` otherwise.
57
+ *
58
+ * @interface DecodedInnerInstruction
59
+ * @category Parser
60
+ * @since v0.5.0
61
+ */
62
+ export interface DecodedInnerInstruction {
63
+ /** Zero-based index of the outer instruction that triggered this CPI call. */
64
+ readonly outerIndex: number;
65
+ /** Zero-based position within the inner instruction set of the parent. */
66
+ readonly innerIndex: number;
67
+ /** SAP instruction name if the CPI targets the SAP program, `null` otherwise. */
68
+ readonly name: string | null;
69
+ /** Decoded arguments when the CPI targets SAP and decoding succeeds. */
70
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
71
+ readonly args: Record<string, any> | null;
72
+ /** Ordered account keys for this inner instruction. */
73
+ readonly accounts: PublicKey[];
74
+ /** The program that was invoked by this inner call. */
75
+ readonly programId: PublicKey;
76
+ }
77
+
78
+ // ================================================================
79
+ // Parsed Transaction (complete result)
80
+ // ================================================================
81
+
82
+ /**
83
+ * Full parse result for a single SAP transaction.
84
+ *
85
+ * Combines top-level instruction decoding, inner instruction
86
+ * analysis, and event extraction into one unified structure
87
+ * suitable for indexing, analytics dashboards, and protocol
88
+ * explorers.
89
+ *
90
+ * @interface ParsedSapTransaction
91
+ * @category Parser
92
+ * @since v0.5.0
93
+ *
94
+ * @example
95
+ * ```ts
96
+ * const result = parseSapTransactionComplete(tx, program, SAP_PROGRAM_ID);
97
+ * for (const ix of result.instructions) {
98
+ * console.log(ix.name, ix.args);
99
+ * }
100
+ * for (const event of result.events) {
101
+ * console.log(event.name, event.data);
102
+ * }
103
+ * ```
104
+ */
105
+ export interface ParsedSapTransaction {
106
+ /** Transaction signature (base-58), extracted from the response when available. */
107
+ readonly signature: string | null;
108
+ /** Slot at which the transaction was confirmed. */
109
+ readonly slot: number | null;
110
+ /** Block timestamp (unix seconds) or `null` if unavailable. */
111
+ readonly blockTime: number | null;
112
+ /** Whether the transaction succeeded (`true`) or failed. */
113
+ readonly success: boolean;
114
+ /** Top-level SAP instructions found in the transaction. */
115
+ readonly instructions: DecodedSapInstruction[];
116
+ /** All inner (CPI) instructions, including non-SAP programs. */
117
+ readonly innerInstructions: DecodedInnerInstruction[];
118
+ /** Decoded SAP events extracted from the transaction logs. */
119
+ readonly events: ParsedEvent[];
120
+ /** Raw log lines from the transaction, for additional debugging. */
121
+ readonly logs: string[];
122
+ }
123
+
124
+ // ================================================================
125
+ // Filter helpers
126
+ // ================================================================
127
+
128
+ /**
129
+ * Options for filtering parsed instruction results.
130
+ *
131
+ * @interface ParseFilterOptions
132
+ * @category Parser
133
+ * @since v0.5.0
134
+ */
135
+ export interface ParseFilterOptions {
136
+ /**
137
+ * When `true`, include inner (CPI) instructions in the parse
138
+ * result. Defaults to `false` because inner instruction
139
+ * reconstruction requires additional account-table lookups.
140
+ */
141
+ readonly includeInner?: boolean;
142
+ /**
143
+ * When `true`, decode and attach SAP events from the
144
+ * transaction logs. Defaults to `true`.
145
+ */
146
+ readonly includeEvents?: boolean;
147
+ /**
148
+ * Restrict the result to instructions matching one of these
149
+ * names. When `undefined` or empty, all SAP instructions are
150
+ * returned.
151
+ */
152
+ readonly instructionFilter?: string[];
153
+ /**
154
+ * Restrict events to those matching one of these names.
155
+ * When `undefined` or empty, all events are returned.
156
+ */
157
+ readonly eventFilter?: SapEventName[];
158
+ }
159
+
160
+ // ================================================================
161
+ // Coder interface (minimal contract)
162
+ // ================================================================
163
+
164
+ /**
165
+ * Minimal interface for the Anchor instruction coder.
166
+ *
167
+ * Extracted so that parser functions can accept either a full
168
+ * `Program` instance or a standalone coder/IDL pair without
169
+ * requiring a live RPC connection.
170
+ *
171
+ * @interface SapInstructionCoder
172
+ * @category Parser
173
+ * @since v0.5.0
174
+ */
175
+ export interface SapInstructionCoder {
176
+ /** Decode raw instruction data into a name and typed argument object. */
177
+ decode(
178
+ data: Buffer | Uint8Array,
179
+ encoding?: string,
180
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
181
+ ): { name: string; data: Record<string, any> } | null;
182
+ }