x402-express-mantle 1.0.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 (127) hide show
  1. package/README.md +155 -0
  2. package/lib/cjs/client/index.d.ts +243 -0
  3. package/lib/cjs/client/index.js +413 -0
  4. package/lib/cjs/client/index.js.map +1 -0
  5. package/lib/cjs/exact/client/index.d.ts +37 -0
  6. package/lib/cjs/exact/client/index.js +281 -0
  7. package/lib/cjs/exact/client/index.js.map +1 -0
  8. package/lib/cjs/exact/facilitator/index.d.ts +110 -0
  9. package/lib/cjs/exact/facilitator/index.js +714 -0
  10. package/lib/cjs/exact/facilitator/index.js.map +1 -0
  11. package/lib/cjs/exact/server/index.d.ts +87 -0
  12. package/lib/cjs/exact/server/index.js +209 -0
  13. package/lib/cjs/exact/server/index.js.map +1 -0
  14. package/lib/cjs/exact/v1/client/index.d.ts +33 -0
  15. package/lib/cjs/exact/v1/client/index.js +169 -0
  16. package/lib/cjs/exact/v1/client/index.js.map +1 -0
  17. package/lib/cjs/exact/v1/facilitator/index.d.ts +71 -0
  18. package/lib/cjs/exact/v1/facilitator/index.js +384 -0
  19. package/lib/cjs/exact/v1/facilitator/index.js.map +1 -0
  20. package/lib/cjs/facilitator/index.d.ts +192 -0
  21. package/lib/cjs/facilitator/index.js +398 -0
  22. package/lib/cjs/facilitator/index.js.map +1 -0
  23. package/lib/cjs/http/index.d.ts +52 -0
  24. package/lib/cjs/http/index.js +827 -0
  25. package/lib/cjs/http/index.js.map +1 -0
  26. package/lib/cjs/index.d.ts +145 -0
  27. package/lib/cjs/index.js +314 -0
  28. package/lib/cjs/index.js.map +1 -0
  29. package/lib/cjs/mechanisms-CzuGzYsS.d.ts +270 -0
  30. package/lib/cjs/scheme-MoBRXFM8.d.ts +29 -0
  31. package/lib/cjs/server/index.d.ts +2 -0
  32. package/lib/cjs/server/index.js +1305 -0
  33. package/lib/cjs/server/index.js.map +1 -0
  34. package/lib/cjs/signer-5OVDxViv.d.ts +79 -0
  35. package/lib/cjs/signer-BMkbhFYE.d.ts +123 -0
  36. package/lib/cjs/types/index.d.ts +1 -0
  37. package/lib/cjs/types/index.js +66 -0
  38. package/lib/cjs/types/index.js.map +1 -0
  39. package/lib/cjs/types/v1/index.d.ts +1 -0
  40. package/lib/cjs/types/v1/index.js +19 -0
  41. package/lib/cjs/types/v1/index.js.map +1 -0
  42. package/lib/cjs/utils/index.d.ts +48 -0
  43. package/lib/cjs/utils/index.js +116 -0
  44. package/lib/cjs/utils/index.js.map +1 -0
  45. package/lib/cjs/v1/index.d.ts +12 -0
  46. package/lib/cjs/v1/index.js +180 -0
  47. package/lib/cjs/v1/index.js.map +1 -0
  48. package/lib/cjs/x402HTTPResourceServer-D1YtlH_r.d.ts +719 -0
  49. package/lib/esm/chunk-3CEIVWNN.mjs +339 -0
  50. package/lib/esm/chunk-3CEIVWNN.mjs.map +1 -0
  51. package/lib/esm/chunk-BJTO5JO5.mjs +11 -0
  52. package/lib/esm/chunk-BJTO5JO5.mjs.map +1 -0
  53. package/lib/esm/chunk-EEA7DKZI.mjs +111 -0
  54. package/lib/esm/chunk-EEA7DKZI.mjs.map +1 -0
  55. package/lib/esm/chunk-FOUXRQAV.mjs +88 -0
  56. package/lib/esm/chunk-FOUXRQAV.mjs.map +1 -0
  57. package/lib/esm/chunk-IKSTWKEM.mjs +157 -0
  58. package/lib/esm/chunk-IKSTWKEM.mjs.map +1 -0
  59. package/lib/esm/chunk-JYZWCLMP.mjs +305 -0
  60. package/lib/esm/chunk-JYZWCLMP.mjs.map +1 -0
  61. package/lib/esm/chunk-PNSAJQCF.mjs +108 -0
  62. package/lib/esm/chunk-PNSAJQCF.mjs.map +1 -0
  63. package/lib/esm/chunk-PSA4YVU2.mjs +92 -0
  64. package/lib/esm/chunk-PSA4YVU2.mjs.map +1 -0
  65. package/lib/esm/chunk-QLXM7BIB.mjs +23 -0
  66. package/lib/esm/chunk-QLXM7BIB.mjs.map +1 -0
  67. package/lib/esm/chunk-TDLQZ6MP.mjs +86 -0
  68. package/lib/esm/chunk-TDLQZ6MP.mjs.map +1 -0
  69. package/lib/esm/chunk-VE37GDG2.mjs +7 -0
  70. package/lib/esm/chunk-VE37GDG2.mjs.map +1 -0
  71. package/lib/esm/chunk-WWACQNRQ.mjs +7 -0
  72. package/lib/esm/chunk-WWACQNRQ.mjs.map +1 -0
  73. package/lib/esm/chunk-X4W4S5RB.mjs +39 -0
  74. package/lib/esm/chunk-X4W4S5RB.mjs.map +1 -0
  75. package/lib/esm/chunk-Z4QX3O5V.mjs +748 -0
  76. package/lib/esm/chunk-Z4QX3O5V.mjs.map +1 -0
  77. package/lib/esm/chunk-ZYXTTU74.mjs +88 -0
  78. package/lib/esm/chunk-ZYXTTU74.mjs.map +1 -0
  79. package/lib/esm/client/index.d.mts +243 -0
  80. package/lib/esm/client/index.mjs +260 -0
  81. package/lib/esm/client/index.mjs.map +1 -0
  82. package/lib/esm/exact/client/index.d.mts +37 -0
  83. package/lib/esm/exact/client/index.mjs +36 -0
  84. package/lib/esm/exact/client/index.mjs.map +1 -0
  85. package/lib/esm/exact/facilitator/index.d.mts +110 -0
  86. package/lib/esm/exact/facilitator/index.mjs +350 -0
  87. package/lib/esm/exact/facilitator/index.mjs.map +1 -0
  88. package/lib/esm/exact/server/index.d.mts +87 -0
  89. package/lib/esm/exact/server/index.mjs +129 -0
  90. package/lib/esm/exact/server/index.mjs.map +1 -0
  91. package/lib/esm/exact/v1/client/index.d.mts +33 -0
  92. package/lib/esm/exact/v1/client/index.mjs +8 -0
  93. package/lib/esm/exact/v1/client/index.mjs.map +1 -0
  94. package/lib/esm/exact/v1/facilitator/index.d.mts +71 -0
  95. package/lib/esm/exact/v1/facilitator/index.mjs +8 -0
  96. package/lib/esm/exact/v1/facilitator/index.mjs.map +1 -0
  97. package/lib/esm/facilitator/index.d.mts +192 -0
  98. package/lib/esm/facilitator/index.mjs +373 -0
  99. package/lib/esm/facilitator/index.mjs.map +1 -0
  100. package/lib/esm/http/index.d.mts +52 -0
  101. package/lib/esm/http/index.mjs +29 -0
  102. package/lib/esm/http/index.mjs.map +1 -0
  103. package/lib/esm/index.d.mts +145 -0
  104. package/lib/esm/index.mjs +277 -0
  105. package/lib/esm/index.mjs.map +1 -0
  106. package/lib/esm/mechanisms-CzuGzYsS.d.mts +270 -0
  107. package/lib/esm/scheme-fjF-9LhT.d.mts +29 -0
  108. package/lib/esm/server/index.d.mts +2 -0
  109. package/lib/esm/server/index.mjs +563 -0
  110. package/lib/esm/server/index.mjs.map +1 -0
  111. package/lib/esm/signer-5OVDxViv.d.mts +79 -0
  112. package/lib/esm/signer-BMkbhFYE.d.mts +123 -0
  113. package/lib/esm/types/index.d.mts +1 -0
  114. package/lib/esm/types/index.mjs +10 -0
  115. package/lib/esm/types/index.mjs.map +1 -0
  116. package/lib/esm/types/v1/index.d.mts +1 -0
  117. package/lib/esm/types/v1/index.mjs +1 -0
  118. package/lib/esm/types/v1/index.mjs.map +1 -0
  119. package/lib/esm/utils/index.d.mts +48 -0
  120. package/lib/esm/utils/index.mjs +20 -0
  121. package/lib/esm/utils/index.mjs.map +1 -0
  122. package/lib/esm/v1/index.d.mts +12 -0
  123. package/lib/esm/v1/index.mjs +13 -0
  124. package/lib/esm/v1/index.mjs.map +1 -0
  125. package/lib/esm/x402HTTPResourceServer-BIfIK5HS.d.mts +719 -0
  126. package/package.json +39 -0
  127. package/src/index.js +4 -0
@@ -0,0 +1,714 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/exact/facilitator/index.ts
21
+ var facilitator_exports = {};
22
+ __export(facilitator_exports, {
23
+ ExactSvmScheme: () => ExactSvmScheme,
24
+ registerExactSvmScheme: () => registerExactSvmScheme
25
+ });
26
+ module.exports = __toCommonJS(facilitator_exports);
27
+
28
+ // src/exact/facilitator/scheme.ts
29
+ var import_compute_budget = require("@solana-program/compute-budget");
30
+ var import_token2 = require("@solana-program/token");
31
+ var import_token_20222 = require("@solana-program/token-2022");
32
+ var import_kit2 = require("@solana/kit");
33
+
34
+ // src/constants.ts
35
+ var MAX_COMPUTE_UNIT_PRICE_MICROLAMPORTS = 5e6;
36
+
37
+ // src/utils.ts
38
+ var import_kit = require("@solana/kit");
39
+ var import_token = require("@solana-program/token");
40
+ var import_token_2022 = require("@solana-program/token-2022");
41
+ function decodeTransactionFromPayload(svmPayload) {
42
+ try {
43
+ const base64Encoder = (0, import_kit.getBase64Encoder)();
44
+ const transactionBytes = base64Encoder.encode(svmPayload.transaction);
45
+ const transactionDecoder = (0, import_kit.getTransactionDecoder)();
46
+ return transactionDecoder.decode(transactionBytes);
47
+ } catch (error) {
48
+ console.error("Error decoding transaction:", error);
49
+ throw new Error("invalid_exact_svm_payload_transaction");
50
+ }
51
+ }
52
+ function getTokenPayerFromTransaction(transaction) {
53
+ const compiled = (0, import_kit.getCompiledTransactionMessageDecoder)().decode(transaction.messageBytes);
54
+ const staticAccounts = compiled.staticAccounts ?? [];
55
+ const instructions = compiled.instructions ?? [];
56
+ for (const ix of instructions) {
57
+ const programIndex = ix.programAddressIndex;
58
+ const programAddress = staticAccounts[programIndex].toString();
59
+ if (programAddress === import_token.TOKEN_PROGRAM_ADDRESS.toString() || programAddress === import_token_2022.TOKEN_2022_PROGRAM_ADDRESS.toString()) {
60
+ const accountIndices = ix.accountIndices ?? [];
61
+ if (accountIndices.length >= 4) {
62
+ const ownerIndex = accountIndices[3];
63
+ const ownerAddress = staticAccounts[ownerIndex].toString();
64
+ if (ownerAddress) return ownerAddress;
65
+ }
66
+ }
67
+ }
68
+ return "";
69
+ }
70
+
71
+ // src/exact/facilitator/scheme.ts
72
+ var ExactSvmScheme = class {
73
+ /**
74
+ * Creates a new ExactSvmFacilitator instance.
75
+ *
76
+ * @param signer - The SVM RPC client for facilitator operations
77
+ * @returns ExactSvmFacilitator instance
78
+ */
79
+ constructor(signer) {
80
+ this.signer = signer;
81
+ this.scheme = "exact";
82
+ this.caipFamily = "solana:*";
83
+ }
84
+ /**
85
+ * Get mechanism-specific extra data for the supported kinds endpoint.
86
+ * For SVM, this includes a randomly selected fee payer address.
87
+ * Random selection distributes load across multiple signers.
88
+ *
89
+ * @param _ - The network identifier (unused for SVM)
90
+ * @returns Extra data with feePayer address
91
+ */
92
+ getExtra(_) {
93
+ const addresses = this.signer.getAddresses();
94
+ const randomIndex = Math.floor(Math.random() * addresses.length);
95
+ return {
96
+ feePayer: addresses[randomIndex]
97
+ };
98
+ }
99
+ /**
100
+ * Get signer addresses used by this facilitator.
101
+ * For SVM, returns all available fee payer addresses.
102
+ *
103
+ * @param _ - The network identifier (unused for SVM)
104
+ * @returns Array of fee payer addresses
105
+ */
106
+ getSigners(_) {
107
+ return [...this.signer.getAddresses()];
108
+ }
109
+ /**
110
+ * Verifies a payment payload.
111
+ *
112
+ * @param payload - The payment payload to verify
113
+ * @param requirements - The payment requirements
114
+ * @returns Promise resolving to verification response
115
+ */
116
+ async verify(payload, requirements) {
117
+ const exactSvmPayload = payload.payload;
118
+ if (payload.accepted.scheme !== "exact" || requirements.scheme !== "exact") {
119
+ return {
120
+ isValid: false,
121
+ invalidReason: "unsupported_scheme",
122
+ payer: ""
123
+ };
124
+ }
125
+ if (payload.accepted.network !== requirements.network) {
126
+ return {
127
+ isValid: false,
128
+ invalidReason: "network_mismatch",
129
+ payer: ""
130
+ };
131
+ }
132
+ if (!requirements.extra?.feePayer || typeof requirements.extra.feePayer !== "string") {
133
+ return {
134
+ isValid: false,
135
+ invalidReason: "invalid_exact_svm_payload_missing_fee_payer",
136
+ payer: ""
137
+ };
138
+ }
139
+ const signerAddresses = this.signer.getAddresses().map((addr) => addr.toString());
140
+ if (!signerAddresses.includes(requirements.extra.feePayer)) {
141
+ return {
142
+ isValid: false,
143
+ invalidReason: "fee_payer_not_managed_by_facilitator",
144
+ payer: ""
145
+ };
146
+ }
147
+ let transaction;
148
+ try {
149
+ transaction = decodeTransactionFromPayload(exactSvmPayload);
150
+ } catch {
151
+ return {
152
+ isValid: false,
153
+ invalidReason: "invalid_exact_svm_payload_transaction_could_not_be_decoded",
154
+ payer: ""
155
+ };
156
+ }
157
+ const compiled = (0, import_kit2.getCompiledTransactionMessageDecoder)().decode(transaction.messageBytes);
158
+ const decompiled = (0, import_kit2.decompileTransactionMessage)(compiled);
159
+ const instructions = decompiled.instructions ?? [];
160
+ if (instructions.length !== 3) {
161
+ return {
162
+ isValid: false,
163
+ invalidReason: "invalid_exact_svm_payload_transaction_instructions_length",
164
+ payer: ""
165
+ };
166
+ }
167
+ try {
168
+ this.verifyComputeLimitInstruction(instructions[0]);
169
+ this.verifyComputePriceInstruction(instructions[1]);
170
+ } catch (error) {
171
+ const errorMessage = error instanceof Error ? error.message : String(error);
172
+ return {
173
+ isValid: false,
174
+ invalidReason: errorMessage,
175
+ payer: ""
176
+ };
177
+ }
178
+ const payer = getTokenPayerFromTransaction(transaction);
179
+ if (!payer) {
180
+ return {
181
+ isValid: false,
182
+ invalidReason: "invalid_exact_svm_payload_no_transfer_instruction",
183
+ payer: ""
184
+ };
185
+ }
186
+ const transferIx = instructions[2];
187
+ const programAddress = transferIx.programAddress.toString();
188
+ if (programAddress !== import_token2.TOKEN_PROGRAM_ADDRESS.toString() && programAddress !== import_token_20222.TOKEN_2022_PROGRAM_ADDRESS.toString()) {
189
+ return {
190
+ isValid: false,
191
+ invalidReason: "invalid_exact_svm_payload_no_transfer_instruction",
192
+ payer
193
+ };
194
+ }
195
+ let parsedTransfer;
196
+ try {
197
+ if (programAddress === import_token2.TOKEN_PROGRAM_ADDRESS.toString()) {
198
+ parsedTransfer = (0, import_token2.parseTransferCheckedInstruction)(transferIx);
199
+ } else {
200
+ parsedTransfer = (0, import_token_20222.parseTransferCheckedInstruction)(transferIx);
201
+ }
202
+ } catch {
203
+ return {
204
+ isValid: false,
205
+ invalidReason: "invalid_exact_svm_payload_no_transfer_instruction",
206
+ payer
207
+ };
208
+ }
209
+ const authorityAddress = parsedTransfer.accounts.authority.address.toString();
210
+ if (signerAddresses.includes(authorityAddress)) {
211
+ return {
212
+ isValid: false,
213
+ invalidReason: "invalid_exact_svm_payload_transaction_fee_payer_transferring_funds",
214
+ payer
215
+ };
216
+ }
217
+ const mintAddress = parsedTransfer.accounts.mint.address.toString();
218
+ if (mintAddress !== requirements.asset) {
219
+ return {
220
+ isValid: false,
221
+ invalidReason: "invalid_exact_svm_payload_mint_mismatch",
222
+ payer
223
+ };
224
+ }
225
+ const destATA = parsedTransfer.accounts.destination.address.toString();
226
+ try {
227
+ const [expectedDestATA] = await (0, import_token_20222.findAssociatedTokenPda)({
228
+ mint: requirements.asset,
229
+ owner: requirements.payTo,
230
+ tokenProgram: programAddress === import_token2.TOKEN_PROGRAM_ADDRESS.toString() ? import_token2.TOKEN_PROGRAM_ADDRESS : import_token_20222.TOKEN_2022_PROGRAM_ADDRESS
231
+ });
232
+ if (destATA !== expectedDestATA.toString()) {
233
+ return {
234
+ isValid: false,
235
+ invalidReason: "invalid_exact_svm_payload_recipient_mismatch",
236
+ payer
237
+ };
238
+ }
239
+ } catch {
240
+ return {
241
+ isValid: false,
242
+ invalidReason: "invalid_exact_svm_payload_recipient_mismatch",
243
+ payer
244
+ };
245
+ }
246
+ const amount = parsedTransfer.data.amount;
247
+ if (amount < BigInt(requirements.amount)) {
248
+ return {
249
+ isValid: false,
250
+ invalidReason: "invalid_exact_svm_payload_amount_insufficient",
251
+ payer
252
+ };
253
+ }
254
+ try {
255
+ const feePayer = requirements.extra.feePayer;
256
+ const fullySignedTransaction = await this.signer.signTransaction(
257
+ exactSvmPayload.transaction,
258
+ feePayer,
259
+ requirements.network
260
+ );
261
+ await this.signer.simulateTransaction(fullySignedTransaction, requirements.network);
262
+ } catch (error) {
263
+ const errorMessage = error instanceof Error ? error.message : String(error);
264
+ return {
265
+ isValid: false,
266
+ invalidReason: `transaction_simulation_failed: ${errorMessage}`,
267
+ payer
268
+ };
269
+ }
270
+ return {
271
+ isValid: true,
272
+ invalidReason: void 0,
273
+ payer
274
+ };
275
+ }
276
+ /**
277
+ * Settles a payment by submitting the transaction.
278
+ * Ensures the correct signer is used based on the feePayer specified in requirements.
279
+ *
280
+ * @param payload - The payment payload to settle
281
+ * @param requirements - The payment requirements
282
+ * @returns Promise resolving to settlement response
283
+ */
284
+ async settle(payload, requirements) {
285
+ const exactSvmPayload = payload.payload;
286
+ const valid = await this.verify(payload, requirements);
287
+ if (!valid.isValid) {
288
+ return {
289
+ success: false,
290
+ network: payload.accepted.network,
291
+ transaction: "",
292
+ errorReason: valid.invalidReason ?? "verification_failed",
293
+ payer: valid.payer || ""
294
+ };
295
+ }
296
+ try {
297
+ const feePayer = requirements.extra.feePayer;
298
+ const fullySignedTransaction = await this.signer.signTransaction(
299
+ exactSvmPayload.transaction,
300
+ feePayer,
301
+ requirements.network
302
+ );
303
+ const signature = await this.signer.sendTransaction(
304
+ fullySignedTransaction,
305
+ requirements.network
306
+ );
307
+ await this.signer.confirmTransaction(signature, requirements.network);
308
+ return {
309
+ success: true,
310
+ transaction: signature,
311
+ network: payload.accepted.network,
312
+ payer: valid.payer
313
+ };
314
+ } catch (error) {
315
+ console.error("Failed to settle transaction:", error);
316
+ return {
317
+ success: false,
318
+ errorReason: "transaction_failed",
319
+ transaction: "",
320
+ network: payload.accepted.network,
321
+ payer: valid.payer || ""
322
+ };
323
+ }
324
+ }
325
+ /**
326
+ * Verify that the compute limit instruction is valid.
327
+ *
328
+ * @param instruction - The compute limit instruction
329
+ * @param instruction.programAddress - Program address
330
+ * @param instruction.data - Instruction data bytes
331
+ */
332
+ verifyComputeLimitInstruction(instruction) {
333
+ const programAddress = instruction.programAddress.toString();
334
+ if (programAddress !== import_compute_budget.COMPUTE_BUDGET_PROGRAM_ADDRESS.toString() || !instruction.data || instruction.data[0] !== 2) {
335
+ throw new Error(
336
+ "invalid_exact_svm_payload_transaction_instructions_compute_limit_instruction"
337
+ );
338
+ }
339
+ try {
340
+ (0, import_compute_budget.parseSetComputeUnitLimitInstruction)(instruction);
341
+ } catch {
342
+ throw new Error(
343
+ "invalid_exact_svm_payload_transaction_instructions_compute_limit_instruction"
344
+ );
345
+ }
346
+ }
347
+ /**
348
+ * Verify that the compute price instruction is valid.
349
+ *
350
+ * @param instruction - The compute price instruction
351
+ * @param instruction.programAddress - Program address
352
+ * @param instruction.data - Instruction data bytes
353
+ */
354
+ verifyComputePriceInstruction(instruction) {
355
+ const programAddress = instruction.programAddress.toString();
356
+ if (programAddress !== import_compute_budget.COMPUTE_BUDGET_PROGRAM_ADDRESS.toString() || !instruction.data || instruction.data[0] !== 3) {
357
+ throw new Error(
358
+ "invalid_exact_svm_payload_transaction_instructions_compute_price_instruction"
359
+ );
360
+ }
361
+ try {
362
+ const parsedInstruction = (0, import_compute_budget.parseSetComputeUnitPriceInstruction)(instruction);
363
+ if (parsedInstruction.microLamports > BigInt(MAX_COMPUTE_UNIT_PRICE_MICROLAMPORTS)) {
364
+ throw new Error(
365
+ "invalid_exact_svm_payload_transaction_instructions_compute_price_instruction_too_high"
366
+ );
367
+ }
368
+ } catch (error) {
369
+ if (error instanceof Error && error.message.includes("too_high")) {
370
+ throw error;
371
+ }
372
+ throw new Error(
373
+ "invalid_exact_svm_payload_transaction_instructions_compute_price_instruction"
374
+ );
375
+ }
376
+ }
377
+ };
378
+
379
+ // src/exact/v1/facilitator/scheme.ts
380
+ var import_compute_budget2 = require("@solana-program/compute-budget");
381
+ var import_token3 = require("@solana-program/token");
382
+ var import_token_20223 = require("@solana-program/token-2022");
383
+ var import_kit3 = require("@solana/kit");
384
+ var ExactSvmSchemeV1 = class {
385
+ /**
386
+ * Creates a new ExactSvmFacilitatorV1 instance.
387
+ *
388
+ * @param signer - The SVM RPC client for facilitator operations
389
+ * @returns ExactSvmFacilitatorV1 instance
390
+ */
391
+ constructor(signer) {
392
+ this.signer = signer;
393
+ this.scheme = "exact";
394
+ this.caipFamily = "solana:*";
395
+ }
396
+ /**
397
+ * Get mechanism-specific extra data for the supported kinds endpoint.
398
+ * For SVM, this includes a randomly selected fee payer address.
399
+ * Random selection distributes load across multiple signers.
400
+ *
401
+ * @param _ - The network identifier (unused for SVM)
402
+ * @returns Extra data with feePayer address
403
+ */
404
+ getExtra(_) {
405
+ const addresses = this.signer.getAddresses();
406
+ const randomIndex = Math.floor(Math.random() * addresses.length);
407
+ return {
408
+ feePayer: addresses[randomIndex]
409
+ };
410
+ }
411
+ /**
412
+ * Get signer addresses used by this facilitator.
413
+ * For SVM, returns all available fee payer addresses.
414
+ *
415
+ * @param _ - The network identifier (unused for SVM)
416
+ * @returns Array of fee payer addresses
417
+ */
418
+ getSigners(_) {
419
+ return [...this.signer.getAddresses()];
420
+ }
421
+ /**
422
+ * Verifies a payment payload (V1).
423
+ *
424
+ * @param payload - The payment payload to verify
425
+ * @param requirements - The payment requirements
426
+ * @returns Promise resolving to verification response
427
+ */
428
+ async verify(payload, requirements) {
429
+ const requirementsV1 = requirements;
430
+ const payloadV1 = payload;
431
+ const exactSvmPayload = payload.payload;
432
+ if (payloadV1.scheme !== "exact" || requirements.scheme !== "exact") {
433
+ return {
434
+ isValid: false,
435
+ invalidReason: "unsupported_scheme",
436
+ payer: ""
437
+ };
438
+ }
439
+ if (payloadV1.network !== requirements.network) {
440
+ return {
441
+ isValid: false,
442
+ invalidReason: "network_mismatch",
443
+ payer: ""
444
+ };
445
+ }
446
+ if (!requirementsV1.extra?.feePayer || typeof requirementsV1.extra.feePayer !== "string") {
447
+ return {
448
+ isValid: false,
449
+ invalidReason: "invalid_exact_svm_payload_missing_fee_payer",
450
+ payer: ""
451
+ };
452
+ }
453
+ const signerAddresses = this.signer.getAddresses().map((addr) => addr.toString());
454
+ if (!signerAddresses.includes(requirementsV1.extra.feePayer)) {
455
+ return {
456
+ isValid: false,
457
+ invalidReason: "fee_payer_not_managed_by_facilitator",
458
+ payer: ""
459
+ };
460
+ }
461
+ let transaction;
462
+ try {
463
+ transaction = decodeTransactionFromPayload(exactSvmPayload);
464
+ } catch {
465
+ return {
466
+ isValid: false,
467
+ invalidReason: "invalid_exact_svm_payload_transaction_could_not_be_decoded",
468
+ payer: ""
469
+ };
470
+ }
471
+ const compiled = (0, import_kit3.getCompiledTransactionMessageDecoder)().decode(transaction.messageBytes);
472
+ const decompiled = (0, import_kit3.decompileTransactionMessage)(compiled);
473
+ const instructions = decompiled.instructions ?? [];
474
+ if (instructions.length !== 3) {
475
+ return {
476
+ isValid: false,
477
+ invalidReason: "invalid_exact_svm_payload_transaction_instructions_length",
478
+ payer: ""
479
+ };
480
+ }
481
+ try {
482
+ this.verifyComputeLimitInstruction(instructions[0]);
483
+ this.verifyComputePriceInstruction(instructions[1]);
484
+ } catch (error) {
485
+ const errorMessage = error instanceof Error ? error.message : String(error);
486
+ return {
487
+ isValid: false,
488
+ invalidReason: errorMessage,
489
+ payer: ""
490
+ };
491
+ }
492
+ const payer = getTokenPayerFromTransaction(transaction);
493
+ if (!payer) {
494
+ return {
495
+ isValid: false,
496
+ invalidReason: "invalid_exact_svm_payload_no_transfer_instruction",
497
+ payer: ""
498
+ };
499
+ }
500
+ const transferIx = instructions[2];
501
+ const programAddress = transferIx.programAddress.toString();
502
+ if (programAddress !== import_token3.TOKEN_PROGRAM_ADDRESS.toString() && programAddress !== import_token_20223.TOKEN_2022_PROGRAM_ADDRESS.toString()) {
503
+ return {
504
+ isValid: false,
505
+ invalidReason: "invalid_exact_svm_payload_no_transfer_instruction",
506
+ payer
507
+ };
508
+ }
509
+ let parsedTransfer;
510
+ try {
511
+ if (programAddress === import_token3.TOKEN_PROGRAM_ADDRESS.toString()) {
512
+ parsedTransfer = (0, import_token3.parseTransferCheckedInstruction)(transferIx);
513
+ } else {
514
+ parsedTransfer = (0, import_token_20223.parseTransferCheckedInstruction)(transferIx);
515
+ }
516
+ } catch {
517
+ return {
518
+ isValid: false,
519
+ invalidReason: "invalid_exact_svm_payload_no_transfer_instruction",
520
+ payer
521
+ };
522
+ }
523
+ const authorityAddress = parsedTransfer.accounts.authority.address.toString();
524
+ if (signerAddresses.includes(authorityAddress)) {
525
+ return {
526
+ isValid: false,
527
+ invalidReason: "invalid_exact_svm_payload_transaction_fee_payer_transferring_funds",
528
+ payer
529
+ };
530
+ }
531
+ const mintAddress = parsedTransfer.accounts.mint.address.toString();
532
+ if (mintAddress !== requirements.asset) {
533
+ return {
534
+ isValid: false,
535
+ invalidReason: "invalid_exact_svm_payload_mint_mismatch",
536
+ payer
537
+ };
538
+ }
539
+ const destATA = parsedTransfer.accounts.destination.address.toString();
540
+ try {
541
+ const [expectedDestATA] = await (0, import_token_20223.findAssociatedTokenPda)({
542
+ mint: requirements.asset,
543
+ owner: requirements.payTo,
544
+ tokenProgram: programAddress === import_token3.TOKEN_PROGRAM_ADDRESS.toString() ? import_token3.TOKEN_PROGRAM_ADDRESS : import_token_20223.TOKEN_2022_PROGRAM_ADDRESS
545
+ });
546
+ if (destATA !== expectedDestATA.toString()) {
547
+ return {
548
+ isValid: false,
549
+ invalidReason: "invalid_exact_svm_payload_recipient_mismatch",
550
+ payer
551
+ };
552
+ }
553
+ } catch {
554
+ return {
555
+ isValid: false,
556
+ invalidReason: "invalid_exact_svm_payload_recipient_mismatch",
557
+ payer
558
+ };
559
+ }
560
+ const amount = parsedTransfer.data.amount;
561
+ if (amount < BigInt(requirementsV1.maxAmountRequired)) {
562
+ return {
563
+ isValid: false,
564
+ invalidReason: "invalid_exact_svm_payload_amount_insufficient",
565
+ payer
566
+ };
567
+ }
568
+ try {
569
+ const feePayer = requirementsV1.extra.feePayer;
570
+ const fullySignedTransaction = await this.signer.signTransaction(
571
+ exactSvmPayload.transaction,
572
+ feePayer,
573
+ requirements.network
574
+ );
575
+ await this.signer.simulateTransaction(fullySignedTransaction, requirements.network);
576
+ } catch (error) {
577
+ const errorMessage = error instanceof Error ? error.message : String(error);
578
+ return {
579
+ isValid: false,
580
+ invalidReason: `transaction_simulation_failed: ${errorMessage}`,
581
+ payer
582
+ };
583
+ }
584
+ return {
585
+ isValid: true,
586
+ invalidReason: void 0,
587
+ payer
588
+ };
589
+ }
590
+ /**
591
+ * Settles a payment by submitting the transaction (V1).
592
+ * Ensures the correct signer is used based on the feePayer specified in requirements.
593
+ *
594
+ * @param payload - The payment payload to settle
595
+ * @param requirements - The payment requirements
596
+ * @returns Promise resolving to settlement response
597
+ */
598
+ async settle(payload, requirements) {
599
+ const payloadV1 = payload;
600
+ const exactSvmPayload = payload.payload;
601
+ const valid = await this.verify(payload, requirements);
602
+ if (!valid.isValid) {
603
+ return {
604
+ success: false,
605
+ network: payloadV1.network,
606
+ transaction: "",
607
+ errorReason: valid.invalidReason ?? "verification_failed",
608
+ payer: valid.payer || ""
609
+ };
610
+ }
611
+ try {
612
+ const feePayer = requirements.extra.feePayer;
613
+ const fullySignedTransaction = await this.signer.signTransaction(
614
+ exactSvmPayload.transaction,
615
+ feePayer,
616
+ requirements.network
617
+ );
618
+ const signature = await this.signer.sendTransaction(
619
+ fullySignedTransaction,
620
+ requirements.network
621
+ );
622
+ await this.signer.confirmTransaction(signature, requirements.network);
623
+ return {
624
+ success: true,
625
+ transaction: signature,
626
+ network: payloadV1.network,
627
+ payer: valid.payer
628
+ };
629
+ } catch (error) {
630
+ console.error("Failed to settle transaction:", error);
631
+ return {
632
+ success: false,
633
+ errorReason: "transaction_failed",
634
+ transaction: "",
635
+ network: payloadV1.network,
636
+ payer: valid.payer || ""
637
+ };
638
+ }
639
+ }
640
+ /**
641
+ * Verify compute limit instruction
642
+ *
643
+ * @param instruction - The compute limit instruction
644
+ * @param instruction.programAddress - Program address
645
+ * @param instruction.data - Instruction data bytes
646
+ */
647
+ verifyComputeLimitInstruction(instruction) {
648
+ const programAddress = instruction.programAddress.toString();
649
+ if (programAddress !== import_compute_budget2.COMPUTE_BUDGET_PROGRAM_ADDRESS.toString() || !instruction.data || instruction.data[0] !== 2) {
650
+ throw new Error(
651
+ "invalid_exact_svm_payload_transaction_instructions_compute_limit_instruction"
652
+ );
653
+ }
654
+ try {
655
+ (0, import_compute_budget2.parseSetComputeUnitLimitInstruction)(instruction);
656
+ } catch {
657
+ throw new Error(
658
+ "invalid_exact_svm_payload_transaction_instructions_compute_limit_instruction"
659
+ );
660
+ }
661
+ }
662
+ /**
663
+ * Verify compute price instruction
664
+ *
665
+ * @param instruction - The compute price instruction
666
+ * @param instruction.programAddress - Program address
667
+ * @param instruction.data - Instruction data bytes
668
+ */
669
+ verifyComputePriceInstruction(instruction) {
670
+ const programAddress = instruction.programAddress.toString();
671
+ if (programAddress !== import_compute_budget2.COMPUTE_BUDGET_PROGRAM_ADDRESS.toString() || !instruction.data || instruction.data[0] !== 3) {
672
+ throw new Error(
673
+ "invalid_exact_svm_payload_transaction_instructions_compute_price_instruction"
674
+ );
675
+ }
676
+ try {
677
+ const parsedInstruction = (0, import_compute_budget2.parseSetComputeUnitPriceInstruction)(instruction);
678
+ if (parsedInstruction.microLamports > BigInt(MAX_COMPUTE_UNIT_PRICE_MICROLAMPORTS)) {
679
+ throw new Error(
680
+ "invalid_exact_svm_payload_transaction_instructions_compute_price_instruction_too_high"
681
+ );
682
+ }
683
+ } catch (error) {
684
+ if (error instanceof Error && error.message.includes("too_high")) {
685
+ throw error;
686
+ }
687
+ throw new Error(
688
+ "invalid_exact_svm_payload_transaction_instructions_compute_price_instruction"
689
+ );
690
+ }
691
+ }
692
+ };
693
+
694
+ // src/exact/v1/client/scheme.ts
695
+ var import_compute_budget3 = require("@solana-program/compute-budget");
696
+ var import_token4 = require("@solana-program/token");
697
+ var import_token_20224 = require("@solana-program/token-2022");
698
+ var import_kit4 = require("@solana/kit");
699
+
700
+ // src/v1/index.ts
701
+ var NETWORKS = ["solana", "solana-devnet", "solana-testnet"];
702
+
703
+ // src/exact/facilitator/register.ts
704
+ function registerExactSvmScheme(facilitator, config) {
705
+ facilitator.register(config.networks, new ExactSvmScheme(config.signer));
706
+ facilitator.registerV1(NETWORKS, new ExactSvmSchemeV1(config.signer));
707
+ return facilitator;
708
+ }
709
+ // Annotate the CommonJS export names for ESM import in node:
710
+ 0 && (module.exports = {
711
+ ExactSvmScheme,
712
+ registerExactSvmScheme
713
+ });
714
+ //# sourceMappingURL=index.js.map