@agent-score/commerce 1.2.0 → 1.3.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.
- package/README.md +26 -11
- package/dist/{_response-RpEB7-vl.d.ts → _response-C2yFQoIA.d.ts} +1 -1
- package/dist/{_response-DS-LR590.d.mts → _response-DpB-cm2c.d.mts} +1 -1
- package/dist/{agent_instructions-d3UWTdam.d.mts → agent_instructions-DiMSGkdm.d.mts} +10 -6
- package/dist/{agent_instructions-d3UWTdam.d.ts → agent_instructions-DiMSGkdm.d.ts} +10 -6
- package/dist/challenge/index.d.mts +18 -9
- package/dist/challenge/index.d.ts +18 -9
- package/dist/challenge/index.js +25 -24
- package/dist/challenge/index.js.map +1 -1
- package/dist/challenge/index.mjs +25 -24
- package/dist/challenge/index.mjs.map +1 -1
- package/dist/core.js +1 -1
- package/dist/core.js.map +1 -1
- package/dist/core.mjs +1 -1
- package/dist/core.mjs.map +1 -1
- package/dist/discovery/index.d.mts +130 -6
- package/dist/discovery/index.d.ts +130 -6
- package/dist/discovery/index.js +75 -59
- package/dist/discovery/index.js.map +1 -1
- package/dist/discovery/index.mjs +70 -58
- package/dist/discovery/index.mjs.map +1 -1
- package/dist/identity/express.d.mts +2 -2
- package/dist/identity/express.d.ts +2 -2
- package/dist/identity/express.js +48 -25
- package/dist/identity/express.js.map +1 -1
- package/dist/identity/express.mjs +48 -25
- package/dist/identity/express.mjs.map +1 -1
- package/dist/identity/fastify.d.mts +2 -2
- package/dist/identity/fastify.d.ts +2 -2
- package/dist/identity/fastify.js +48 -25
- package/dist/identity/fastify.js.map +1 -1
- package/dist/identity/fastify.mjs +48 -25
- package/dist/identity/fastify.mjs.map +1 -1
- package/dist/identity/hono.d.mts +2 -2
- package/dist/identity/hono.d.ts +2 -2
- package/dist/identity/hono.js +48 -25
- package/dist/identity/hono.js.map +1 -1
- package/dist/identity/hono.mjs +48 -25
- package/dist/identity/hono.mjs.map +1 -1
- package/dist/identity/nextjs.d.mts +2 -2
- package/dist/identity/nextjs.d.ts +2 -2
- package/dist/identity/nextjs.js +48 -25
- package/dist/identity/nextjs.js.map +1 -1
- package/dist/identity/nextjs.mjs +48 -25
- package/dist/identity/nextjs.mjs.map +1 -1
- package/dist/identity/web.d.mts +2 -2
- package/dist/identity/web.d.ts +2 -2
- package/dist/identity/web.js +48 -25
- package/dist/identity/web.js.map +1 -1
- package/dist/identity/web.mjs +48 -25
- package/dist/identity/web.mjs.map +1 -1
- package/dist/index.d.mts +12 -12
- package/dist/index.d.ts +12 -12
- package/dist/index.js +47 -24
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +47 -24
- package/dist/index.mjs.map +1 -1
- package/dist/payment/index.d.mts +136 -49
- package/dist/payment/index.d.ts +136 -49
- package/dist/payment/index.js +161 -73
- package/dist/payment/index.js.map +1 -1
- package/dist/payment/index.mjs +160 -72
- package/dist/payment/index.mjs.map +1 -1
- package/dist/{signer-Cvdwn6Cs.d.mts → signer-kCAJUZwp.d.mts} +10 -12
- package/dist/{signer-Cvdwn6Cs.d.ts → signer-kCAJUZwp.d.ts} +10 -12
- package/dist/stripe-multichain/index.d.mts +2 -2
- package/dist/stripe-multichain/index.d.ts +2 -2
- package/dist/stripe-multichain/index.js.map +1 -1
- package/dist/stripe-multichain/index.mjs.map +1 -1
- package/package.json +13 -4
package/dist/payment/index.js
CHANGED
|
@@ -23,12 +23,12 @@ __export(payment_exports, {
|
|
|
23
23
|
SETTLEMENT_OVERRIDES_HEADER: () => SETTLEMENT_OVERRIDES_HEADER,
|
|
24
24
|
USDC: () => USDC,
|
|
25
25
|
X402_SUPPORTED_BASE_NETWORKS: () => X402_SUPPORTED_BASE_NETWORKS,
|
|
26
|
-
X402_SUPPORTED_SVM_NETWORKS: () => X402_SUPPORTED_SVM_NETWORKS,
|
|
27
26
|
aliasAmountFields: () => aliasAmountFields,
|
|
28
27
|
buildIdempotencyKey: () => buildIdempotencyKey,
|
|
29
28
|
buildPaymentDirective: () => buildPaymentDirective,
|
|
30
29
|
buildPaymentHeaders: () => buildPaymentHeaders,
|
|
31
30
|
buildPaymentRequestBlob: () => buildPaymentRequestBlob,
|
|
31
|
+
classifyX402SettleResult: () => classifyX402SettleResult,
|
|
32
32
|
createMppxServer: () => createMppxServer,
|
|
33
33
|
createX402Server: () => createX402Server,
|
|
34
34
|
dispatchSettlementByNetwork: () => dispatchSettlementByNetwork,
|
|
@@ -141,15 +141,15 @@ var rails = {
|
|
|
141
141
|
decimals: USDC.base.sepolia.decimals,
|
|
142
142
|
asset: USDC.base.sepolia.address
|
|
143
143
|
},
|
|
144
|
-
"
|
|
145
|
-
method: "
|
|
144
|
+
"mpp-solana-mainnet": {
|
|
145
|
+
method: "solana",
|
|
146
146
|
network: networks.solana.mainnet.caip2,
|
|
147
147
|
currency: USDC.solana.mainnet.mint,
|
|
148
148
|
decimals: USDC.solana.mainnet.decimals,
|
|
149
149
|
asset: USDC.solana.mainnet.mint
|
|
150
150
|
},
|
|
151
|
-
"
|
|
152
|
-
method: "
|
|
151
|
+
"mpp-solana-devnet": {
|
|
152
|
+
method: "solana",
|
|
153
153
|
network: networks.solana.devnet.caip2,
|
|
154
154
|
currency: USDC.solana.devnet.mint,
|
|
155
155
|
decimals: USDC.solana.devnet.decimals,
|
|
@@ -219,11 +219,6 @@ function registerX402SchemesV1V2(server, network, scheme) {
|
|
|
219
219
|
|
|
220
220
|
// src/payment/x402_server.ts
|
|
221
221
|
async function createX402Server(opts = {}) {
|
|
222
|
-
for (const rail of opts.rails ?? []) {
|
|
223
|
-
if (rail.startsWith("x402-solana") && rail.endsWith("-upto")) {
|
|
224
|
-
throw new Error(`Rail "${rail}" not supported \u2014 @x402/svm does not ship an upto scheme yet (EVM-only).`);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
222
|
const x402Core = await dynamicImport("@x402/core/server") ?? null;
|
|
228
223
|
if (!x402Core) {
|
|
229
224
|
throw new Error(
|
|
@@ -247,7 +242,6 @@ async function createX402Server(opts = {}) {
|
|
|
247
242
|
const server = new x402Core.x402ResourceServer(facilitator);
|
|
248
243
|
let evmExactModule = null;
|
|
249
244
|
let evmUptoModule = null;
|
|
250
|
-
let svmModule = null;
|
|
251
245
|
for (const rail of opts.rails ?? []) {
|
|
252
246
|
const isUpto = rail.endsWith("-upto");
|
|
253
247
|
if (rail.startsWith("x402-base")) {
|
|
@@ -266,13 +260,6 @@ async function createX402Server(opts = {}) {
|
|
|
266
260
|
}
|
|
267
261
|
registerX402SchemesV1V2(server, network, new evmExactModule.ExactEvmScheme());
|
|
268
262
|
}
|
|
269
|
-
} else if (rail.startsWith("x402-solana")) {
|
|
270
|
-
svmModule ??= await dynamicImport("@x402/svm/exact/server");
|
|
271
|
-
if (!svmModule?.ExactSvmScheme) {
|
|
272
|
-
throw new Error("@x402/svm not installed \u2014 `npm install @x402/svm` for x402 solana rails.");
|
|
273
|
-
}
|
|
274
|
-
const network = rail === "x402-solana-mainnet" ? networks.solana.mainnet.caip2 : networks.solana.devnet.caip2;
|
|
275
|
-
registerX402SchemesV1V2(server, network, new svmModule.ExactSvmScheme());
|
|
276
263
|
}
|
|
277
264
|
}
|
|
278
265
|
for (const { network, scheme } of opts.schemes ?? []) {
|
|
@@ -301,9 +288,60 @@ async function dynamicImport(moduleName) {
|
|
|
301
288
|
}
|
|
302
289
|
|
|
303
290
|
// src/payment/x402_settle.ts
|
|
291
|
+
function classifyX402SettleResult(result) {
|
|
292
|
+
if (result.success) return null;
|
|
293
|
+
switch (result.phase) {
|
|
294
|
+
case "no_requirements":
|
|
295
|
+
return {
|
|
296
|
+
status: 500,
|
|
297
|
+
code: "payment_internal_error",
|
|
298
|
+
message: "Failed to build x402 payment requirements for this configuration",
|
|
299
|
+
nextSteps: {
|
|
300
|
+
action: "contact_support",
|
|
301
|
+
user_message: "The merchant could not produce a payment challenge for this request. Try again later or contact support."
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
case "verify_failed":
|
|
305
|
+
return {
|
|
306
|
+
status: 400,
|
|
307
|
+
code: "payment_proof_invalid",
|
|
308
|
+
message: "Payment credential failed verification; regenerate from a fresh 402 challenge",
|
|
309
|
+
nextSteps: {
|
|
310
|
+
action: "regenerate_payment_credential",
|
|
311
|
+
user_message: "The payment credential was rejected at verify time. Discard it, fetch a fresh 402 challenge, and re-sign."
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
case "facilitator_error":
|
|
315
|
+
return {
|
|
316
|
+
status: 503,
|
|
317
|
+
code: "payment_provider_unavailable",
|
|
318
|
+
message: "Payment provider could not process this network configuration",
|
|
319
|
+
nextSteps: {
|
|
320
|
+
action: "try_different_rail",
|
|
321
|
+
user_message: "This rail is currently unavailable. Pick a different rail from the 402 challenge and retry."
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
case "settle_failed":
|
|
325
|
+
return {
|
|
326
|
+
status: 503,
|
|
327
|
+
code: "payment_provider_unavailable",
|
|
328
|
+
message: "Payment credential verified but on-chain settlement failed",
|
|
329
|
+
nextSteps: {
|
|
330
|
+
action: "retry_or_swap_method",
|
|
331
|
+
retry_after_seconds: 10,
|
|
332
|
+
user_message: "Transient settlement error. Retry in a few seconds, or pick a different rail from the 402 challenge."
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
}
|
|
304
337
|
async function processX402Settle(input) {
|
|
305
338
|
const server = input.x402Server;
|
|
306
|
-
|
|
339
|
+
let builtRequirements;
|
|
340
|
+
try {
|
|
341
|
+
builtRequirements = await server.buildPaymentRequirements(input.resourceConfig);
|
|
342
|
+
} catch (err) {
|
|
343
|
+
return { success: false, phase: "facilitator_error", step: "build_requirements", error: err };
|
|
344
|
+
}
|
|
307
345
|
const matchedRequirement = builtRequirements[0];
|
|
308
346
|
if (!matchedRequirement) {
|
|
309
347
|
return { success: false, phase: "no_requirements", reason: "x402Server.buildPaymentRequirements returned empty" };
|
|
@@ -312,13 +350,23 @@ async function processX402Settle(input) {
|
|
|
312
350
|
const path = new URL(input.resourceMeta.url).pathname;
|
|
313
351
|
return { method: "POST", adapter: { getPath: () => path }, routePattern: path };
|
|
314
352
|
})();
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
input.
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
353
|
+
let enrichedExt;
|
|
354
|
+
try {
|
|
355
|
+
enrichedExt = input.extension !== void 0 ? server.enrichExtensions(input.extension, transportContext) : void 0;
|
|
356
|
+
} catch (err) {
|
|
357
|
+
return { success: false, phase: "facilitator_error", step: "enrich_extensions", error: err };
|
|
358
|
+
}
|
|
359
|
+
let verifyResult;
|
|
360
|
+
try {
|
|
361
|
+
verifyResult = await server.processPaymentRequest(
|
|
362
|
+
input.payload,
|
|
363
|
+
input.resourceConfig,
|
|
364
|
+
input.resourceMeta,
|
|
365
|
+
enrichedExt
|
|
366
|
+
);
|
|
367
|
+
} catch (err) {
|
|
368
|
+
return { success: false, phase: "facilitator_error", step: "process_payment_request", error: err };
|
|
369
|
+
}
|
|
322
370
|
if (!verifyResult.success) {
|
|
323
371
|
return { success: false, phase: "verify_failed", verifyResult };
|
|
324
372
|
}
|
|
@@ -342,30 +390,15 @@ var X402_SUPPORTED_BASE_NETWORKS = /* @__PURE__ */ new Set([
|
|
|
342
390
|
networks.base.mainnet.caip2,
|
|
343
391
|
networks.base.sepolia.caip2
|
|
344
392
|
]);
|
|
345
|
-
var X402_SUPPORTED_SVM_NETWORKS = /* @__PURE__ */ new Set([
|
|
346
|
-
networks.solana.mainnet.caip2,
|
|
347
|
-
networks.solana.devnet.caip2
|
|
348
|
-
]);
|
|
349
393
|
function validateX402NetworkConfig(input) {
|
|
350
394
|
if (!X402_SUPPORTED_BASE_NETWORKS.has(input.baseNetwork)) {
|
|
351
395
|
throw new Error(
|
|
352
396
|
`X402_BASE_NETWORK=${input.baseNetwork} is not supported. Use one of: ${[...X402_SUPPORTED_BASE_NETWORKS].join(", ")}`
|
|
353
397
|
);
|
|
354
398
|
}
|
|
355
|
-
if (!X402_SUPPORTED_SVM_NETWORKS.has(input.svmNetwork)) {
|
|
356
|
-
throw new Error(
|
|
357
|
-
`X402_SVM_NETWORK=${input.svmNetwork} is not supported. Use one of: ${[...X402_SUPPORTED_SVM_NETWORKS].join(", ")}`
|
|
358
|
-
);
|
|
359
|
-
}
|
|
360
|
-
if (input.baseNetwork === input.svmNetwork) {
|
|
361
|
-
throw new Error(
|
|
362
|
-
`X402_BASE_NETWORK and X402_SVM_NETWORK must be different (both set to ${input.baseNetwork}).`
|
|
363
|
-
);
|
|
364
|
-
}
|
|
365
399
|
}
|
|
366
400
|
var EVM_ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;
|
|
367
|
-
var
|
|
368
|
-
var REGENERATE_WARNING = "If you're trying to pay with Tempo USDC, use `tempo request` (sends Authorization: Payment), not a manual X-Payment header. Do NOT use `tempo wallet transfer` \u2014 that sends USDC on-chain but will not complete the MPP handshake. For x402 on Base/Solana, use `agentscore-pay pay` so the X-Payment credential is signed and submitted; bare wallet transfers do not complete the handshake.";
|
|
401
|
+
var REGENERATE_WARNING = "Use `agentscore-pay pay --chain base` (or `tempo request` for Tempo USDC) so the credential is signed and submitted via the protocol handshake. Do NOT use `tempo wallet transfer` \u2014 that sends USDC on-chain but does not complete the handshake.";
|
|
369
402
|
function regenerateBody(message, userMessage) {
|
|
370
403
|
return {
|
|
371
404
|
error: { code: "payment_proof_invalid", message },
|
|
@@ -403,18 +436,27 @@ async function verifyX402Request(input) {
|
|
|
403
436
|
}
|
|
404
437
|
const signedNetwork = payload.accepted?.network;
|
|
405
438
|
const signedPayTo = payload.accepted?.payTo;
|
|
406
|
-
if (!signedNetwork || signedNetwork !== input.
|
|
439
|
+
if (!signedNetwork || signedNetwork !== input.acceptedNetwork) {
|
|
440
|
+
if (signedNetwork && signedNetwork.toLowerCase().startsWith("solana:")) {
|
|
441
|
+
return {
|
|
442
|
+
ok: false,
|
|
443
|
+
status: 400,
|
|
444
|
+
body: regenerateBody(
|
|
445
|
+
`x402 on ${signedNetwork} is not accepted; Solana payments must use the \`solana/charge\` rail advertised in the 402 challenge. This server accepts x402 on ${input.acceptedNetwork} only.`,
|
|
446
|
+
"Solana payments are not accepted over x402 at this merchant. Pick the `solana/charge` rail from the 402 challenge and re-sign."
|
|
447
|
+
)
|
|
448
|
+
};
|
|
449
|
+
}
|
|
407
450
|
return {
|
|
408
451
|
ok: false,
|
|
409
452
|
status: 400,
|
|
410
453
|
body: regenerateBody(
|
|
411
|
-
`Unsupported x402 network ${signedNetwork ?? "<missing>"}; this server accepts ${input.
|
|
412
|
-
"The credential signed for an unsupported network. Pick
|
|
454
|
+
`Unsupported x402 network ${signedNetwork ?? "<missing>"}; this server accepts ${input.acceptedNetwork}.`,
|
|
455
|
+
"The credential signed for an unsupported network. Pick the accepted network from the 402 challenge and re-sign."
|
|
413
456
|
)
|
|
414
457
|
};
|
|
415
458
|
}
|
|
416
|
-
const
|
|
417
|
-
const addressShapeOk = isSolana ? typeof signedPayTo === "string" && SOLANA_ADDRESS_RE.test(signedPayTo) : typeof signedPayTo === "string" && EVM_ADDRESS_RE.test(signedPayTo);
|
|
459
|
+
const addressShapeOk = typeof signedPayTo === "string" && EVM_ADDRESS_RE.test(signedPayTo);
|
|
418
460
|
if (!signedPayTo || !addressShapeOk) {
|
|
419
461
|
return {
|
|
420
462
|
ok: false,
|
|
@@ -435,7 +477,7 @@ async function verifyX402Request(input) {
|
|
|
435
477
|
)
|
|
436
478
|
};
|
|
437
479
|
}
|
|
438
|
-
return { ok: true, payload, signedNetwork, signedPayTo
|
|
480
|
+
return { ok: true, payload, signedNetwork, signedPayTo };
|
|
439
481
|
}
|
|
440
482
|
|
|
441
483
|
// src/stripe-multichain/mppx_stripe.ts
|
|
@@ -494,6 +536,29 @@ async function createMppxServer(opts) {
|
|
|
494
536
|
})
|
|
495
537
|
);
|
|
496
538
|
}
|
|
539
|
+
if (opts.rails?.solana) {
|
|
540
|
+
const solanaMpp = await dynamicImport2("@solana/mpp/server");
|
|
541
|
+
if (!solanaMpp?.charge) {
|
|
542
|
+
throw new Error(
|
|
543
|
+
"@solana/mpp not installed \u2014 `npm install @solana/mpp @solana/kit` to use the solana rail."
|
|
544
|
+
);
|
|
545
|
+
}
|
|
546
|
+
const s = opts.rails.solana;
|
|
547
|
+
const network = s.network ?? "mainnet-beta";
|
|
548
|
+
const defaultMint = network === "mainnet-beta" ? USDC.solana.mainnet.mint : USDC.solana.devnet.mint;
|
|
549
|
+
const defaultDecimals = network === "mainnet-beta" ? USDC.solana.mainnet.decimals : USDC.solana.devnet.decimals;
|
|
550
|
+
methods.push(
|
|
551
|
+
solanaMpp.charge({
|
|
552
|
+
recipient: s.recipient,
|
|
553
|
+
currency: s.currency ?? defaultMint,
|
|
554
|
+
decimals: s.decimals ?? defaultDecimals,
|
|
555
|
+
network,
|
|
556
|
+
...s.rpcUrl ? { rpcUrl: s.rpcUrl } : {},
|
|
557
|
+
...s.signer ? { signer: s.signer } : {},
|
|
558
|
+
...s.tokenProgram ? { tokenProgram: s.tokenProgram } : {}
|
|
559
|
+
})
|
|
560
|
+
);
|
|
561
|
+
}
|
|
497
562
|
if (opts.rails?.stripe) {
|
|
498
563
|
const stripeMethod = await createMppxStripe(opts.rails.stripe);
|
|
499
564
|
methods.push(stripeMethod);
|
|
@@ -601,6 +666,44 @@ function clampKey(key) {
|
|
|
601
666
|
}
|
|
602
667
|
|
|
603
668
|
// src/signer.ts
|
|
669
|
+
var TOKEN_PROGRAM = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
|
|
670
|
+
var TOKEN_2022_PROGRAM = "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb";
|
|
671
|
+
var TRANSFER_CHECKED_DISCRIMINATOR = 12;
|
|
672
|
+
async function extractSolanaSignerFromCredential(credential) {
|
|
673
|
+
const payload = credential.payload;
|
|
674
|
+
if (!payload?.transaction || payload.type !== "transaction") return null;
|
|
675
|
+
const moduleName = "@solana/kit";
|
|
676
|
+
const kit = await import(moduleName).catch(() => null);
|
|
677
|
+
if (!kit?.getBase64Codec || !kit.getTransactionDecoder || !kit.getCompiledTransactionMessageDecoder) {
|
|
678
|
+
return null;
|
|
679
|
+
}
|
|
680
|
+
try {
|
|
681
|
+
const txBytes = kit.getBase64Codec().encode(payload.transaction);
|
|
682
|
+
const decoded = kit.getTransactionDecoder().decode(txBytes);
|
|
683
|
+
const message = kit.getCompiledTransactionMessageDecoder().decode(decoded.messageBytes);
|
|
684
|
+
for (const ix of message.instructions) {
|
|
685
|
+
const programId = message.staticAccounts[ix.programAddressIndex];
|
|
686
|
+
if (programId !== TOKEN_PROGRAM && programId !== TOKEN_2022_PROGRAM) continue;
|
|
687
|
+
const data = ix.data;
|
|
688
|
+
if (!data || data.length === 0 || data[0] !== TRANSFER_CHECKED_DISCRIMINATOR) continue;
|
|
689
|
+
const accountIndices = ix.accountIndices ?? [];
|
|
690
|
+
const authorityIndex = accountIndices[3];
|
|
691
|
+
if (authorityIndex === void 0) continue;
|
|
692
|
+
if (authorityIndex >= message.staticAccounts.length) {
|
|
693
|
+
console.warn(
|
|
694
|
+
"[gate] Solana TransferChecked authority resolves through an address lookup table; signer-match recovery requires the static-account form. Skipping."
|
|
695
|
+
);
|
|
696
|
+
continue;
|
|
697
|
+
}
|
|
698
|
+
const authority = message.staticAccounts[authorityIndex];
|
|
699
|
+
if (authority) return authority;
|
|
700
|
+
}
|
|
701
|
+
return null;
|
|
702
|
+
} catch (err) {
|
|
703
|
+
console.warn("[gate] Solana credential decode failed:", err instanceof Error ? err.message : err);
|
|
704
|
+
return null;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
604
707
|
async function extractPaymentSigner(request, x402PaymentHeader) {
|
|
605
708
|
const authHeader = request.headers.get("authorization");
|
|
606
709
|
if (authHeader) {
|
|
@@ -610,8 +713,12 @@ async function extractPaymentSigner(request, x402PaymentHeader) {
|
|
|
610
713
|
if (mppx?.Credential?.extractPaymentScheme(authHeader)) {
|
|
611
714
|
const credential = mppx.Credential.fromRequest(request);
|
|
612
715
|
const source = credential.source;
|
|
613
|
-
const
|
|
614
|
-
if (
|
|
716
|
+
const evmMatch = source?.match(/^did:pkh:eip155:\d+:(0x[0-9a-fA-F]{40})$/);
|
|
717
|
+
if (evmMatch) return { address: evmMatch[1].toLowerCase(), network: "evm" };
|
|
718
|
+
const solMatch = source?.match(/^did:pkh:solana:[1-9A-HJ-NP-Za-km-z]{32,44}:([1-9A-HJ-NP-Za-km-z]{32,44})$/);
|
|
719
|
+
if (solMatch) return { address: solMatch[1], network: "solana" };
|
|
720
|
+
const solanaFromTx = await extractSolanaSignerFromCredential(credential);
|
|
721
|
+
if (solanaFromTx) return { address: solanaFromTx, network: "solana" };
|
|
615
722
|
}
|
|
616
723
|
} catch (err) {
|
|
617
724
|
console.warn("[gate] MPP signer extraction failed:", err instanceof Error ? err.message : err);
|
|
@@ -621,28 +728,9 @@ async function extractPaymentSigner(request, x402PaymentHeader) {
|
|
|
621
728
|
try {
|
|
622
729
|
const decoded = atob(x402PaymentHeader);
|
|
623
730
|
const parsed = JSON.parse(decoded);
|
|
624
|
-
const
|
|
625
|
-
if (
|
|
626
|
-
|
|
627
|
-
if (typeof from === "string" && /^0x[0-9a-fA-F]{40}$/.test(from)) {
|
|
628
|
-
return { address: from.toLowerCase(), network: "evm" };
|
|
629
|
-
}
|
|
630
|
-
} else if (network.startsWith("solana:")) {
|
|
631
|
-
const transaction = parsed?.payload?.transaction;
|
|
632
|
-
if (typeof transaction === "string") {
|
|
633
|
-
const moduleName = "@x402/svm";
|
|
634
|
-
const svm = await import(moduleName).catch(() => null);
|
|
635
|
-
if (svm?.decodeTransactionFromPayload && svm.getTokenPayerFromTransaction) {
|
|
636
|
-
const tx = svm.decodeTransactionFromPayload({ transaction });
|
|
637
|
-
const payer = svm.getTokenPayerFromTransaction(tx);
|
|
638
|
-
if (typeof payer === "string" && payer.length > 0) return { address: payer, network: "solana" };
|
|
639
|
-
}
|
|
640
|
-
}
|
|
641
|
-
} else {
|
|
642
|
-
const from = parsed?.payload?.authorization?.from;
|
|
643
|
-
if (typeof from === "string" && /^0x[0-9a-fA-F]{40}$/.test(from)) {
|
|
644
|
-
return { address: from.toLowerCase(), network: "evm" };
|
|
645
|
-
}
|
|
731
|
+
const from = parsed?.payload?.authorization?.from;
|
|
732
|
+
if (typeof from === "string" && /^0x[0-9a-fA-F]{40}$/.test(from)) {
|
|
733
|
+
return { address: from.toLowerCase(), network: "evm" };
|
|
646
734
|
}
|
|
647
735
|
} catch (err) {
|
|
648
736
|
console.warn("[gate] x402 signer extraction failed:", err instanceof Error ? err.message : err);
|
|
@@ -664,12 +752,12 @@ function settlementOverrideHeader(overrides) {
|
|
|
664
752
|
SETTLEMENT_OVERRIDES_HEADER,
|
|
665
753
|
USDC,
|
|
666
754
|
X402_SUPPORTED_BASE_NETWORKS,
|
|
667
|
-
X402_SUPPORTED_SVM_NETWORKS,
|
|
668
755
|
aliasAmountFields,
|
|
669
756
|
buildIdempotencyKey,
|
|
670
757
|
buildPaymentDirective,
|
|
671
758
|
buildPaymentHeaders,
|
|
672
759
|
buildPaymentRequestBlob,
|
|
760
|
+
classifyX402SettleResult,
|
|
673
761
|
createMppxServer,
|
|
674
762
|
createX402Server,
|
|
675
763
|
dispatchSettlementByNetwork,
|