@oobe-protocol-labs/synapse-sap-sdk 0.6.2 → 0.7.0

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 (140) hide show
  1. package/dist/cjs/constants/seeds.js +7 -0
  2. package/dist/cjs/constants/seeds.js.map +1 -1
  3. package/dist/cjs/core/client.js +42 -0
  4. package/dist/cjs/core/client.js.map +1 -1
  5. package/dist/cjs/events/geyser.js +295 -0
  6. package/dist/cjs/events/geyser.js.map +1 -0
  7. package/dist/cjs/idl/synapse_agent_sap.json +7545 -3501
  8. package/dist/cjs/index.js +28 -3
  9. package/dist/cjs/index.js.map +1 -1
  10. package/dist/cjs/modules/escrow-v2.js +241 -0
  11. package/dist/cjs/modules/escrow-v2.js.map +1 -0
  12. package/dist/cjs/modules/escrow.js +4 -0
  13. package/dist/cjs/modules/escrow.js.map +1 -1
  14. package/dist/cjs/modules/index.js +7 -1
  15. package/dist/cjs/modules/index.js.map +1 -1
  16. package/dist/cjs/modules/staking.js +94 -0
  17. package/dist/cjs/modules/staking.js.map +1 -0
  18. package/dist/cjs/modules/subscription.js +96 -0
  19. package/dist/cjs/modules/subscription.js.map +1 -0
  20. package/dist/cjs/pda/index.js +143 -1
  21. package/dist/cjs/pda/index.js.map +1 -1
  22. package/dist/cjs/postgres/sync.js +72 -4
  23. package/dist/cjs/postgres/sync.js.map +1 -1
  24. package/dist/cjs/registries/x402.js +88 -51
  25. package/dist/cjs/registries/x402.js.map +1 -1
  26. package/dist/cjs/types/enums.js +51 -1
  27. package/dist/cjs/types/enums.js.map +1 -1
  28. package/dist/cjs/types/index.js +4 -1
  29. package/dist/cjs/types/index.js.map +1 -1
  30. package/dist/cjs/types/instructions.js.map +1 -1
  31. package/dist/cjs/utils/escrow-validation.js +219 -0
  32. package/dist/cjs/utils/escrow-validation.js.map +1 -0
  33. package/dist/cjs/utils/index.js +12 -1
  34. package/dist/cjs/utils/index.js.map +1 -1
  35. package/dist/cjs/utils/merchant-validator.js +246 -0
  36. package/dist/cjs/utils/merchant-validator.js.map +1 -0
  37. package/dist/cjs/utils/x402-direct.js +231 -0
  38. package/dist/cjs/utils/x402-direct.js.map +1 -0
  39. package/dist/esm/constants/seeds.js +7 -0
  40. package/dist/esm/constants/seeds.js.map +1 -1
  41. package/dist/esm/core/client.js +42 -0
  42. package/dist/esm/core/client.js.map +1 -1
  43. package/dist/esm/events/geyser.js +258 -0
  44. package/dist/esm/events/geyser.js.map +1 -0
  45. package/dist/esm/idl/synapse_agent_sap.json +7545 -3501
  46. package/dist/esm/index.js +7 -3
  47. package/dist/esm/index.js.map +1 -1
  48. package/dist/esm/modules/escrow-v2.js +237 -0
  49. package/dist/esm/modules/escrow-v2.js.map +1 -0
  50. package/dist/esm/modules/escrow.js +4 -0
  51. package/dist/esm/modules/escrow.js.map +1 -1
  52. package/dist/esm/modules/index.js +3 -0
  53. package/dist/esm/modules/index.js.map +1 -1
  54. package/dist/esm/modules/staking.js +90 -0
  55. package/dist/esm/modules/staking.js.map +1 -0
  56. package/dist/esm/modules/subscription.js +92 -0
  57. package/dist/esm/modules/subscription.js.map +1 -0
  58. package/dist/esm/pda/index.js +135 -0
  59. package/dist/esm/pda/index.js.map +1 -1
  60. package/dist/esm/postgres/sync.js +72 -4
  61. package/dist/esm/postgres/sync.js.map +1 -1
  62. package/dist/esm/registries/x402.js +89 -52
  63. package/dist/esm/registries/x402.js.map +1 -1
  64. package/dist/esm/types/enums.js +50 -0
  65. package/dist/esm/types/enums.js.map +1 -1
  66. package/dist/esm/types/index.js +1 -1
  67. package/dist/esm/types/index.js.map +1 -1
  68. package/dist/esm/types/instructions.js.map +1 -1
  69. package/dist/esm/utils/escrow-validation.js +212 -0
  70. package/dist/esm/utils/escrow-validation.js.map +1 -0
  71. package/dist/esm/utils/index.js +4 -0
  72. package/dist/esm/utils/index.js.map +1 -1
  73. package/dist/esm/utils/merchant-validator.js +241 -0
  74. package/dist/esm/utils/merchant-validator.js.map +1 -0
  75. package/dist/esm/utils/x402-direct.js +228 -0
  76. package/dist/esm/utils/x402-direct.js.map +1 -0
  77. package/dist/types/constants/seeds.d.ts +7 -0
  78. package/dist/types/constants/seeds.d.ts.map +1 -1
  79. package/dist/types/core/client.d.ts +33 -0
  80. package/dist/types/core/client.d.ts.map +1 -1
  81. package/dist/types/events/geyser.d.ts +150 -0
  82. package/dist/types/events/geyser.d.ts.map +1 -0
  83. package/dist/types/index.d.ts +8 -4
  84. package/dist/types/index.d.ts.map +1 -1
  85. package/dist/types/modules/escrow-v2.d.ts +51 -0
  86. package/dist/types/modules/escrow-v2.d.ts.map +1 -0
  87. package/dist/types/modules/escrow.d.ts +4 -0
  88. package/dist/types/modules/escrow.d.ts.map +1 -1
  89. package/dist/types/modules/index.d.ts +3 -0
  90. package/dist/types/modules/index.d.ts.map +1 -1
  91. package/dist/types/modules/staking.d.ts +32 -0
  92. package/dist/types/modules/staking.d.ts.map +1 -0
  93. package/dist/types/modules/subscription.d.ts +33 -0
  94. package/dist/types/modules/subscription.d.ts.map +1 -0
  95. package/dist/types/pda/index.d.ts +99 -0
  96. package/dist/types/pda/index.d.ts.map +1 -1
  97. package/dist/types/plugin/schemas.d.ts +2 -2
  98. package/dist/types/postgres/sync.d.ts +26 -2
  99. package/dist/types/postgres/sync.d.ts.map +1 -1
  100. package/dist/types/registries/x402.d.ts +14 -12
  101. package/dist/types/registries/x402.d.ts.map +1 -1
  102. package/dist/types/types/accounts.d.ts +157 -1
  103. package/dist/types/types/accounts.d.ts.map +1 -1
  104. package/dist/types/types/enums.d.ts +64 -0
  105. package/dist/types/types/enums.d.ts.map +1 -1
  106. package/dist/types/types/index.d.ts +4 -4
  107. package/dist/types/types/index.d.ts.map +1 -1
  108. package/dist/types/types/instructions.d.ts +34 -0
  109. package/dist/types/types/instructions.d.ts.map +1 -1
  110. package/dist/types/utils/escrow-validation.d.ts +145 -0
  111. package/dist/types/utils/escrow-validation.d.ts.map +1 -0
  112. package/dist/types/utils/index.d.ts +6 -0
  113. package/dist/types/utils/index.d.ts.map +1 -1
  114. package/dist/types/utils/merchant-validator.d.ts +176 -0
  115. package/dist/types/utils/merchant-validator.d.ts.map +1 -0
  116. package/dist/types/utils/x402-direct.d.ts +114 -0
  117. package/dist/types/utils/x402-direct.d.ts.map +1 -0
  118. package/package.json +5 -1
  119. package/src/constants/seeds.ts +7 -0
  120. package/src/core/client.ts +45 -0
  121. package/src/events/geyser.ts +384 -0
  122. package/src/events/yellowstone.d.ts +7 -0
  123. package/src/idl/synapse_agent_sap.json +7545 -3501
  124. package/src/index.ts +51 -0
  125. package/src/modules/escrow-v2.ts +396 -0
  126. package/src/modules/escrow.ts +4 -0
  127. package/src/modules/index.ts +3 -0
  128. package/src/modules/staking.ts +122 -0
  129. package/src/modules/subscription.ts +147 -0
  130. package/src/pda/index.ts +196 -0
  131. package/src/postgres/sync.ts +90 -4
  132. package/src/registries/x402.ts +108 -69
  133. package/src/types/accounts.ts +192 -1
  134. package/src/types/enums.ts +65 -0
  135. package/src/types/index.ts +15 -0
  136. package/src/types/instructions.ts +40 -0
  137. package/src/utils/escrow-validation.ts +301 -0
  138. package/src/utils/index.ts +28 -0
  139. package/src/utils/merchant-validator.ts +359 -0
  140. package/src/utils/x402-direct.ts +370 -0
@@ -0,0 +1,370 @@
1
+ /**
2
+ * @module utils/x402-direct
3
+ * @description Recognize x402 direct SPL token payments on an agent's ATA
4
+ * by scanning transaction history and filtering for x402 patterns.
5
+ *
6
+ * @category Utils
7
+ * @since v0.6.4
8
+ */
9
+
10
+ import {
11
+ type Connection,
12
+ PublicKey,
13
+ type ParsedTransactionWithMeta,
14
+ type ConfirmedSignatureInfo,
15
+ } from "@solana/web3.js";
16
+ import { sha256 } from "../utils";
17
+
18
+ // ═══════════════════════════════════════════════════════════════════
19
+ // Types
20
+ // ═══════════════════════════════════════════════════════════════════
21
+
22
+ /**
23
+ * @interface SettlementPayload
24
+ * @description Settlement metadata from the merchant's PAYMENT-RESPONSE.
25
+ * @category Utils
26
+ * @since v0.6.4
27
+ */
28
+ export interface SettlementPayload {
29
+ /** SHA-256 service hash. */
30
+ readonly serviceHash: string;
31
+ /** Resource identifier. */
32
+ readonly resource: string;
33
+ /** Agent wallet (base58). */
34
+ readonly agentWallet: string;
35
+ /** Depositor wallet (base58). */
36
+ readonly depositorWallet: string;
37
+ /** Amount in smallest unit. */
38
+ readonly amount: string;
39
+ /** Service timestamp. */
40
+ readonly timestamp: number;
41
+ }
42
+
43
+ /**
44
+ * @interface X402DirectPayment
45
+ * @description A recognized x402 direct SPL transfer on an agent's ATA.
46
+ * @category Utils
47
+ * @since v0.6.4
48
+ */
49
+ export interface X402DirectPayment {
50
+ /** Transaction signature. */
51
+ readonly signature: string;
52
+ /** Transfer amount (in smallest token unit). */
53
+ readonly amount: bigint;
54
+ /** Source ATA (payer). */
55
+ readonly payerAta: PublicKey;
56
+ /** Destination ATA (payTo / agent). */
57
+ readonly payeeAta: PublicKey;
58
+ /** Token mint used for transfer. */
59
+ readonly mint: PublicKey;
60
+ /** Memo data (if a Memo instruction was included). */
61
+ readonly memo: string | null;
62
+ /** Matched settlement payload (if server-side verification is available). */
63
+ readonly settlement: SettlementPayload | null;
64
+ /** Block time (unix seconds). */
65
+ readonly blockTime: number | null;
66
+ /** Slot number. */
67
+ readonly slot: number;
68
+ }
69
+
70
+ /**
71
+ * @interface GetX402DirectOptions
72
+ * @description Options for {@link getX402DirectPayments}.
73
+ * @category Utils
74
+ * @since v0.6.4
75
+ */
76
+ export interface GetX402DirectOptions {
77
+ /** Max signatures to scan (default: 100). */
78
+ readonly limit?: number;
79
+ /** Only return transfers from this specific payer. */
80
+ readonly filterPayer?: PublicKey;
81
+ /** Known settlements from server-side PAYMENT-RESPONSE logs.
82
+ * Used for deterministic hash matching. */
83
+ readonly knownSettlements?: SettlementPayload[];
84
+ /** Only include payments that match x402 memo prefix. Default: false. */
85
+ readonly requireMemo?: boolean;
86
+ /** Scan before this TX signature (pagination). */
87
+ readonly before?: string;
88
+ /** Scan after this TX signature (pagination). */
89
+ readonly until?: string;
90
+ }
91
+
92
+ // ═══════════════════════════════════════════════════════════════════
93
+ // Core
94
+ // ═══════════════════════════════════════════════════════════════════
95
+
96
+ /** Recognized x402 memo prefixes. */
97
+ const X402_MEMO_PREFIXES = ["x402:", "SAP-x402:", "x402-direct:"];
98
+
99
+ /**
100
+ * @name extractSplTransfer
101
+ * @description Extract SPL Token transfer details from a parsed transaction.
102
+ *
103
+ * Looks for `transfer` or `transferChecked` inner instructions on the
104
+ * Token Program and returns source/dest/amount/mint.
105
+ *
106
+ * @internal
107
+ */
108
+ function extractSplTransfer(
109
+ tx: ParsedTransactionWithMeta,
110
+ payToAta: PublicKey,
111
+ ): {
112
+ amount: bigint;
113
+ source: PublicKey;
114
+ destination: PublicKey;
115
+ mint: PublicKey;
116
+ } | null {
117
+ if (!tx.meta?.innerInstructions && !tx.transaction.message.instructions) {
118
+ return null;
119
+ }
120
+
121
+ // Check all instructions (outer + inner)
122
+ const allIxs = [
123
+ ...tx.transaction.message.instructions,
124
+ ...(tx.meta?.innerInstructions?.flatMap((g) => g.instructions) ?? []),
125
+ ];
126
+
127
+ for (const ix of allIxs) {
128
+ // Only process parsed instructions with known program
129
+ if (!("parsed" in ix) || !("program" in ix)) continue;
130
+ const parsed = ix as { parsed: Record<string, unknown>; program: string };
131
+
132
+ if (parsed.program !== "spl-token") continue;
133
+
134
+ const info = parsed.parsed as {
135
+ type?: string;
136
+ info?: {
137
+ source?: string;
138
+ destination?: string;
139
+ amount?: string;
140
+ tokenAmount?: { amount?: string };
141
+ mint?: string;
142
+ authority?: string;
143
+ };
144
+ };
145
+
146
+ if (
147
+ info.type !== "transfer" &&
148
+ info.type !== "transferChecked"
149
+ ) {
150
+ continue;
151
+ }
152
+
153
+ const transferInfo = info.info;
154
+ if (!transferInfo?.source || !transferInfo?.destination) continue;
155
+
156
+ // Check destination matches our payTo ATA
157
+ const destPk = new PublicKey(transferInfo.destination);
158
+ if (!destPk.equals(payToAta)) continue;
159
+
160
+ const amountStr =
161
+ transferInfo.amount ?? transferInfo.tokenAmount?.amount ?? "0";
162
+
163
+ return {
164
+ amount: BigInt(amountStr),
165
+ source: new PublicKey(transferInfo.source),
166
+ destination: destPk,
167
+ mint: transferInfo.mint ? new PublicKey(transferInfo.mint) : destPk, // fallback
168
+ };
169
+ }
170
+
171
+ return null;
172
+ }
173
+
174
+ /**
175
+ * @name extractMemo
176
+ * @description Extract memo data from a parsed transaction.
177
+ * @internal
178
+ */
179
+ function extractMemo(tx: ParsedTransactionWithMeta): string | null {
180
+ const allIxs = [
181
+ ...tx.transaction.message.instructions,
182
+ ...(tx.meta?.innerInstructions?.flatMap((g) => g.instructions) ?? []),
183
+ ];
184
+
185
+ for (const ix of allIxs) {
186
+ if (!("parsed" in ix) || !("program" in ix)) continue;
187
+ const parsed = ix as { parsed: unknown; program: string };
188
+ if (parsed.program === "spl-memo" && typeof parsed.parsed === "string") {
189
+ return parsed.parsed;
190
+ }
191
+ }
192
+
193
+ // Also check log messages for memo
194
+ if (tx.meta?.logMessages) {
195
+ for (const log of tx.meta.logMessages) {
196
+ if (log.startsWith("Program log: Memo")) {
197
+ const memoMatch = log.match(/Memo \(len \d+\): "(.*?)"/);
198
+ if (memoMatch?.[1]) return memoMatch[1];
199
+ }
200
+ }
201
+ }
202
+
203
+ return null;
204
+ }
205
+
206
+ /**
207
+ * @name matchesX402Pattern
208
+ * @description Check if a transfer matches an x402 payment pattern.
209
+ *
210
+ * Matches if:
211
+ * - A memo with recognized x402 prefix is present, OR
212
+ * - The transfer matches a known settlement payload (deterministic hash), OR
213
+ * - `requireMemo` is false (any SPL transfer to the ATA is included)
214
+ *
215
+ * @internal
216
+ */
217
+ function matchesX402Pattern(
218
+ transfer: { amount: bigint; source: PublicKey },
219
+ memo: string | null,
220
+ knownSettlements: SettlementPayload[],
221
+ requireMemo: boolean,
222
+ ): SettlementPayload | true | false {
223
+ // 1. Check memo prefix
224
+ if (memo) {
225
+ for (const prefix of X402_MEMO_PREFIXES) {
226
+ if (memo.startsWith(prefix)) return true;
227
+ }
228
+ // Try base64 JSON parse for embedded x402 payload
229
+ try {
230
+ const decoded = Buffer.from(memo, "base64").toString("utf-8");
231
+ const parsed = JSON.parse(decoded);
232
+ if (parsed.protocol === "x402" || parsed.protocol === "SAP-x402") {
233
+ return true;
234
+ }
235
+ } catch {
236
+ // Not base64 JSON — ignore
237
+ }
238
+ }
239
+
240
+ // 2. Match against known settlements (deterministic hash)
241
+ for (const settlement of knownSettlements) {
242
+ const expected = BigInt(settlement.amount);
243
+ if (transfer.amount !== expected) continue;
244
+
245
+ // Deterministic hash: sha256(agentWallet + depositor + amount + timestamp)
246
+ const hashInput =
247
+ settlement.agentWallet +
248
+ settlement.depositorWallet +
249
+ settlement.amount +
250
+ settlement.timestamp.toString();
251
+ const expectedHash = Buffer.from(sha256(hashInput)).toString("hex");
252
+ const serviceHash = settlement.serviceHash;
253
+
254
+ if (expectedHash === serviceHash) return settlement;
255
+ }
256
+
257
+ // 3. If requireMemo is false, accept any SPL transfer to the ATA
258
+ if (!requireMemo) return true;
259
+
260
+ return false;
261
+ }
262
+
263
+ /**
264
+ * @name getX402DirectPayments
265
+ * @description Scan an agent's ATA for x402 direct payments.
266
+ *
267
+ * Fetches recent transaction signatures for the given `payTo` ATA,
268
+ * inspects each transaction for SPL token transfers, and filters
269
+ * for x402 payment patterns (memo prefix, settlement hash match, etc.).
270
+ *
271
+ * @param connection - Solana RPC connection.
272
+ * @param payToAta - The agent's receiving ATA (e.g. USDC ATA of Syra).
273
+ * @param opts - Filter and pagination options.
274
+ * @returns Array of recognized x402 direct payments, newest first.
275
+ *
276
+ * @category Utils
277
+ * @since v0.6.4
278
+ *
279
+ * @example
280
+ * ```ts
281
+ * import { getX402DirectPayments, findATA } from "@oobe-protocol-labs/synapse-sap-sdk";
282
+ *
283
+ * const USDC_MINT = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
284
+ * const payToAta = findATA(agentWallet, USDC_MINT);
285
+ *
286
+ * const payments = await getX402DirectPayments(connection, payToAta, {
287
+ * limit: 50,
288
+ * knownSettlements: savedSettlements, // from your API PAYMENT-RESPONSE logs
289
+ * });
290
+ *
291
+ * for (const p of payments) {
292
+ * console.log(`${p.signature}: ${p.amount} from ${p.payerAta.toBase58()}`);
293
+ * if (p.settlement) {
294
+ * console.log(` Matched settlement: ${p.settlement.serviceHash}`);
295
+ * }
296
+ * }
297
+ * ```
298
+ */
299
+ export async function getX402DirectPayments(
300
+ connection: Connection,
301
+ payToAta: PublicKey,
302
+ opts?: GetX402DirectOptions,
303
+ ): Promise<X402DirectPayment[]> {
304
+ const limit = opts?.limit ?? 100;
305
+ const knownSettlements = opts?.knownSettlements ?? [];
306
+ const requireMemo = opts?.requireMemo ?? false;
307
+
308
+ // 1. Fetch signatures
309
+ const sigOpts: {
310
+ limit: number;
311
+ before?: string;
312
+ until?: string;
313
+ } = { limit };
314
+ if (opts?.before) sigOpts.before = opts.before;
315
+ if (opts?.until) sigOpts.until = opts.until;
316
+
317
+ const sigs: ConfirmedSignatureInfo[] =
318
+ await connection.getSignaturesForAddress(payToAta, sigOpts);
319
+
320
+ if (sigs.length === 0) return [];
321
+
322
+ // 2. Fetch transactions (batch with getParsedTransactions if available)
323
+ const txs = await connection.getParsedTransactions(
324
+ sigs.map((s) => s.signature),
325
+ { maxSupportedTransactionVersion: 0 },
326
+ );
327
+
328
+ // 3. Extract and filter
329
+ const results: X402DirectPayment[] = [];
330
+
331
+ for (let i = 0; i < txs.length; i++) {
332
+ const tx = txs[i];
333
+ if (!tx) continue;
334
+
335
+ // Extract SPL transfer to our ATA
336
+ const transfer = extractSplTransfer(tx, payToAta);
337
+ if (!transfer) continue;
338
+
339
+ // Filter by payer if specified
340
+ if (opts?.filterPayer && !transfer.source.equals(opts.filterPayer)) {
341
+ continue;
342
+ }
343
+
344
+ // Extract memo
345
+ const memo = extractMemo(tx);
346
+
347
+ // Match x402 pattern
348
+ const match = matchesX402Pattern(
349
+ transfer,
350
+ memo,
351
+ knownSettlements,
352
+ requireMemo,
353
+ );
354
+ if (match === false) continue;
355
+
356
+ results.push({
357
+ signature: sigs[i]!.signature,
358
+ amount: transfer.amount,
359
+ payerAta: transfer.source,
360
+ payeeAta: transfer.destination,
361
+ mint: transfer.mint,
362
+ memo,
363
+ settlement: typeof match === "object" ? match : null,
364
+ blockTime: tx.blockTime ?? null,
365
+ slot: tx.slot,
366
+ });
367
+ }
368
+
369
+ return results;
370
+ }