@shroud-fi/x402 0.1.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/LICENSE +21 -0
- package/README.md +77 -0
- package/dist/cjs/client.d.ts +43 -0
- package/dist/cjs/client.d.ts.map +1 -0
- package/dist/cjs/client.js +199 -0
- package/dist/cjs/client.js.map +1 -0
- package/dist/cjs/constants.d.ts +16 -0
- package/dist/cjs/constants.d.ts.map +1 -0
- package/dist/cjs/constants.js +19 -0
- package/dist/cjs/constants.js.map +1 -0
- package/dist/cjs/errors.d.ts +61 -0
- package/dist/cjs/errors.d.ts.map +1 -0
- package/dist/cjs/errors.js +82 -0
- package/dist/cjs/errors.js.map +1 -0
- package/dist/cjs/facilitator.d.ts +50 -0
- package/dist/cjs/facilitator.d.ts.map +1 -0
- package/dist/cjs/facilitator.js +106 -0
- package/dist/cjs/facilitator.js.map +1 -0
- package/dist/cjs/index.d.ts +8 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +29 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/protocol.d.ts +117 -0
- package/dist/cjs/protocol.d.ts.map +1 -0
- package/dist/cjs/protocol.js +39 -0
- package/dist/cjs/protocol.js.map +1 -0
- package/dist/cjs/server.d.ts +49 -0
- package/dist/cjs/server.d.ts.map +1 -0
- package/dist/cjs/server.js +237 -0
- package/dist/cjs/server.js.map +1 -0
- package/dist/cjs/signing.d.ts +93 -0
- package/dist/cjs/signing.d.ts.map +1 -0
- package/dist/cjs/signing.js +170 -0
- package/dist/cjs/signing.js.map +1 -0
- package/dist/cjs/types.d.ts +93 -0
- package/dist/cjs/types.d.ts.map +1 -0
- package/dist/cjs/types.js +6 -0
- package/dist/cjs/types.js.map +1 -0
- package/dist/esm/client.d.ts +43 -0
- package/dist/esm/client.d.ts.map +1 -0
- package/dist/esm/client.js +196 -0
- package/dist/esm/client.js.map +1 -0
- package/dist/esm/constants.d.ts +16 -0
- package/dist/esm/constants.d.ts.map +1 -0
- package/dist/esm/constants.js +16 -0
- package/dist/esm/constants.js.map +1 -0
- package/dist/esm/errors.d.ts +61 -0
- package/dist/esm/errors.d.ts.map +1 -0
- package/dist/esm/errors.js +73 -0
- package/dist/esm/errors.js.map +1 -0
- package/dist/esm/facilitator.d.ts +50 -0
- package/dist/esm/facilitator.d.ts.map +1 -0
- package/dist/esm/facilitator.js +100 -0
- package/dist/esm/facilitator.js.map +1 -0
- package/dist/esm/index.d.ts +8 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +12 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/protocol.d.ts +117 -0
- package/dist/esm/protocol.d.ts.map +1 -0
- package/dist/esm/protocol.js +36 -0
- package/dist/esm/protocol.js.map +1 -0
- package/dist/esm/server.d.ts +49 -0
- package/dist/esm/server.d.ts.map +1 -0
- package/dist/esm/server.js +234 -0
- package/dist/esm/server.js.map +1 -0
- package/dist/esm/signing.d.ts +93 -0
- package/dist/esm/signing.d.ts.map +1 -0
- package/dist/esm/signing.js +131 -0
- package/dist/esm/signing.js.map +1 -0
- package/dist/esm/types.d.ts +93 -0
- package/dist/esm/types.d.ts.map +1 -0
- package/dist/esm/types.js +5 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/tsconfig.cjs.tsbuildinfo +1 -0
- package/dist/tsconfig.esm.tsbuildinfo +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +64 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Facilitator HTTP client.
|
|
4
|
+
*
|
|
5
|
+
* Two endpoints per the x402 spec:
|
|
6
|
+
* - POST /verify — facilitator validates signature + balance + simulation.
|
|
7
|
+
* - POST /settle — facilitator broadcasts the on-chain settlement tx.
|
|
8
|
+
*
|
|
9
|
+
* Privacy invariants:
|
|
10
|
+
* - We forward only the signed PaymentPayload + the PaymentRequirements. The
|
|
11
|
+
* facilitator never receives the recipient's main wallet — only the
|
|
12
|
+
* freshly derived stealth address (the `payTo` field of the requirements).
|
|
13
|
+
* - We never log request/response bodies. Tags are short strings only.
|
|
14
|
+
* - Auth token (if any) is attached as a Bearer header. We never log the
|
|
15
|
+
* full token; tests verify the header is set but redaction is the
|
|
16
|
+
* operator's responsibility upstream.
|
|
17
|
+
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.resolveFacilitator = resolveFacilitator;
|
|
20
|
+
exports.buildFacilitatorHeaders = buildFacilitatorHeaders;
|
|
21
|
+
exports.facilitatorVerify = facilitatorVerify;
|
|
22
|
+
exports.facilitatorSettle = facilitatorSettle;
|
|
23
|
+
const protocol_js_1 = require("./protocol.js");
|
|
24
|
+
const errors_js_1 = require("./errors.js");
|
|
25
|
+
/** Resolve the facilitator config, defaulting to PayAI free tier. */
|
|
26
|
+
function resolveFacilitator(config) {
|
|
27
|
+
if (config === undefined) {
|
|
28
|
+
return { url: protocol_js_1.PAYAI_FACILITATOR_URL };
|
|
29
|
+
}
|
|
30
|
+
return config;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Build standard headers for a facilitator request. When an Ed25519 auth
|
|
34
|
+
* token is configured, attach `Authorization: Bearer <token>`. Otherwise
|
|
35
|
+
* the request hits the PayAI free-tier endpoint (no auth required).
|
|
36
|
+
*/
|
|
37
|
+
function buildFacilitatorHeaders(config) {
|
|
38
|
+
const headers = {
|
|
39
|
+
'content-type': 'application/json',
|
|
40
|
+
accept: 'application/json',
|
|
41
|
+
};
|
|
42
|
+
if (config.ed25519AuthToken !== undefined) {
|
|
43
|
+
headers['authorization'] = `Bearer ${config.ed25519AuthToken}`;
|
|
44
|
+
}
|
|
45
|
+
return headers;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Call the facilitator's `/verify` endpoint. Returns the parsed verification
|
|
49
|
+
* result. Re-wraps every failure path as a tagged X402FacilitatorError so
|
|
50
|
+
* no upstream response body leaks through.
|
|
51
|
+
*/
|
|
52
|
+
async function facilitatorVerify(config, body, fetchImpl = fetch) {
|
|
53
|
+
const url = `${config.url.replace(/\/+$/, '')}/verify`;
|
|
54
|
+
let res;
|
|
55
|
+
try {
|
|
56
|
+
res = await fetchImpl(url, {
|
|
57
|
+
method: 'POST',
|
|
58
|
+
headers: buildFacilitatorHeaders(config),
|
|
59
|
+
body: JSON.stringify(body),
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
throw new errors_js_1.X402FacilitatorError('network');
|
|
64
|
+
}
|
|
65
|
+
if (!res.ok) {
|
|
66
|
+
throw new errors_js_1.X402FacilitatorError('verify');
|
|
67
|
+
}
|
|
68
|
+
let parsed;
|
|
69
|
+
try {
|
|
70
|
+
parsed = (await res.json());
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
throw new errors_js_1.X402FacilitatorError('verify');
|
|
74
|
+
}
|
|
75
|
+
return parsed;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Call the facilitator's `/settle` endpoint. Returns the parsed settle
|
|
79
|
+
* result (including the on-chain tx hash on success).
|
|
80
|
+
*/
|
|
81
|
+
async function facilitatorSettle(config, body, fetchImpl = fetch) {
|
|
82
|
+
const url = `${config.url.replace(/\/+$/, '')}/settle`;
|
|
83
|
+
let res;
|
|
84
|
+
try {
|
|
85
|
+
res = await fetchImpl(url, {
|
|
86
|
+
method: 'POST',
|
|
87
|
+
headers: buildFacilitatorHeaders(config),
|
|
88
|
+
body: JSON.stringify(body),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
throw new errors_js_1.X402FacilitatorError('network');
|
|
93
|
+
}
|
|
94
|
+
if (!res.ok) {
|
|
95
|
+
throw new errors_js_1.X402FacilitatorError('settle');
|
|
96
|
+
}
|
|
97
|
+
let parsed;
|
|
98
|
+
try {
|
|
99
|
+
parsed = (await res.json());
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
throw new errors_js_1.X402FacilitatorError('settle');
|
|
103
|
+
}
|
|
104
|
+
return parsed;
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=facilitator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facilitator.js","sourceRoot":"","sources":["../../src/facilitator.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;AAqBH,gDAOC;AAOD,0DAWC;AAOD,8CA0BC;AAMD,8CA0BC;AA5GD,+CAAkF;AAClF,2CAAmD;AAgBnD,qEAAqE;AACrE,SAAgB,kBAAkB,CAChC,MAAyC;IAEzC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,EAAE,GAAG,EAAE,mCAAqB,EAAE,CAAC;IACxC,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,SAAgB,uBAAuB,CACrC,MAA6B;IAE7B,MAAM,OAAO,GAA2B;QACtC,cAAc,EAAE,kBAAkB;QAClC,MAAM,EAAE,kBAAkB;KAC3B,CAAC;IACF,IAAI,MAAM,CAAC,gBAAgB,KAAK,SAAS,EAAE,CAAC;QAC1C,OAAO,CAAC,eAAe,CAAC,GAAG,UAAU,MAAM,CAAC,gBAAgB,EAAE,CAAC;IACjE,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;GAIG;AACI,KAAK,UAAU,iBAAiB,CACrC,MAA6B,EAC7B,IAAa,EACb,YAA0B,KAAK;IAE/B,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,SAAS,CAAC;IACvD,IAAI,GAAa,CAAC;IAClB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE;YACzB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,uBAAuB,CAAC,MAAM,CAAC;YACxC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC3B,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,gCAAoB,CAAC,SAAS,CAAC,CAAC;IAC5C,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,gCAAoB,CAAC,QAAQ,CAAC,CAAC;IAC3C,CAAC;IACD,IAAI,MAA+B,CAAC;IACpC,IAAI,CAAC;QACH,MAAM,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAA4B,CAAC;IACzD,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,gCAAoB,CAAC,QAAQ,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;GAGG;AACI,KAAK,UAAU,iBAAiB,CACrC,MAA6B,EAC7B,IAAa,EACb,YAA0B,KAAK;IAE/B,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,SAAS,CAAC;IACvD,IAAI,GAAa,CAAC;IAClB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE;YACzB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,uBAAuB,CAAC,MAAM,CAAC;YACxC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC3B,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,gCAAoB,CAAC,SAAS,CAAC,CAAC;IAC5C,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,gCAAoB,CAAC,QAAQ,CAAC,CAAC;IAC3C,CAAC;IACD,IAAI,MAA+B,CAAC;IACpC,IAAI,CAAC;QACH,MAAM,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAA4B,CAAC;IACzD,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,gCAAoB,CAAC,QAAQ,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { createX402Server } from './server.js';
|
|
2
|
+
export type { X402Server, X402ServerConfig, X402Challenge, X402PaymentRequirements, X402PaymentVerification, } from './server.js';
|
|
3
|
+
export { createX402Client } from './client.js';
|
|
4
|
+
export type { X402Client, X402ClientConfig, X402PaymentResult, } from './client.js';
|
|
5
|
+
export { X402_PAYMENT_REQUIRED_HEADER, X402_PAYMENT_SIGNATURE_HEADER, X402_PAYMENT_RESPONSE_HEADER, X402_SCHEME_EXACT, PAYAI_FACILITATOR_URL, COINBASE_FACILITATOR_URL, } from './protocol.js';
|
|
6
|
+
export type { X402PaymentPayload, X402SchemeId, X402FacilitatorConfig, } from './protocol.js';
|
|
7
|
+
export { X402Error, X402InvalidChallengeError, X402SignatureVerificationError, X402FacilitatorError, X402AssetNotSupportedError, X402AmountMismatchError, } from './errors.js';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,YAAY,EACV,UAAU,EACV,gBAAgB,EAChB,aAAa,EACb,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,YAAY,EACV,UAAU,EACV,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,4BAA4B,EAC5B,6BAA6B,EAC7B,4BAA4B,EAC5B,iBAAiB,EACjB,qBAAqB,EACrB,wBAAwB,GACzB,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,kBAAkB,EAClB,YAAY,EACZ,qBAAqB,GACtB,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,SAAS,EACT,yBAAyB,EACzB,8BAA8B,EAC9B,oBAAoB,EACpB,0BAA0B,EAC1B,uBAAuB,GACxB,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Public surface — @shroud-fi/x402
|
|
3
|
+
// HTTP 402 + stealth-address payment routing for AI agents on Base.
|
|
4
|
+
// See packages/x402/README and docs/research/competitive/x402-spec-and-ecosystem.md.
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.X402AmountMismatchError = exports.X402AssetNotSupportedError = exports.X402FacilitatorError = exports.X402SignatureVerificationError = exports.X402InvalidChallengeError = exports.X402Error = exports.COINBASE_FACILITATOR_URL = exports.PAYAI_FACILITATOR_URL = exports.X402_SCHEME_EXACT = exports.X402_PAYMENT_RESPONSE_HEADER = exports.X402_PAYMENT_SIGNATURE_HEADER = exports.X402_PAYMENT_REQUIRED_HEADER = exports.createX402Client = exports.createX402Server = void 0;
|
|
7
|
+
// Server side
|
|
8
|
+
var server_js_1 = require("./server.js");
|
|
9
|
+
Object.defineProperty(exports, "createX402Server", { enumerable: true, get: function () { return server_js_1.createX402Server; } });
|
|
10
|
+
// Client side
|
|
11
|
+
var client_js_1 = require("./client.js");
|
|
12
|
+
Object.defineProperty(exports, "createX402Client", { enumerable: true, get: function () { return client_js_1.createX402Client; } });
|
|
13
|
+
// Protocol constants + types
|
|
14
|
+
var protocol_js_1 = require("./protocol.js");
|
|
15
|
+
Object.defineProperty(exports, "X402_PAYMENT_REQUIRED_HEADER", { enumerable: true, get: function () { return protocol_js_1.X402_PAYMENT_REQUIRED_HEADER; } });
|
|
16
|
+
Object.defineProperty(exports, "X402_PAYMENT_SIGNATURE_HEADER", { enumerable: true, get: function () { return protocol_js_1.X402_PAYMENT_SIGNATURE_HEADER; } });
|
|
17
|
+
Object.defineProperty(exports, "X402_PAYMENT_RESPONSE_HEADER", { enumerable: true, get: function () { return protocol_js_1.X402_PAYMENT_RESPONSE_HEADER; } });
|
|
18
|
+
Object.defineProperty(exports, "X402_SCHEME_EXACT", { enumerable: true, get: function () { return protocol_js_1.X402_SCHEME_EXACT; } });
|
|
19
|
+
Object.defineProperty(exports, "PAYAI_FACILITATOR_URL", { enumerable: true, get: function () { return protocol_js_1.PAYAI_FACILITATOR_URL; } });
|
|
20
|
+
Object.defineProperty(exports, "COINBASE_FACILITATOR_URL", { enumerable: true, get: function () { return protocol_js_1.COINBASE_FACILITATOR_URL; } });
|
|
21
|
+
// Errors
|
|
22
|
+
var errors_js_1 = require("./errors.js");
|
|
23
|
+
Object.defineProperty(exports, "X402Error", { enumerable: true, get: function () { return errors_js_1.X402Error; } });
|
|
24
|
+
Object.defineProperty(exports, "X402InvalidChallengeError", { enumerable: true, get: function () { return errors_js_1.X402InvalidChallengeError; } });
|
|
25
|
+
Object.defineProperty(exports, "X402SignatureVerificationError", { enumerable: true, get: function () { return errors_js_1.X402SignatureVerificationError; } });
|
|
26
|
+
Object.defineProperty(exports, "X402FacilitatorError", { enumerable: true, get: function () { return errors_js_1.X402FacilitatorError; } });
|
|
27
|
+
Object.defineProperty(exports, "X402AssetNotSupportedError", { enumerable: true, get: function () { return errors_js_1.X402AssetNotSupportedError; } });
|
|
28
|
+
Object.defineProperty(exports, "X402AmountMismatchError", { enumerable: true, get: function () { return errors_js_1.X402AmountMismatchError; } });
|
|
29
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAAA,mCAAmC;AACnC,oEAAoE;AACpE,qFAAqF;;;AAErF,cAAc;AACd,yCAA+C;AAAtC,6GAAA,gBAAgB,OAAA;AASzB,cAAc;AACd,yCAA+C;AAAtC,6GAAA,gBAAgB,OAAA;AAOzB,6BAA6B;AAC7B,6CAOuB;AANrB,2HAAA,4BAA4B,OAAA;AAC5B,4HAAA,6BAA6B,OAAA;AAC7B,2HAAA,4BAA4B,OAAA;AAC5B,gHAAA,iBAAiB,OAAA;AACjB,oHAAA,qBAAqB,OAAA;AACrB,uHAAA,wBAAwB,OAAA;AAQ1B,SAAS;AACT,yCAOqB;AANnB,sGAAA,SAAS,OAAA;AACT,sHAAA,yBAAyB,OAAA;AACzB,2HAAA,8BAA8B,OAAA;AAC9B,iHAAA,oBAAoB,OAAA;AACpB,uHAAA,0BAA0B,OAAA;AAC1B,oHAAA,uBAAuB,OAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"commonjs"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* x402 protocol constants + wire types.
|
|
3
|
+
*
|
|
4
|
+
* v2 spec only. See docs/research/competitive/x402-spec-and-ecosystem.md §1
|
|
5
|
+
* for the canonical field names. v1 (whitepaper, deprecated) names are not
|
|
6
|
+
* accepted by this package.
|
|
7
|
+
*/
|
|
8
|
+
import type { Address, Hex } from 'viem';
|
|
9
|
+
/** Server → client: 402 challenge envelope (raw JSON, no base64 in v2). */
|
|
10
|
+
export declare const X402_PAYMENT_REQUIRED_HEADER: "X-PAYMENT-REQUIRED";
|
|
11
|
+
/**
|
|
12
|
+
* Client → server: signed PaymentPayload (base64-encoded JSON).
|
|
13
|
+
*
|
|
14
|
+
* Canonical name per the v2 spec is `X-PAYMENT`. Older drafts and some
|
|
15
|
+
* SDKs use `X-PAYMENT-SIGNATURE`; we use `X-PAYMENT` to stay aligned with
|
|
16
|
+
* the foundation SDKs (`@x402/fetch`, `@x402/axios`, `@x402/express` all
|
|
17
|
+
* read `X-PAYMENT`).
|
|
18
|
+
*/
|
|
19
|
+
export declare const X402_PAYMENT_SIGNATURE_HEADER: "X-PAYMENT";
|
|
20
|
+
/** Server → client: settlement confirmation (base64-encoded JSON, on 2xx). */
|
|
21
|
+
export declare const X402_PAYMENT_RESPONSE_HEADER: "X-PAYMENT-RESPONSE";
|
|
22
|
+
/** "Exact" scheme — seller knows price up front. Only scheme we support in v1. */
|
|
23
|
+
export declare const X402_SCHEME_EXACT: "exact";
|
|
24
|
+
export type X402SchemeId = typeof X402_SCHEME_EXACT;
|
|
25
|
+
/**
|
|
26
|
+
* PayAI Network facilitator — free tier (≤ 10k settlements/mo) requires no
|
|
27
|
+
* authentication at all. Our default.
|
|
28
|
+
*/
|
|
29
|
+
export declare const PAYAI_FACILITATOR_URL: "https://facilitator.payai.network";
|
|
30
|
+
/**
|
|
31
|
+
* Coinbase CDP facilitator — secondary. Requires CDP API key for use.
|
|
32
|
+
* URL verified against research doc §3 (cdp.coinbase.com/platform/v2/x402).
|
|
33
|
+
*/
|
|
34
|
+
export declare const COINBASE_FACILITATOR_URL: "https://api.cdp.coinbase.com/platform/v2/x402";
|
|
35
|
+
/**
|
|
36
|
+
* The `accepts[N]` entry from a v2 `PaymentRequired` object — the exact shape
|
|
37
|
+
* a client receives over the wire.
|
|
38
|
+
*
|
|
39
|
+
* Field names match the spec verbatim (NOT the v1 whitepaper names — see
|
|
40
|
+
* research doc §10.1 for the drift table).
|
|
41
|
+
*/
|
|
42
|
+
export interface X402PaymentRequirements {
|
|
43
|
+
/** Scheme id; only `'exact'` supported in v1. */
|
|
44
|
+
readonly scheme: X402SchemeId;
|
|
45
|
+
/** CAIP-2 network id, e.g. `'eip155:8453'`. */
|
|
46
|
+
readonly network: string;
|
|
47
|
+
/**
|
|
48
|
+
* Maximum payment amount in token base units (string-encoded to survive
|
|
49
|
+
* uint256). For scheme `exact`, this is the exact required amount.
|
|
50
|
+
*
|
|
51
|
+
* Spec field name: `maxAmountRequired`. We mirror it verbatim.
|
|
52
|
+
*/
|
|
53
|
+
readonly maxAmountRequired: string;
|
|
54
|
+
/** ERC-20 contract address of the asset. */
|
|
55
|
+
readonly asset: Address;
|
|
56
|
+
/**
|
|
57
|
+
* Recipient address. In ShroudFi servers this is ALWAYS a freshly derived
|
|
58
|
+
* stealth address — never the server's main wallet.
|
|
59
|
+
*/
|
|
60
|
+
readonly payTo: Address;
|
|
61
|
+
/** Authorization validity window (seconds). */
|
|
62
|
+
readonly maxTimeoutSeconds: number;
|
|
63
|
+
/** Resource being paid for (URL or pseudo-URL). */
|
|
64
|
+
readonly resource: string;
|
|
65
|
+
/** Optional human-readable description. */
|
|
66
|
+
readonly description?: string;
|
|
67
|
+
/**
|
|
68
|
+
* Scheme-specific extra data. For `exact` on EVM, contains the EIP-712
|
|
69
|
+
* domain `name` + `version` for the asset (so the client can rebuild the
|
|
70
|
+
* domain separator without having to look the token up).
|
|
71
|
+
*/
|
|
72
|
+
readonly extra: {
|
|
73
|
+
readonly name: string;
|
|
74
|
+
readonly version: string;
|
|
75
|
+
/**
|
|
76
|
+
* ShroudFi-specific extension: emitted so a ShroudFi-aware client can
|
|
77
|
+
* relay the Announcement event after settlement. Forward-compatible —
|
|
78
|
+
* non-ShroudFi clients ignore unknown keys.
|
|
79
|
+
*/
|
|
80
|
+
readonly shroudfiAnnouncement?: {
|
|
81
|
+
readonly ephemeralPubKey: Hex;
|
|
82
|
+
readonly viewTag: number;
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* The signed payload the client sends back in `X-PAYMENT`. EIP-3009
|
|
88
|
+
* `transferWithAuthorization` shape.
|
|
89
|
+
*/
|
|
90
|
+
export interface X402PaymentPayload {
|
|
91
|
+
readonly x402Version: 2;
|
|
92
|
+
readonly scheme: X402SchemeId;
|
|
93
|
+
readonly network: string;
|
|
94
|
+
readonly payload: {
|
|
95
|
+
readonly signature: Hex;
|
|
96
|
+
readonly authorization: {
|
|
97
|
+
readonly from: Address;
|
|
98
|
+
readonly to: Address;
|
|
99
|
+
/** uint256 as string. */
|
|
100
|
+
readonly value: string;
|
|
101
|
+
readonly validAfter: string;
|
|
102
|
+
readonly validBefore: string;
|
|
103
|
+
readonly nonce: Hex;
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Optional facilitator config. When unset, the default is PayAI free-tier
|
|
109
|
+
* (no auth). When `ed25519AuthToken` is provided, the facilitator client
|
|
110
|
+
* attaches `Authorization: Bearer <token>` to every request — caller is
|
|
111
|
+
* responsible for minting the JWT per PayAI's spec (research doc §10.5).
|
|
112
|
+
*/
|
|
113
|
+
export interface X402FacilitatorConfig {
|
|
114
|
+
readonly url: string;
|
|
115
|
+
readonly ed25519AuthToken?: string;
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=protocol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/protocol.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;AAIzC,2EAA2E;AAC3E,eAAO,MAAM,4BAA4B,EAAG,oBAA6B,CAAC;AAE1E;;;;;;;GAOG;AACH,eAAO,MAAM,6BAA6B,EAAG,WAAoB,CAAC;AAElE,8EAA8E;AAC9E,eAAO,MAAM,4BAA4B,EAAG,oBAA6B,CAAC;AAI1E,kFAAkF;AAClF,eAAO,MAAM,iBAAiB,EAAG,OAAgB,CAAC;AAElD,MAAM,MAAM,YAAY,GAAG,OAAO,iBAAiB,CAAC;AAIpD;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAChC,mCAA4C,CAAC;AAE/C;;;GAGG;AACH,eAAO,MAAM,wBAAwB,EACnC,+CAAwD,CAAC;AAI3D;;;;;;GAMG;AACH,MAAM,WAAW,uBAAuB;IACtC,iDAAiD;IACjD,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,+CAA+C;IAC/C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,4CAA4C;IAC5C,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,+CAA+C;IAC/C,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,mDAAmD;IACnD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,2CAA2C;IAC3C,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE;QACd,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB;;;;WAIG;QACH,QAAQ,CAAC,oBAAoB,CAAC,EAAE;YAC9B,QAAQ,CAAC,eAAe,EAAE,GAAG,CAAC;YAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;SAC1B,CAAC;KACH,CAAC;CACH;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE;QAChB,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC;QACxB,QAAQ,CAAC,aAAa,EAAE;YACtB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;YACvB,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;YACrB,yBAAyB;YACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;YACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;YAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;YAC7B,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC;SACrB,CAAC;KACH,CAAC;CACH;AAED;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACpC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* x402 protocol constants + wire types.
|
|
4
|
+
*
|
|
5
|
+
* v2 spec only. See docs/research/competitive/x402-spec-and-ecosystem.md §1
|
|
6
|
+
* for the canonical field names. v1 (whitepaper, deprecated) names are not
|
|
7
|
+
* accepted by this package.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.COINBASE_FACILITATOR_URL = exports.PAYAI_FACILITATOR_URL = exports.X402_SCHEME_EXACT = exports.X402_PAYMENT_RESPONSE_HEADER = exports.X402_PAYMENT_SIGNATURE_HEADER = exports.X402_PAYMENT_REQUIRED_HEADER = void 0;
|
|
11
|
+
// ─── HTTP header names ───────────────────────────────────────────────────────
|
|
12
|
+
/** Server → client: 402 challenge envelope (raw JSON, no base64 in v2). */
|
|
13
|
+
exports.X402_PAYMENT_REQUIRED_HEADER = 'X-PAYMENT-REQUIRED';
|
|
14
|
+
/**
|
|
15
|
+
* Client → server: signed PaymentPayload (base64-encoded JSON).
|
|
16
|
+
*
|
|
17
|
+
* Canonical name per the v2 spec is `X-PAYMENT`. Older drafts and some
|
|
18
|
+
* SDKs use `X-PAYMENT-SIGNATURE`; we use `X-PAYMENT` to stay aligned with
|
|
19
|
+
* the foundation SDKs (`@x402/fetch`, `@x402/axios`, `@x402/express` all
|
|
20
|
+
* read `X-PAYMENT`).
|
|
21
|
+
*/
|
|
22
|
+
exports.X402_PAYMENT_SIGNATURE_HEADER = 'X-PAYMENT';
|
|
23
|
+
/** Server → client: settlement confirmation (base64-encoded JSON, on 2xx). */
|
|
24
|
+
exports.X402_PAYMENT_RESPONSE_HEADER = 'X-PAYMENT-RESPONSE';
|
|
25
|
+
// ─── Scheme identifiers ──────────────────────────────────────────────────────
|
|
26
|
+
/** "Exact" scheme — seller knows price up front. Only scheme we support in v1. */
|
|
27
|
+
exports.X402_SCHEME_EXACT = 'exact';
|
|
28
|
+
// ─── Facilitator URLs ────────────────────────────────────────────────────────
|
|
29
|
+
/**
|
|
30
|
+
* PayAI Network facilitator — free tier (≤ 10k settlements/mo) requires no
|
|
31
|
+
* authentication at all. Our default.
|
|
32
|
+
*/
|
|
33
|
+
exports.PAYAI_FACILITATOR_URL = 'https://facilitator.payai.network';
|
|
34
|
+
/**
|
|
35
|
+
* Coinbase CDP facilitator — secondary. Requires CDP API key for use.
|
|
36
|
+
* URL verified against research doc §3 (cdp.coinbase.com/platform/v2/x402).
|
|
37
|
+
*/
|
|
38
|
+
exports.COINBASE_FACILITATOR_URL = 'https://api.cdp.coinbase.com/platform/v2/x402';
|
|
39
|
+
//# sourceMappingURL=protocol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../src/protocol.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AAIH,gFAAgF;AAEhF,2EAA2E;AAC9D,QAAA,4BAA4B,GAAG,oBAA6B,CAAC;AAE1E;;;;;;;GAOG;AACU,QAAA,6BAA6B,GAAG,WAAoB,CAAC;AAElE,8EAA8E;AACjE,QAAA,4BAA4B,GAAG,oBAA6B,CAAC;AAE1E,gFAAgF;AAEhF,kFAAkF;AACrE,QAAA,iBAAiB,GAAG,OAAgB,CAAC;AAIlD,gFAAgF;AAEhF;;;GAGG;AACU,QAAA,qBAAqB,GAChC,mCAA4C,CAAC;AAE/C;;;GAGG;AACU,QAAA,wBAAwB,GACnC,+CAAwD,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* x402 server — challenge generation + signed-payment verification.
|
|
3
|
+
*
|
|
4
|
+
* Privacy invariants enforced here:
|
|
5
|
+
* - Every challenge derives a FRESH stealth address from the recipient's
|
|
6
|
+
* meta-address. The recipient's main wallet NEVER appears in the
|
|
7
|
+
* PaymentRequired body.
|
|
8
|
+
* - The facilitator is only ever shown the stealth `payTo` — same property.
|
|
9
|
+
* - Error paths never include amount values, signature bytes, or the
|
|
10
|
+
* server's spend key.
|
|
11
|
+
*/
|
|
12
|
+
import { type X402PaymentPayload } from './protocol.js';
|
|
13
|
+
import type { X402Challenge, X402PaymentVerification, X402ServerConfig } from './types.js';
|
|
14
|
+
export interface X402Server {
|
|
15
|
+
/**
|
|
16
|
+
* Build a 402 challenge for a given resource. Each call derives a fresh
|
|
17
|
+
* stealth address — calls are deliberately non-idempotent.
|
|
18
|
+
*/
|
|
19
|
+
challenge(args: {
|
|
20
|
+
resource: string;
|
|
21
|
+
description?: string;
|
|
22
|
+
priceAtomic?: bigint;
|
|
23
|
+
}): Promise<X402Challenge>;
|
|
24
|
+
/**
|
|
25
|
+
* Verify a signed payload submitted by the client. Optionally settles via
|
|
26
|
+
* the configured facilitator.
|
|
27
|
+
*
|
|
28
|
+
* When `skipFacilitator: true` is passed, verify returns `valid: true` after
|
|
29
|
+
* signature recovery succeeds and does NOT contact the facilitator. The
|
|
30
|
+
* caller is then responsible for settling the EIP-3009 authorization on-chain
|
|
31
|
+
* itself (e.g. by calling `USDC.transferWithAuthorization` directly through
|
|
32
|
+
* its own walletClient). Use this when the operator runs its own settler EOA
|
|
33
|
+
* and does not want a facilitator in the trust chain — e.g. headless
|
|
34
|
+
* agent-to-agent demos, anon-stack deployments.
|
|
35
|
+
*/
|
|
36
|
+
verify(args: {
|
|
37
|
+
signedPayload: string | X402PaymentPayload;
|
|
38
|
+
challenge: X402Challenge;
|
|
39
|
+
skipFacilitator?: boolean;
|
|
40
|
+
}): Promise<X402PaymentVerification>;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Build an X402Server bound to a single recipient meta-address + asset.
|
|
44
|
+
*/
|
|
45
|
+
export declare function createX402Server(config: X402ServerConfig): X402Server;
|
|
46
|
+
/** Re-export so consumers don't have to dig into types.ts. */
|
|
47
|
+
export type { X402Challenge, X402PaymentVerification, X402ServerConfig, } from './types.js';
|
|
48
|
+
export type { X402PaymentRequirements } from './protocol.js';
|
|
49
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,EAGL,KAAK,kBAAkB,EAExB,MAAM,eAAe,CAAC;AAMvB,OAAO,KAAK,EACV,aAAa,EACb,uBAAuB,EACvB,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAmCpB,MAAM,WAAW,UAAU;IACzB;;;OAGG;IACH,SAAS,CAAC,IAAI,EAAE;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAC3B;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,IAAI,EAAE;QACX,aAAa,EAAE,MAAM,GAAG,kBAAkB,CAAC;QAC3C,SAAS,EAAE,aAAa,CAAC;QACzB,eAAe,CAAC,EAAE,OAAO,CAAC;KAC3B,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAC;CACtC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,UAAU,CA2MrE;AAED,8DAA8D;AAC9D,YAAY,EACV,aAAa,EACb,uBAAuB,EACvB,gBAAgB,GACjB,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* x402 server — challenge generation + signed-payment verification.
|
|
4
|
+
*
|
|
5
|
+
* Privacy invariants enforced here:
|
|
6
|
+
* - Every challenge derives a FRESH stealth address from the recipient's
|
|
7
|
+
* meta-address. The recipient's main wallet NEVER appears in the
|
|
8
|
+
* PaymentRequired body.
|
|
9
|
+
* - The facilitator is only ever shown the stealth `payTo` — same property.
|
|
10
|
+
* - Error paths never include amount values, signature bytes, or the
|
|
11
|
+
* server's spend key.
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.createX402Server = createX402Server;
|
|
15
|
+
const core_1 = require("@shroud-fi/core");
|
|
16
|
+
const payments_1 = require("@shroud-fi/payments");
|
|
17
|
+
const transport_1 = require("@shroud-fi/transport");
|
|
18
|
+
const protocol_js_1 = require("./protocol.js");
|
|
19
|
+
const constants_js_1 = require("./constants.js");
|
|
20
|
+
const errors_js_1 = require("./errors.js");
|
|
21
|
+
const facilitator_js_1 = require("./facilitator.js");
|
|
22
|
+
const signing_js_1 = require("./signing.js");
|
|
23
|
+
/**
|
|
24
|
+
* Encode a CAIP-2 network id from a chain id. EVM only.
|
|
25
|
+
*/
|
|
26
|
+
function caip2(chainId) {
|
|
27
|
+
return `eip155:${chainId}`;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Robust bigint coercion that accepts decimal strings, hex strings,
|
|
31
|
+
* numbers, and bigints. Throws X402InvalidChallengeError on anything else.
|
|
32
|
+
*/
|
|
33
|
+
function toBigInt(v) {
|
|
34
|
+
if (typeof v === 'bigint')
|
|
35
|
+
return v;
|
|
36
|
+
if (typeof v === 'number')
|
|
37
|
+
return BigInt(v);
|
|
38
|
+
if (typeof v === 'string') {
|
|
39
|
+
try {
|
|
40
|
+
return BigInt(v);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
throw new errors_js_1.X402InvalidChallengeError();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
throw new errors_js_1.X402InvalidChallengeError();
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Build an X402Server bound to a single recipient meta-address + asset.
|
|
50
|
+
*/
|
|
51
|
+
function createX402Server(config) {
|
|
52
|
+
// Validate asset is canonical USDC for the chain. Fail-fast at construction.
|
|
53
|
+
const canonicalUsdc = (0, transport_1.getUSDC)(config.chainId);
|
|
54
|
+
const usdcDomain = (0, transport_1.getUSDCDomain)(config.chainId);
|
|
55
|
+
if (canonicalUsdc === undefined || usdcDomain === undefined) {
|
|
56
|
+
throw new errors_js_1.X402AssetNotSupportedError();
|
|
57
|
+
}
|
|
58
|
+
if (config.asset.toLowerCase() !== canonicalUsdc.toLowerCase()) {
|
|
59
|
+
throw new errors_js_1.X402AssetNotSupportedError();
|
|
60
|
+
}
|
|
61
|
+
// Pre-decode the meta-address ONCE — repeated decodes would waste cycles.
|
|
62
|
+
// The decode validates curve membership; downstream errors become
|
|
63
|
+
// X402InvalidChallengeError.
|
|
64
|
+
let decoded;
|
|
65
|
+
try {
|
|
66
|
+
decoded = (0, core_1.decodeMetaAddress)(config.recipientMetaAddress);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
throw new errors_js_1.X402InvalidChallengeError();
|
|
70
|
+
}
|
|
71
|
+
const facilitator = (0, facilitator_js_1.resolveFacilitator)(config.facilitator);
|
|
72
|
+
return {
|
|
73
|
+
async challenge({ resource, description, priceAtomic }) {
|
|
74
|
+
const price = priceAtomic ?? config.defaultPriceAtomic;
|
|
75
|
+
// Derive a fresh stealth address per call. prepareStealthPayment hashes
|
|
76
|
+
// a fresh ephemeral key internally — uniqueness is built in.
|
|
77
|
+
const prepared = (0, payments_1.prepareStealthPayment)(decoded);
|
|
78
|
+
const requirements = {
|
|
79
|
+
scheme: protocol_js_1.X402_SCHEME_EXACT,
|
|
80
|
+
network: caip2(config.chainId),
|
|
81
|
+
maxAmountRequired: price.toString(),
|
|
82
|
+
asset: config.asset,
|
|
83
|
+
payTo: prepared.stealthAddress,
|
|
84
|
+
maxTimeoutSeconds: constants_js_1.DEFAULT_MAX_TIMEOUT_SECS,
|
|
85
|
+
resource,
|
|
86
|
+
...(description !== undefined ? { description } : {}),
|
|
87
|
+
extra: {
|
|
88
|
+
name: usdcDomain.name,
|
|
89
|
+
version: usdcDomain.version,
|
|
90
|
+
shroudfiAnnouncement: {
|
|
91
|
+
ephemeralPubKey: prepared.ephemeralPubKey,
|
|
92
|
+
viewTag: prepared.viewTag,
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
const body = {
|
|
97
|
+
x402Version: constants_js_1.X402_VERSION,
|
|
98
|
+
error: 'Payment required',
|
|
99
|
+
accepts: [requirements],
|
|
100
|
+
};
|
|
101
|
+
return {
|
|
102
|
+
status: 402,
|
|
103
|
+
headers: {
|
|
104
|
+
[protocol_js_1.X402_PAYMENT_REQUIRED_HEADER]: JSON.stringify(body),
|
|
105
|
+
'content-type': 'application/json',
|
|
106
|
+
},
|
|
107
|
+
body,
|
|
108
|
+
announcement: {
|
|
109
|
+
ephemeralPubKey: prepared.ephemeralPubKey,
|
|
110
|
+
viewTag: prepared.viewTag,
|
|
111
|
+
stealthAddress: prepared.stealthAddress,
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
},
|
|
115
|
+
async verify({ signedPayload, challenge, skipFacilitator }) {
|
|
116
|
+
// 1. Decode incoming payload.
|
|
117
|
+
let payload;
|
|
118
|
+
if (typeof signedPayload === 'string') {
|
|
119
|
+
try {
|
|
120
|
+
// Spec: header value is base64-encoded JSON.
|
|
121
|
+
const decodedJson = Buffer.from(signedPayload, 'base64').toString('utf-8');
|
|
122
|
+
payload = JSON.parse(decodedJson);
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return { valid: false, error: 'malformed_payload' };
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
payload = signedPayload;
|
|
130
|
+
}
|
|
131
|
+
// 2. Structural checks. Tagged failures only — no field values in errors.
|
|
132
|
+
if (payload.x402Version !== 2 ||
|
|
133
|
+
payload.scheme !== protocol_js_1.X402_SCHEME_EXACT ||
|
|
134
|
+
payload.network !== caip2(config.chainId)) {
|
|
135
|
+
return { valid: false, error: 'scheme_mismatch' };
|
|
136
|
+
}
|
|
137
|
+
const auth = payload.payload?.authorization;
|
|
138
|
+
const sig = payload.payload?.signature;
|
|
139
|
+
if (auth === undefined || sig === undefined) {
|
|
140
|
+
return { valid: false, error: 'malformed_payload' };
|
|
141
|
+
}
|
|
142
|
+
const accepted = challenge.body.accepts[0];
|
|
143
|
+
if (accepted === undefined) {
|
|
144
|
+
return { valid: false, error: 'malformed_challenge' };
|
|
145
|
+
}
|
|
146
|
+
// 3. Authorization fields must address the same stealth `payTo` and the
|
|
147
|
+
// exact required amount.
|
|
148
|
+
let value;
|
|
149
|
+
let validAfter;
|
|
150
|
+
let validBefore;
|
|
151
|
+
try {
|
|
152
|
+
value = toBigInt(auth.value);
|
|
153
|
+
validAfter = toBigInt(auth.validAfter);
|
|
154
|
+
validBefore = toBigInt(auth.validBefore);
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
return { valid: false, error: 'malformed_payload' };
|
|
158
|
+
}
|
|
159
|
+
if (auth.to.toLowerCase() !== accepted.payTo.toLowerCase()) {
|
|
160
|
+
return { valid: false, error: 'recipient_mismatch' };
|
|
161
|
+
}
|
|
162
|
+
let requiredAmount;
|
|
163
|
+
try {
|
|
164
|
+
requiredAmount = toBigInt(accepted.maxAmountRequired);
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
return { valid: false, error: 'malformed_challenge' };
|
|
168
|
+
}
|
|
169
|
+
if (value !== requiredAmount) {
|
|
170
|
+
return { valid: false, error: 'amount_mismatch' };
|
|
171
|
+
}
|
|
172
|
+
// 4. Time window.
|
|
173
|
+
const nowSecs = BigInt(Math.floor(Date.now() / 1000));
|
|
174
|
+
if (validBefore <= nowSecs) {
|
|
175
|
+
return { valid: false, error: 'expired' };
|
|
176
|
+
}
|
|
177
|
+
if (validAfter > nowSecs) {
|
|
178
|
+
return { valid: false, error: 'not_yet_valid' };
|
|
179
|
+
}
|
|
180
|
+
// 5. Signature recovery.
|
|
181
|
+
const authInput = {
|
|
182
|
+
from: auth.from,
|
|
183
|
+
to: auth.to,
|
|
184
|
+
value,
|
|
185
|
+
validAfter,
|
|
186
|
+
validBefore,
|
|
187
|
+
nonce: auth.nonce,
|
|
188
|
+
};
|
|
189
|
+
const recovered = await (0, signing_js_1.verifyTransferWithAuthorizationSignature)({
|
|
190
|
+
chainId: config.chainId,
|
|
191
|
+
verifyingContract: config.asset,
|
|
192
|
+
authorization: authInput,
|
|
193
|
+
signature: sig,
|
|
194
|
+
});
|
|
195
|
+
if (recovered === null ||
|
|
196
|
+
recovered.toLowerCase() !== auth.from.toLowerCase()) {
|
|
197
|
+
return { valid: false, error: 'signature_invalid' };
|
|
198
|
+
}
|
|
199
|
+
// 6a. Self-settle mode: caller handles on-chain settlement, we return
|
|
200
|
+
// valid:true after signature recovery. No facilitator contact.
|
|
201
|
+
if (skipFacilitator === true) {
|
|
202
|
+
return { valid: true };
|
|
203
|
+
}
|
|
204
|
+
// 6b. Facilitator submission. Caller gets the settled tx hash.
|
|
205
|
+
// We send the facilitator only what it needs: the requirements + the
|
|
206
|
+
// signed payload. The recipient's main wallet is never in this body
|
|
207
|
+
// because `accepted.payTo` is the freshly derived stealth address.
|
|
208
|
+
try {
|
|
209
|
+
const verifyResult = await (0, facilitator_js_1.facilitatorVerify)(facilitator, {
|
|
210
|
+
x402Version: constants_js_1.X402_VERSION,
|
|
211
|
+
paymentRequirements: accepted,
|
|
212
|
+
paymentPayload: payload,
|
|
213
|
+
});
|
|
214
|
+
if (!verifyResult.isValid) {
|
|
215
|
+
return { valid: false, error: 'facilitator_rejected' };
|
|
216
|
+
}
|
|
217
|
+
const settle = await (0, facilitator_js_1.facilitatorSettle)(facilitator, {
|
|
218
|
+
x402Version: constants_js_1.X402_VERSION,
|
|
219
|
+
paymentRequirements: accepted,
|
|
220
|
+
paymentPayload: payload,
|
|
221
|
+
});
|
|
222
|
+
if (!settle.success || settle.txHash === undefined) {
|
|
223
|
+
return { valid: false, error: 'facilitator_settle_failed' };
|
|
224
|
+
}
|
|
225
|
+
return { valid: true, settledTxHash: settle.txHash };
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
// Facilitator unreachable / non-2xx. Return signature-verified=true
|
|
229
|
+
// so the caller can decide whether to retry or fall back. The signed
|
|
230
|
+
// payload remains cryptographically valid even when the facilitator
|
|
231
|
+
// path failed.
|
|
232
|
+
return { valid: false, error: 'facilitator_unreachable' };
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":"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"}
|