@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
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ShroudFi contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# @shroud-fi/x402
|
|
2
|
+
|
|
3
|
+
> Stealth-addressed HTTP 402 payments for AI agents. EIP-3009 settlement into one-time addresses.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@shroud-fi/x402)
|
|
6
|
+
[](./LICENSE)
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm i @shroud-fi/x402 viem
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## What it does
|
|
13
|
+
|
|
14
|
+
`@shroud-fi/x402` wraps the HTTP 402 protocol with ShroudFi's stealth-address layer. Any endpoint can issue a 402 challenge, and any agent can pay it — but the USDC settlement lands at a **fresh, one-time stealth address** derived from the seller's meta-address.
|
|
15
|
+
|
|
16
|
+
Call the same `/pay/signal` URL ten times — get ten unlinkable USDC destinations. The customer graph never forms on-chain.
|
|
17
|
+
|
|
18
|
+
## Why it matters
|
|
19
|
+
|
|
20
|
+
A naive agent-to-agent payment exposes the buyer's main wallet, the seller's main wallet, and a verifiable on-chain link between them. After enough calls, the entire customer graph of an agentic service is publicly reconstructable. Stealth-addressed x402 closes that.
|
|
21
|
+
|
|
22
|
+
## Quick start (client)
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { payX402 } from '@shroud-fi/x402';
|
|
26
|
+
|
|
27
|
+
const signal = await payX402({
|
|
28
|
+
agent, // a ShroudAgent from @shroud-fi/agent-runtime
|
|
29
|
+
url: 'https://api.alpha.xyz/signal',
|
|
30
|
+
maxPriceUsdcAtomic: 10_000n, // 0.01 USDC
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
console.log(signal); // unlocked response body
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Quick start (server)
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
import { createX402Server } from '@shroud-fi/x402';
|
|
40
|
+
|
|
41
|
+
const x402 = createX402Server({
|
|
42
|
+
resource: 'https://api.alpha.xyz/signal',
|
|
43
|
+
priceUsdcAtomic: 10_000n,
|
|
44
|
+
recipientMeta: 'st:base:0x024fa9bb…',
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// In your Fastify / Express handler:
|
|
48
|
+
const payment = req.headers['x-payment'];
|
|
49
|
+
if (!payment) {
|
|
50
|
+
return reply.code(402).send(await x402.challenge());
|
|
51
|
+
}
|
|
52
|
+
const verified = await x402.verify(payment);
|
|
53
|
+
if (!verified.ok) return reply.code(402).send({ error: verified.reason });
|
|
54
|
+
// payment OK — settle + serve content
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Exports
|
|
58
|
+
|
|
59
|
+
| Symbol | Purpose |
|
|
60
|
+
|---|---|
|
|
61
|
+
| `payX402(args)` | One-shot client. Calls a URL, signs USDC if a 402 lands, retries with `X-PAYMENT`, returns the unlocked body. |
|
|
62
|
+
| `createX402Server(cfg)` | Server-side primitives. Mint a 402 challenge or verify a payment payload. |
|
|
63
|
+
| `buildX402Payment(args)` | Lower-level sign-only flow for custom HTTP machinery. |
|
|
64
|
+
|
|
65
|
+
Full API reference: [shroudfi.live/sdk#x402](https://shroudfi.live/sdk#x402)
|
|
66
|
+
|
|
67
|
+
## Standards used
|
|
68
|
+
|
|
69
|
+
- **HTTP 402 Payment Required** + **`x402` extension** ([x402.org](https://x402.org/))
|
|
70
|
+
- **EIP-3009** `transferWithAuthorization` for USDC settlement
|
|
71
|
+
- **EIP-5564 / 6538** for stealth-address derivation
|
|
72
|
+
|
|
73
|
+
## License
|
|
74
|
+
|
|
75
|
+
MIT — see [LICENSE](./LICENSE).
|
|
76
|
+
|
|
77
|
+
Part of the [ShroudFi](https://shroudfi.live) privacy SDK for AI agents on Base.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* x402 client — fetch wrapper that auto-handles 402 challenges.
|
|
3
|
+
*
|
|
4
|
+
* Flow:
|
|
5
|
+
* 1. Issue initial fetch.
|
|
6
|
+
* 2. If status !== 402, return as-is.
|
|
7
|
+
* 3. Parse X-PAYMENT-REQUIRED, validate scheme + asset + safety cap.
|
|
8
|
+
* 4. Sign EIP-3009 TransferWithAuthorization for USDC.
|
|
9
|
+
* 5. Re-issue request with `X-PAYMENT: base64(JSON(payload))`.
|
|
10
|
+
* 6. On 2xx, surface `x402Settlement` on the returned Response if the
|
|
11
|
+
* server attached X-PAYMENT-RESPONSE.
|
|
12
|
+
*
|
|
13
|
+
* Privacy invariants:
|
|
14
|
+
* - The signed payload is constructed in memory and forwarded directly to
|
|
15
|
+
* the server. We never log or serialize the signature, nonce, or value.
|
|
16
|
+
* - The client wallet address is unavoidably visible (it IS the `from`).
|
|
17
|
+
* This is the agent's stealth-payer EOA, not a persistent identity if
|
|
18
|
+
* used by ShroudAgent.
|
|
19
|
+
* - Errors carry no amount, no signature, no nonce bytes.
|
|
20
|
+
*/
|
|
21
|
+
import type { X402ClientConfig, X402PaymentResult } from './types.js';
|
|
22
|
+
/**
|
|
23
|
+
* The augmented Response surface. We can't subclass `Response` in a portable
|
|
24
|
+
* way, so we attach `x402Settlement` as a non-standard own-property.
|
|
25
|
+
*/
|
|
26
|
+
export interface X402Response extends Response {
|
|
27
|
+
x402Settlement?: X402PaymentResult;
|
|
28
|
+
}
|
|
29
|
+
export interface X402Client {
|
|
30
|
+
/**
|
|
31
|
+
* Wrap `fetch` with 402 auto-pay. The returned Response is augmented with
|
|
32
|
+
* `x402Settlement` when a payment was made.
|
|
33
|
+
*
|
|
34
|
+
* @param maxPriceAtomic — safety cap. If the server demands more, the
|
|
35
|
+
* client throws X402AmountMismatchError without signing anything.
|
|
36
|
+
*/
|
|
37
|
+
fetch(input: string | URL | Request, init?: RequestInit & {
|
|
38
|
+
maxPriceAtomic?: bigint;
|
|
39
|
+
}): Promise<X402Response>;
|
|
40
|
+
}
|
|
41
|
+
export declare function createX402Client(config: X402ClientConfig): X402Client;
|
|
42
|
+
export type { X402ClientConfig, X402PaymentResult } from './types.js';
|
|
43
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAkBH,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAMtE;;;GAGG;AACH,MAAM,WAAW,YAAa,SAAQ,QAAQ;IAC5C,cAAc,CAAC,EAAE,iBAAiB,CAAC;CACpC;AAED,MAAM,WAAW,UAAU;IACzB;;;;;;OAMG;IACH,KAAK,CACH,KAAK,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,EAC7B,IAAI,CAAC,EAAE,WAAW,GAAG;QAAE,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAC/C,OAAO,CAAC,YAAY,CAAC,CAAC;CAC1B;AAyED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,UAAU,CA6HrE;AAED,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* x402 client — fetch wrapper that auto-handles 402 challenges.
|
|
4
|
+
*
|
|
5
|
+
* Flow:
|
|
6
|
+
* 1. Issue initial fetch.
|
|
7
|
+
* 2. If status !== 402, return as-is.
|
|
8
|
+
* 3. Parse X-PAYMENT-REQUIRED, validate scheme + asset + safety cap.
|
|
9
|
+
* 4. Sign EIP-3009 TransferWithAuthorization for USDC.
|
|
10
|
+
* 5. Re-issue request with `X-PAYMENT: base64(JSON(payload))`.
|
|
11
|
+
* 6. On 2xx, surface `x402Settlement` on the returned Response if the
|
|
12
|
+
* server attached X-PAYMENT-RESPONSE.
|
|
13
|
+
*
|
|
14
|
+
* Privacy invariants:
|
|
15
|
+
* - The signed payload is constructed in memory and forwarded directly to
|
|
16
|
+
* the server. We never log or serialize the signature, nonce, or value.
|
|
17
|
+
* - The client wallet address is unavoidably visible (it IS the `from`).
|
|
18
|
+
* This is the agent's stealth-payer EOA, not a persistent identity if
|
|
19
|
+
* used by ShroudAgent.
|
|
20
|
+
* - Errors carry no amount, no signature, no nonce bytes.
|
|
21
|
+
*/
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.createX402Client = createX402Client;
|
|
24
|
+
const transport_1 = require("@shroud-fi/transport");
|
|
25
|
+
const protocol_js_1 = require("./protocol.js");
|
|
26
|
+
const constants_js_1 = require("./constants.js");
|
|
27
|
+
const errors_js_1 = require("./errors.js");
|
|
28
|
+
const signing_js_1 = require("./signing.js");
|
|
29
|
+
/** Decode a 402 challenge body from the response. Tries header, then body. */
|
|
30
|
+
async function readChallenge(res) {
|
|
31
|
+
// Header path (spec-canonical) first.
|
|
32
|
+
const header = res.headers.get(protocol_js_1.X402_PAYMENT_REQUIRED_HEADER);
|
|
33
|
+
if (header !== null && header.length > 0) {
|
|
34
|
+
try {
|
|
35
|
+
const parsed = JSON.parse(header);
|
|
36
|
+
if (Array.isArray(parsed.accepts) && parsed.accepts.length > 0) {
|
|
37
|
+
return parsed;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
// fall through to body parse
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// Body fallback — some servers put the envelope in the body only.
|
|
45
|
+
try {
|
|
46
|
+
const text = await res.clone().text();
|
|
47
|
+
const parsed = JSON.parse(text);
|
|
48
|
+
if (Array.isArray(parsed.accepts) && parsed.accepts.length > 0) {
|
|
49
|
+
return parsed;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// fall through
|
|
54
|
+
}
|
|
55
|
+
throw new errors_js_1.X402InvalidChallengeError();
|
|
56
|
+
}
|
|
57
|
+
/** Decode the X-PAYMENT-RESPONSE header into a settlement record. */
|
|
58
|
+
function readSettlement(res) {
|
|
59
|
+
const header = res.headers.get(protocol_js_1.X402_PAYMENT_RESPONSE_HEADER);
|
|
60
|
+
if (header === null || header.length === 0)
|
|
61
|
+
return undefined;
|
|
62
|
+
try {
|
|
63
|
+
// Header is base64-encoded JSON per the spec.
|
|
64
|
+
const decoded = Buffer.from(header, 'base64').toString('utf-8');
|
|
65
|
+
const parsed = JSON.parse(decoded);
|
|
66
|
+
const txHash = (parsed.transaction ?? parsed.txHash);
|
|
67
|
+
if (txHash === undefined)
|
|
68
|
+
return undefined;
|
|
69
|
+
return {
|
|
70
|
+
txHash,
|
|
71
|
+
settledAt: typeof parsed.settledAt === 'number'
|
|
72
|
+
? parsed.settledAt
|
|
73
|
+
: Math.floor(Date.now() / 1000),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/** Convert a value into a bigint safely. */
|
|
81
|
+
function safeBigInt(v) {
|
|
82
|
+
try {
|
|
83
|
+
if (typeof v === 'bigint')
|
|
84
|
+
return v;
|
|
85
|
+
if (typeof v === 'string' || typeof v === 'number')
|
|
86
|
+
return BigInt(v);
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function createX402Client(config) {
|
|
94
|
+
const transport = config.transport;
|
|
95
|
+
const walletClient = transport.walletClient;
|
|
96
|
+
if (walletClient === undefined || walletClient.account === undefined) {
|
|
97
|
+
// We deliberately throw at construction time so a misconfigured client
|
|
98
|
+
// can't ship to production without a wallet.
|
|
99
|
+
throw new errors_js_1.X402AssetNotSupportedError();
|
|
100
|
+
}
|
|
101
|
+
const account = walletClient.account;
|
|
102
|
+
const chain = transport.chain;
|
|
103
|
+
return {
|
|
104
|
+
async fetch(input, init) {
|
|
105
|
+
const fetchImpl = globalThis.fetch;
|
|
106
|
+
const maxPriceAtomic = init?.maxPriceAtomic;
|
|
107
|
+
// Strip our non-standard option before passing init to fetch.
|
|
108
|
+
const passThroughInit = { ...(init ?? {}) };
|
|
109
|
+
delete passThroughInit.maxPriceAtomic;
|
|
110
|
+
// 1. First attempt.
|
|
111
|
+
const first = (await fetchImpl(input, passThroughInit));
|
|
112
|
+
if (first.status !== 402) {
|
|
113
|
+
return first;
|
|
114
|
+
}
|
|
115
|
+
// 2. Decode challenge.
|
|
116
|
+
const challenge = await readChallenge(first);
|
|
117
|
+
const requirements = challenge.accepts[0];
|
|
118
|
+
if (requirements === undefined) {
|
|
119
|
+
throw new errors_js_1.X402InvalidChallengeError();
|
|
120
|
+
}
|
|
121
|
+
// 3. Scheme + network + asset checks.
|
|
122
|
+
if (requirements.scheme !== protocol_js_1.X402_SCHEME_EXACT) {
|
|
123
|
+
throw new errors_js_1.X402InvalidChallengeError();
|
|
124
|
+
}
|
|
125
|
+
const canonicalUsdc = (0, transport_1.getUSDC)(chain.id);
|
|
126
|
+
if (canonicalUsdc === undefined) {
|
|
127
|
+
throw new errors_js_1.X402AssetNotSupportedError();
|
|
128
|
+
}
|
|
129
|
+
if (requirements.asset.toLowerCase() !==
|
|
130
|
+
canonicalUsdc.toLowerCase()) {
|
|
131
|
+
throw new errors_js_1.X402AssetNotSupportedError();
|
|
132
|
+
}
|
|
133
|
+
const expectedNetwork = `eip155:${chain.id}`;
|
|
134
|
+
if (requirements.network !== expectedNetwork) {
|
|
135
|
+
throw new errors_js_1.X402AssetNotSupportedError();
|
|
136
|
+
}
|
|
137
|
+
// 4. Safety cap.
|
|
138
|
+
const required = safeBigInt(requirements.maxAmountRequired);
|
|
139
|
+
if (required === null) {
|
|
140
|
+
throw new errors_js_1.X402InvalidChallengeError();
|
|
141
|
+
}
|
|
142
|
+
if (maxPriceAtomic !== undefined && required > maxPriceAtomic) {
|
|
143
|
+
throw new errors_js_1.X402AmountMismatchError();
|
|
144
|
+
}
|
|
145
|
+
// 5. Build authorization. validAfter=0n, validBefore=now+ttl.
|
|
146
|
+
const nowSecs = BigInt(Math.floor(Date.now() / 1000));
|
|
147
|
+
const ttl = BigInt(Math.min(requirements.maxTimeoutSeconds || constants_js_1.DEFAULT_AUTHORIZATION_TTL_SECS, constants_js_1.DEFAULT_AUTHORIZATION_TTL_SECS));
|
|
148
|
+
const validBefore = nowSecs + ttl;
|
|
149
|
+
const nonce = (0, signing_js_1.generateAuthorizationNonce)();
|
|
150
|
+
const signed = await (0, signing_js_1.signTransferWithAuthorization)({
|
|
151
|
+
account,
|
|
152
|
+
chain,
|
|
153
|
+
verifyingContract: requirements.asset,
|
|
154
|
+
input: {
|
|
155
|
+
from: account.address,
|
|
156
|
+
to: requirements.payTo,
|
|
157
|
+
value: required,
|
|
158
|
+
validAfter: 0n,
|
|
159
|
+
validBefore,
|
|
160
|
+
nonce,
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
// 6. Build the PaymentPayload + base64 the header.
|
|
164
|
+
const payload = {
|
|
165
|
+
x402Version: constants_js_1.X402_VERSION,
|
|
166
|
+
scheme: protocol_js_1.X402_SCHEME_EXACT,
|
|
167
|
+
network: requirements.network,
|
|
168
|
+
payload: {
|
|
169
|
+
signature: signed.signature,
|
|
170
|
+
authorization: {
|
|
171
|
+
from: signed.from,
|
|
172
|
+
to: signed.to,
|
|
173
|
+
value: signed.value.toString(),
|
|
174
|
+
validAfter: signed.validAfter.toString(),
|
|
175
|
+
validBefore: signed.validBefore.toString(),
|
|
176
|
+
nonce: signed.nonce,
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
const encoded = Buffer.from(JSON.stringify(payload), 'utf-8').toString('base64');
|
|
181
|
+
// 7. Re-issue. Mutating the headers via a new object so the caller's
|
|
182
|
+
// original init stays untouched.
|
|
183
|
+
const retryHeaders = new Headers(passThroughInit.headers ?? undefined);
|
|
184
|
+
retryHeaders.set(protocol_js_1.X402_PAYMENT_SIGNATURE_HEADER, encoded);
|
|
185
|
+
const retryInit = {
|
|
186
|
+
...passThroughInit,
|
|
187
|
+
headers: retryHeaders,
|
|
188
|
+
};
|
|
189
|
+
const second = (await fetchImpl(input, retryInit));
|
|
190
|
+
const settlement = readSettlement(second);
|
|
191
|
+
if (settlement !== undefined) {
|
|
192
|
+
// Attach as a non-standard own-property.
|
|
193
|
+
second.x402Settlement = settlement;
|
|
194
|
+
}
|
|
195
|
+
return second;
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Defaults for the @shroud-fi/x402 package.
|
|
3
|
+
*
|
|
4
|
+
* Tight defaults reduce blast radius if a signed payload leaks:
|
|
5
|
+
* - 5-minute validity window matches Coinbase CDP recommendation and the
|
|
6
|
+
* PayAI free tier facilitator's default maxTimeoutSeconds (300).
|
|
7
|
+
* - x402Version pinned to 2 (current shipping spec). We deliberately do NOT
|
|
8
|
+
* implement v1 backward-compat per LOCKED-DECISIONS (whitepaper field
|
|
9
|
+
* names are deprecated).
|
|
10
|
+
*/
|
|
11
|
+
export declare const X402_VERSION: 2;
|
|
12
|
+
/** Default EIP-3009 authorization validity window (seconds). */
|
|
13
|
+
export declare const DEFAULT_AUTHORIZATION_TTL_SECS = 300;
|
|
14
|
+
/** Default facilitator `maxTimeoutSeconds` echoed back in PaymentRequired. */
|
|
15
|
+
export declare const DEFAULT_MAX_TIMEOUT_SECS = 300;
|
|
16
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,eAAO,MAAM,YAAY,EAAG,CAAU,CAAC;AAEvC,gEAAgE;AAChE,eAAO,MAAM,8BAA8B,MAAM,CAAC;AAElD,8EAA8E;AAC9E,eAAO,MAAM,wBAAwB,MAAM,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Defaults for the @shroud-fi/x402 package.
|
|
4
|
+
*
|
|
5
|
+
* Tight defaults reduce blast radius if a signed payload leaks:
|
|
6
|
+
* - 5-minute validity window matches Coinbase CDP recommendation and the
|
|
7
|
+
* PayAI free tier facilitator's default maxTimeoutSeconds (300).
|
|
8
|
+
* - x402Version pinned to 2 (current shipping spec). We deliberately do NOT
|
|
9
|
+
* implement v1 backward-compat per LOCKED-DECISIONS (whitepaper field
|
|
10
|
+
* names are deprecated).
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.DEFAULT_MAX_TIMEOUT_SECS = exports.DEFAULT_AUTHORIZATION_TTL_SECS = exports.X402_VERSION = void 0;
|
|
14
|
+
exports.X402_VERSION = 2;
|
|
15
|
+
/** Default EIP-3009 authorization validity window (seconds). */
|
|
16
|
+
exports.DEFAULT_AUTHORIZATION_TTL_SECS = 300;
|
|
17
|
+
/** Default facilitator `maxTimeoutSeconds` echoed back in PaymentRequired. */
|
|
18
|
+
exports.DEFAULT_MAX_TIMEOUT_SECS = 300;
|
|
19
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;;AAEU,QAAA,YAAY,GAAG,CAAU,CAAC;AAEvC,gEAAgE;AACnD,QAAA,8BAA8B,GAAG,GAAG,CAAC;AAElD,8EAA8E;AACjE,QAAA,wBAAwB,GAAG,GAAG,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* x402 error hierarchy.
|
|
3
|
+
*
|
|
4
|
+
* Privacy invariants:
|
|
5
|
+
* - No amount, value, or balance numbers in any .message string.
|
|
6
|
+
* - No private keys, signature bytes, or nonce bytes in any .message string.
|
|
7
|
+
* - No recipient main wallet addresses in any .message string (stealth
|
|
8
|
+
* addresses are derivable on-chain so leaking them post-payment is fine,
|
|
9
|
+
* but the registrant wallet is identity-bearing — never include it).
|
|
10
|
+
* - All errors extend the same base class so callers can `instanceof X402Error`
|
|
11
|
+
* once at the boundary.
|
|
12
|
+
*/
|
|
13
|
+
export declare class X402Error extends Error {
|
|
14
|
+
readonly name: string;
|
|
15
|
+
constructor(message: string);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The 402 challenge body (or its header) could not be parsed / is malformed.
|
|
19
|
+
* Catch-all for "we received something the spec disallows".
|
|
20
|
+
*/
|
|
21
|
+
export declare class X402InvalidChallengeError extends X402Error {
|
|
22
|
+
readonly name: string;
|
|
23
|
+
constructor();
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The signed `PAYMENT-SIGNATURE` payload submitted by the client could not be
|
|
27
|
+
* verified against the challenge (signer mismatch, malformed JSON, expired
|
|
28
|
+
* authorization, etc).
|
|
29
|
+
*/
|
|
30
|
+
export declare class X402SignatureVerificationError extends X402Error {
|
|
31
|
+
readonly name: string;
|
|
32
|
+
constructor();
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Facilitator HTTP call (verify or settle) failed. Tag identifies the
|
|
36
|
+
* facilitator stage but never carries response body, token amount, or signed
|
|
37
|
+
* payload.
|
|
38
|
+
*/
|
|
39
|
+
export declare class X402FacilitatorError extends X402Error {
|
|
40
|
+
readonly name: string;
|
|
41
|
+
constructor(stage: 'verify' | 'settle' | 'network');
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The server's configured asset is not the canonical USDC on the configured
|
|
45
|
+
* chain (or USDC is not deployed on the chain). Hard-fail to avoid signing
|
|
46
|
+
* authorizations against the wrong token.
|
|
47
|
+
*/
|
|
48
|
+
export declare class X402AssetNotSupportedError extends X402Error {
|
|
49
|
+
readonly name: string;
|
|
50
|
+
constructor();
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The server's quoted price exceeded the client's `maxPriceAtomic` safety cap,
|
|
54
|
+
* or the verified payload's value did not equal the challenge requirement.
|
|
55
|
+
* The error carries no amount bytes — caller can read inputs separately.
|
|
56
|
+
*/
|
|
57
|
+
export declare class X402AmountMismatchError extends X402Error {
|
|
58
|
+
readonly name: string;
|
|
59
|
+
constructor();
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,qBAAa,SAAU,SAAQ,KAAK;IAClC,SAAkB,IAAI,EAAE,MAAM,CAAe;gBACjC,OAAO,EAAE,MAAM;CAG5B;AAED;;;GAGG;AACH,qBAAa,yBAA0B,SAAQ,SAAS;IACtD,SAAkB,IAAI,EAAE,MAAM,CAA+B;;CAI9D;AAED;;;;GAIG;AACH,qBAAa,8BAA+B,SAAQ,SAAS;IAC3D,SAAkB,IAAI,EAAE,MAAM,CAAoC;;CAInE;AAED;;;;GAIG;AACH,qBAAa,oBAAqB,SAAQ,SAAS;IACjD,SAAkB,IAAI,EAAE,MAAM,CAA0B;gBAC5C,KAAK,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS;CAGnD;AAED;;;;GAIG;AACH,qBAAa,0BAA2B,SAAQ,SAAS;IACvD,SAAkB,IAAI,EAAE,MAAM,CAAgC;;CAI/D;AAED;;;;GAIG;AACH,qBAAa,uBAAwB,SAAQ,SAAS;IACpD,SAAkB,IAAI,EAAE,MAAM,CAA6B;;CAI5D"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* x402 error hierarchy.
|
|
4
|
+
*
|
|
5
|
+
* Privacy invariants:
|
|
6
|
+
* - No amount, value, or balance numbers in any .message string.
|
|
7
|
+
* - No private keys, signature bytes, or nonce bytes in any .message string.
|
|
8
|
+
* - No recipient main wallet addresses in any .message string (stealth
|
|
9
|
+
* addresses are derivable on-chain so leaking them post-payment is fine,
|
|
10
|
+
* but the registrant wallet is identity-bearing — never include it).
|
|
11
|
+
* - All errors extend the same base class so callers can `instanceof X402Error`
|
|
12
|
+
* once at the boundary.
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.X402AmountMismatchError = exports.X402AssetNotSupportedError = exports.X402FacilitatorError = exports.X402SignatureVerificationError = exports.X402InvalidChallengeError = exports.X402Error = void 0;
|
|
16
|
+
class X402Error extends Error {
|
|
17
|
+
name = 'X402Error';
|
|
18
|
+
constructor(message) {
|
|
19
|
+
super(message);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.X402Error = X402Error;
|
|
23
|
+
/**
|
|
24
|
+
* The 402 challenge body (or its header) could not be parsed / is malformed.
|
|
25
|
+
* Catch-all for "we received something the spec disallows".
|
|
26
|
+
*/
|
|
27
|
+
class X402InvalidChallengeError extends X402Error {
|
|
28
|
+
name = 'X402InvalidChallengeError';
|
|
29
|
+
constructor() {
|
|
30
|
+
super('Invalid x402 challenge payload');
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
exports.X402InvalidChallengeError = X402InvalidChallengeError;
|
|
34
|
+
/**
|
|
35
|
+
* The signed `PAYMENT-SIGNATURE` payload submitted by the client could not be
|
|
36
|
+
* verified against the challenge (signer mismatch, malformed JSON, expired
|
|
37
|
+
* authorization, etc).
|
|
38
|
+
*/
|
|
39
|
+
class X402SignatureVerificationError extends X402Error {
|
|
40
|
+
name = 'X402SignatureVerificationError';
|
|
41
|
+
constructor() {
|
|
42
|
+
super('x402 signed payment payload failed verification');
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
exports.X402SignatureVerificationError = X402SignatureVerificationError;
|
|
46
|
+
/**
|
|
47
|
+
* Facilitator HTTP call (verify or settle) failed. Tag identifies the
|
|
48
|
+
* facilitator stage but never carries response body, token amount, or signed
|
|
49
|
+
* payload.
|
|
50
|
+
*/
|
|
51
|
+
class X402FacilitatorError extends X402Error {
|
|
52
|
+
name = 'X402FacilitatorError';
|
|
53
|
+
constructor(stage) {
|
|
54
|
+
super(`x402 facilitator request failed (stage=${stage})`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
exports.X402FacilitatorError = X402FacilitatorError;
|
|
58
|
+
/**
|
|
59
|
+
* The server's configured asset is not the canonical USDC on the configured
|
|
60
|
+
* chain (or USDC is not deployed on the chain). Hard-fail to avoid signing
|
|
61
|
+
* authorizations against the wrong token.
|
|
62
|
+
*/
|
|
63
|
+
class X402AssetNotSupportedError extends X402Error {
|
|
64
|
+
name = 'X402AssetNotSupportedError';
|
|
65
|
+
constructor() {
|
|
66
|
+
super('x402: requested asset is not supported on the configured chain');
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
exports.X402AssetNotSupportedError = X402AssetNotSupportedError;
|
|
70
|
+
/**
|
|
71
|
+
* The server's quoted price exceeded the client's `maxPriceAtomic` safety cap,
|
|
72
|
+
* or the verified payload's value did not equal the challenge requirement.
|
|
73
|
+
* The error carries no amount bytes — caller can read inputs separately.
|
|
74
|
+
*/
|
|
75
|
+
class X402AmountMismatchError extends X402Error {
|
|
76
|
+
name = 'X402AmountMismatchError';
|
|
77
|
+
constructor() {
|
|
78
|
+
super('x402: payment amount exceeds caller cap or does not match challenge');
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
exports.X402AmountMismatchError = X402AmountMismatchError;
|
|
82
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;AAEH,MAAa,SAAU,SAAQ,KAAK;IAChB,IAAI,GAAW,WAAW,CAAC;IAC7C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;IACjB,CAAC;CACF;AALD,8BAKC;AAED;;;GAGG;AACH,MAAa,yBAA0B,SAAQ,SAAS;IACpC,IAAI,GAAW,2BAA2B,CAAC;IAC7D;QACE,KAAK,CAAC,gCAAgC,CAAC,CAAC;IAC1C,CAAC;CACF;AALD,8DAKC;AAED;;;;GAIG;AACH,MAAa,8BAA+B,SAAQ,SAAS;IACzC,IAAI,GAAW,gCAAgC,CAAC;IAClE;QACE,KAAK,CAAC,iDAAiD,CAAC,CAAC;IAC3D,CAAC;CACF;AALD,wEAKC;AAED;;;;GAIG;AACH,MAAa,oBAAqB,SAAQ,SAAS;IAC/B,IAAI,GAAW,sBAAsB,CAAC;IACxD,YAAY,KAAsC;QAChD,KAAK,CAAC,0CAA0C,KAAK,GAAG,CAAC,CAAC;IAC5D,CAAC;CACF;AALD,oDAKC;AAED;;;;GAIG;AACH,MAAa,0BAA2B,SAAQ,SAAS;IACrC,IAAI,GAAW,4BAA4B,CAAC;IAC9D;QACE,KAAK,CAAC,gEAAgE,CAAC,CAAC;IAC1E,CAAC;CACF;AALD,gEAKC;AAED;;;;GAIG;AACH,MAAa,uBAAwB,SAAQ,SAAS;IAClC,IAAI,GAAW,yBAAyB,CAAC;IAC3D;QACE,KAAK,CAAC,qEAAqE,CAAC,CAAC;IAC/E,CAAC;CACF;AALD,0DAKC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Facilitator HTTP client.
|
|
3
|
+
*
|
|
4
|
+
* Two endpoints per the x402 spec:
|
|
5
|
+
* - POST /verify — facilitator validates signature + balance + simulation.
|
|
6
|
+
* - POST /settle — facilitator broadcasts the on-chain settlement tx.
|
|
7
|
+
*
|
|
8
|
+
* Privacy invariants:
|
|
9
|
+
* - We forward only the signed PaymentPayload + the PaymentRequirements. The
|
|
10
|
+
* facilitator never receives the recipient's main wallet — only the
|
|
11
|
+
* freshly derived stealth address (the `payTo` field of the requirements).
|
|
12
|
+
* - We never log request/response bodies. Tags are short strings only.
|
|
13
|
+
* - Auth token (if any) is attached as a Bearer header. We never log the
|
|
14
|
+
* full token; tests verify the header is set but redaction is the
|
|
15
|
+
* operator's responsibility upstream.
|
|
16
|
+
*/
|
|
17
|
+
import type { Hex } from 'viem';
|
|
18
|
+
import { type X402FacilitatorConfig } from './protocol.js';
|
|
19
|
+
export interface FacilitatorVerifyResult {
|
|
20
|
+
readonly isValid: boolean;
|
|
21
|
+
readonly invalidReason?: string;
|
|
22
|
+
readonly payer?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface FacilitatorSettleResult {
|
|
25
|
+
readonly success: boolean;
|
|
26
|
+
readonly txHash?: Hex;
|
|
27
|
+
readonly errorReason?: string;
|
|
28
|
+
readonly payer?: string;
|
|
29
|
+
readonly network?: string;
|
|
30
|
+
}
|
|
31
|
+
/** Resolve the facilitator config, defaulting to PayAI free tier. */
|
|
32
|
+
export declare function resolveFacilitator(config: X402FacilitatorConfig | undefined): X402FacilitatorConfig;
|
|
33
|
+
/**
|
|
34
|
+
* Build standard headers for a facilitator request. When an Ed25519 auth
|
|
35
|
+
* token is configured, attach `Authorization: Bearer <token>`. Otherwise
|
|
36
|
+
* the request hits the PayAI free-tier endpoint (no auth required).
|
|
37
|
+
*/
|
|
38
|
+
export declare function buildFacilitatorHeaders(config: X402FacilitatorConfig): Record<string, string>;
|
|
39
|
+
/**
|
|
40
|
+
* Call the facilitator's `/verify` endpoint. Returns the parsed verification
|
|
41
|
+
* result. Re-wraps every failure path as a tagged X402FacilitatorError so
|
|
42
|
+
* no upstream response body leaks through.
|
|
43
|
+
*/
|
|
44
|
+
export declare function facilitatorVerify(config: X402FacilitatorConfig, body: unknown, fetchImpl?: typeof fetch): Promise<FacilitatorVerifyResult>;
|
|
45
|
+
/**
|
|
46
|
+
* Call the facilitator's `/settle` endpoint. Returns the parsed settle
|
|
47
|
+
* result (including the on-chain tx hash on success).
|
|
48
|
+
*/
|
|
49
|
+
export declare function facilitatorSettle(config: X402FacilitatorConfig, body: unknown, fetchImpl?: typeof fetch): Promise<FacilitatorSettleResult>;
|
|
50
|
+
//# sourceMappingURL=facilitator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facilitator.d.ts","sourceRoot":"","sources":["../../src/facilitator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;AAChC,OAAO,EAAyB,KAAK,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAGlF,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,qEAAqE;AACrE,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,qBAAqB,GAAG,SAAS,GACxC,qBAAqB,CAKvB;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,qBAAqB,GAC5B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CASxB;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,qBAAqB,EAC7B,IAAI,EAAE,OAAO,EACb,SAAS,GAAE,OAAO,KAAa,GAC9B,OAAO,CAAC,uBAAuB,CAAC,CAsBlC;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,qBAAqB,EAC7B,IAAI,EAAE,OAAO,EACb,SAAS,GAAE,OAAO,KAAa,GAC9B,OAAO,CAAC,uBAAuB,CAAC,CAsBlC"}
|