@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.
Files changed (79) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +77 -0
  3. package/dist/cjs/client.d.ts +43 -0
  4. package/dist/cjs/client.d.ts.map +1 -0
  5. package/dist/cjs/client.js +199 -0
  6. package/dist/cjs/client.js.map +1 -0
  7. package/dist/cjs/constants.d.ts +16 -0
  8. package/dist/cjs/constants.d.ts.map +1 -0
  9. package/dist/cjs/constants.js +19 -0
  10. package/dist/cjs/constants.js.map +1 -0
  11. package/dist/cjs/errors.d.ts +61 -0
  12. package/dist/cjs/errors.d.ts.map +1 -0
  13. package/dist/cjs/errors.js +82 -0
  14. package/dist/cjs/errors.js.map +1 -0
  15. package/dist/cjs/facilitator.d.ts +50 -0
  16. package/dist/cjs/facilitator.d.ts.map +1 -0
  17. package/dist/cjs/facilitator.js +106 -0
  18. package/dist/cjs/facilitator.js.map +1 -0
  19. package/dist/cjs/index.d.ts +8 -0
  20. package/dist/cjs/index.d.ts.map +1 -0
  21. package/dist/cjs/index.js +29 -0
  22. package/dist/cjs/index.js.map +1 -0
  23. package/dist/cjs/package.json +1 -0
  24. package/dist/cjs/protocol.d.ts +117 -0
  25. package/dist/cjs/protocol.d.ts.map +1 -0
  26. package/dist/cjs/protocol.js +39 -0
  27. package/dist/cjs/protocol.js.map +1 -0
  28. package/dist/cjs/server.d.ts +49 -0
  29. package/dist/cjs/server.d.ts.map +1 -0
  30. package/dist/cjs/server.js +237 -0
  31. package/dist/cjs/server.js.map +1 -0
  32. package/dist/cjs/signing.d.ts +93 -0
  33. package/dist/cjs/signing.d.ts.map +1 -0
  34. package/dist/cjs/signing.js +170 -0
  35. package/dist/cjs/signing.js.map +1 -0
  36. package/dist/cjs/types.d.ts +93 -0
  37. package/dist/cjs/types.d.ts.map +1 -0
  38. package/dist/cjs/types.js +6 -0
  39. package/dist/cjs/types.js.map +1 -0
  40. package/dist/esm/client.d.ts +43 -0
  41. package/dist/esm/client.d.ts.map +1 -0
  42. package/dist/esm/client.js +196 -0
  43. package/dist/esm/client.js.map +1 -0
  44. package/dist/esm/constants.d.ts +16 -0
  45. package/dist/esm/constants.d.ts.map +1 -0
  46. package/dist/esm/constants.js +16 -0
  47. package/dist/esm/constants.js.map +1 -0
  48. package/dist/esm/errors.d.ts +61 -0
  49. package/dist/esm/errors.d.ts.map +1 -0
  50. package/dist/esm/errors.js +73 -0
  51. package/dist/esm/errors.js.map +1 -0
  52. package/dist/esm/facilitator.d.ts +50 -0
  53. package/dist/esm/facilitator.d.ts.map +1 -0
  54. package/dist/esm/facilitator.js +100 -0
  55. package/dist/esm/facilitator.js.map +1 -0
  56. package/dist/esm/index.d.ts +8 -0
  57. package/dist/esm/index.d.ts.map +1 -0
  58. package/dist/esm/index.js +12 -0
  59. package/dist/esm/index.js.map +1 -0
  60. package/dist/esm/protocol.d.ts +117 -0
  61. package/dist/esm/protocol.d.ts.map +1 -0
  62. package/dist/esm/protocol.js +36 -0
  63. package/dist/esm/protocol.js.map +1 -0
  64. package/dist/esm/server.d.ts +49 -0
  65. package/dist/esm/server.d.ts.map +1 -0
  66. package/dist/esm/server.js +234 -0
  67. package/dist/esm/server.js.map +1 -0
  68. package/dist/esm/signing.d.ts +93 -0
  69. package/dist/esm/signing.d.ts.map +1 -0
  70. package/dist/esm/signing.js +131 -0
  71. package/dist/esm/signing.js.map +1 -0
  72. package/dist/esm/types.d.ts +93 -0
  73. package/dist/esm/types.d.ts.map +1 -0
  74. package/dist/esm/types.js +5 -0
  75. package/dist/esm/types.js.map +1 -0
  76. package/dist/tsconfig.cjs.tsbuildinfo +1 -0
  77. package/dist/tsconfig.esm.tsbuildinfo +1 -0
  78. package/dist/tsconfig.tsbuildinfo +1 -0
  79. package/package.json +64 -0
@@ -0,0 +1,234 @@
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 { decodeMetaAddress } from '@shroud-fi/core';
13
+ import { prepareStealthPayment } from '@shroud-fi/payments';
14
+ import { getUSDC, getUSDCDomain } from '@shroud-fi/transport';
15
+ import { X402_PAYMENT_REQUIRED_HEADER, X402_SCHEME_EXACT, } from './protocol.js';
16
+ import { X402_VERSION, DEFAULT_MAX_TIMEOUT_SECS } from './constants.js';
17
+ import { X402AssetNotSupportedError, X402InvalidChallengeError, } from './errors.js';
18
+ import { facilitatorSettle, facilitatorVerify, resolveFacilitator, } from './facilitator.js';
19
+ import { verifyTransferWithAuthorizationSignature, } from './signing.js';
20
+ /**
21
+ * Encode a CAIP-2 network id from a chain id. EVM only.
22
+ */
23
+ function caip2(chainId) {
24
+ return `eip155:${chainId}`;
25
+ }
26
+ /**
27
+ * Robust bigint coercion that accepts decimal strings, hex strings,
28
+ * numbers, and bigints. Throws X402InvalidChallengeError on anything else.
29
+ */
30
+ function toBigInt(v) {
31
+ if (typeof v === 'bigint')
32
+ return v;
33
+ if (typeof v === 'number')
34
+ return BigInt(v);
35
+ if (typeof v === 'string') {
36
+ try {
37
+ return BigInt(v);
38
+ }
39
+ catch {
40
+ throw new X402InvalidChallengeError();
41
+ }
42
+ }
43
+ throw new X402InvalidChallengeError();
44
+ }
45
+ /**
46
+ * Build an X402Server bound to a single recipient meta-address + asset.
47
+ */
48
+ export function createX402Server(config) {
49
+ // Validate asset is canonical USDC for the chain. Fail-fast at construction.
50
+ const canonicalUsdc = getUSDC(config.chainId);
51
+ const usdcDomain = getUSDCDomain(config.chainId);
52
+ if (canonicalUsdc === undefined || usdcDomain === undefined) {
53
+ throw new X402AssetNotSupportedError();
54
+ }
55
+ if (config.asset.toLowerCase() !== canonicalUsdc.toLowerCase()) {
56
+ throw new X402AssetNotSupportedError();
57
+ }
58
+ // Pre-decode the meta-address ONCE — repeated decodes would waste cycles.
59
+ // The decode validates curve membership; downstream errors become
60
+ // X402InvalidChallengeError.
61
+ let decoded;
62
+ try {
63
+ decoded = decodeMetaAddress(config.recipientMetaAddress);
64
+ }
65
+ catch {
66
+ throw new X402InvalidChallengeError();
67
+ }
68
+ const facilitator = resolveFacilitator(config.facilitator);
69
+ return {
70
+ async challenge({ resource, description, priceAtomic }) {
71
+ const price = priceAtomic ?? config.defaultPriceAtomic;
72
+ // Derive a fresh stealth address per call. prepareStealthPayment hashes
73
+ // a fresh ephemeral key internally — uniqueness is built in.
74
+ const prepared = prepareStealthPayment(decoded);
75
+ const requirements = {
76
+ scheme: X402_SCHEME_EXACT,
77
+ network: caip2(config.chainId),
78
+ maxAmountRequired: price.toString(),
79
+ asset: config.asset,
80
+ payTo: prepared.stealthAddress,
81
+ maxTimeoutSeconds: DEFAULT_MAX_TIMEOUT_SECS,
82
+ resource,
83
+ ...(description !== undefined ? { description } : {}),
84
+ extra: {
85
+ name: usdcDomain.name,
86
+ version: usdcDomain.version,
87
+ shroudfiAnnouncement: {
88
+ ephemeralPubKey: prepared.ephemeralPubKey,
89
+ viewTag: prepared.viewTag,
90
+ },
91
+ },
92
+ };
93
+ const body = {
94
+ x402Version: X402_VERSION,
95
+ error: 'Payment required',
96
+ accepts: [requirements],
97
+ };
98
+ return {
99
+ status: 402,
100
+ headers: {
101
+ [X402_PAYMENT_REQUIRED_HEADER]: JSON.stringify(body),
102
+ 'content-type': 'application/json',
103
+ },
104
+ body,
105
+ announcement: {
106
+ ephemeralPubKey: prepared.ephemeralPubKey,
107
+ viewTag: prepared.viewTag,
108
+ stealthAddress: prepared.stealthAddress,
109
+ },
110
+ };
111
+ },
112
+ async verify({ signedPayload, challenge, skipFacilitator }) {
113
+ // 1. Decode incoming payload.
114
+ let payload;
115
+ if (typeof signedPayload === 'string') {
116
+ try {
117
+ // Spec: header value is base64-encoded JSON.
118
+ const decodedJson = Buffer.from(signedPayload, 'base64').toString('utf-8');
119
+ payload = JSON.parse(decodedJson);
120
+ }
121
+ catch {
122
+ return { valid: false, error: 'malformed_payload' };
123
+ }
124
+ }
125
+ else {
126
+ payload = signedPayload;
127
+ }
128
+ // 2. Structural checks. Tagged failures only — no field values in errors.
129
+ if (payload.x402Version !== 2 ||
130
+ payload.scheme !== X402_SCHEME_EXACT ||
131
+ payload.network !== caip2(config.chainId)) {
132
+ return { valid: false, error: 'scheme_mismatch' };
133
+ }
134
+ const auth = payload.payload?.authorization;
135
+ const sig = payload.payload?.signature;
136
+ if (auth === undefined || sig === undefined) {
137
+ return { valid: false, error: 'malformed_payload' };
138
+ }
139
+ const accepted = challenge.body.accepts[0];
140
+ if (accepted === undefined) {
141
+ return { valid: false, error: 'malformed_challenge' };
142
+ }
143
+ // 3. Authorization fields must address the same stealth `payTo` and the
144
+ // exact required amount.
145
+ let value;
146
+ let validAfter;
147
+ let validBefore;
148
+ try {
149
+ value = toBigInt(auth.value);
150
+ validAfter = toBigInt(auth.validAfter);
151
+ validBefore = toBigInt(auth.validBefore);
152
+ }
153
+ catch {
154
+ return { valid: false, error: 'malformed_payload' };
155
+ }
156
+ if (auth.to.toLowerCase() !== accepted.payTo.toLowerCase()) {
157
+ return { valid: false, error: 'recipient_mismatch' };
158
+ }
159
+ let requiredAmount;
160
+ try {
161
+ requiredAmount = toBigInt(accepted.maxAmountRequired);
162
+ }
163
+ catch {
164
+ return { valid: false, error: 'malformed_challenge' };
165
+ }
166
+ if (value !== requiredAmount) {
167
+ return { valid: false, error: 'amount_mismatch' };
168
+ }
169
+ // 4. Time window.
170
+ const nowSecs = BigInt(Math.floor(Date.now() / 1000));
171
+ if (validBefore <= nowSecs) {
172
+ return { valid: false, error: 'expired' };
173
+ }
174
+ if (validAfter > nowSecs) {
175
+ return { valid: false, error: 'not_yet_valid' };
176
+ }
177
+ // 5. Signature recovery.
178
+ const authInput = {
179
+ from: auth.from,
180
+ to: auth.to,
181
+ value,
182
+ validAfter,
183
+ validBefore,
184
+ nonce: auth.nonce,
185
+ };
186
+ const recovered = await verifyTransferWithAuthorizationSignature({
187
+ chainId: config.chainId,
188
+ verifyingContract: config.asset,
189
+ authorization: authInput,
190
+ signature: sig,
191
+ });
192
+ if (recovered === null ||
193
+ recovered.toLowerCase() !== auth.from.toLowerCase()) {
194
+ return { valid: false, error: 'signature_invalid' };
195
+ }
196
+ // 6a. Self-settle mode: caller handles on-chain settlement, we return
197
+ // valid:true after signature recovery. No facilitator contact.
198
+ if (skipFacilitator === true) {
199
+ return { valid: true };
200
+ }
201
+ // 6b. Facilitator submission. Caller gets the settled tx hash.
202
+ // We send the facilitator only what it needs: the requirements + the
203
+ // signed payload. The recipient's main wallet is never in this body
204
+ // because `accepted.payTo` is the freshly derived stealth address.
205
+ try {
206
+ const verifyResult = await facilitatorVerify(facilitator, {
207
+ x402Version: X402_VERSION,
208
+ paymentRequirements: accepted,
209
+ paymentPayload: payload,
210
+ });
211
+ if (!verifyResult.isValid) {
212
+ return { valid: false, error: 'facilitator_rejected' };
213
+ }
214
+ const settle = await facilitatorSettle(facilitator, {
215
+ x402Version: X402_VERSION,
216
+ paymentRequirements: accepted,
217
+ paymentPayload: payload,
218
+ });
219
+ if (!settle.success || settle.txHash === undefined) {
220
+ return { valid: false, error: 'facilitator_settle_failed' };
221
+ }
222
+ return { valid: true, settledTxHash: settle.txHash };
223
+ }
224
+ catch {
225
+ // Facilitator unreachable / non-2xx. Return signature-verified=true
226
+ // so the caller can decide whether to retry or fall back. The signed
227
+ // payload remains cryptographically valid even when the facilitator
228
+ // path failed.
229
+ return { valid: false, error: 'facilitator_unreachable' };
230
+ }
231
+ },
232
+ };
233
+ }
234
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * EIP-3009 `TransferWithAuthorization` typed-data signing for x402.
3
+ *
4
+ * Privacy invariants:
5
+ * - The private key never leaves the viem `account` object. We do not
6
+ * extract it, log it, or attach it to errors.
7
+ * - The signed payload (`signature`, `nonce`, `value`) is never logged,
8
+ * stringified into errors, or stored. Caller is responsible for sending
9
+ * it directly to the server in the `X-PAYMENT` header.
10
+ * - `nonce` is a fresh 32 bytes per call via `crypto.getRandomValues`,
11
+ * never reused.
12
+ */
13
+ import type { Account, Address, Chain, Hex } from 'viem';
14
+ /**
15
+ * EIP-3009 `TransferWithAuthorization` typed-data types.
16
+ * Exported for tests; the runtime signer constructs the same object inline.
17
+ */
18
+ export declare const TransferWithAuthorizationTypes: {
19
+ readonly TransferWithAuthorization: readonly [{
20
+ readonly name: "from";
21
+ readonly type: "address";
22
+ }, {
23
+ readonly name: "to";
24
+ readonly type: "address";
25
+ }, {
26
+ readonly name: "value";
27
+ readonly type: "uint256";
28
+ }, {
29
+ readonly name: "validAfter";
30
+ readonly type: "uint256";
31
+ }, {
32
+ readonly name: "validBefore";
33
+ readonly type: "uint256";
34
+ }, {
35
+ readonly name: "nonce";
36
+ readonly type: "bytes32";
37
+ }];
38
+ };
39
+ /**
40
+ * The cleartext authorization fields. Caller passes them in; signer hashes,
41
+ * signs, and returns both signature + the authorization (so the caller can
42
+ * forward the unsigned data alongside the signature).
43
+ */
44
+ export interface TransferWithAuthorizationInput {
45
+ readonly from: Address;
46
+ readonly to: Address;
47
+ readonly value: bigint;
48
+ readonly validAfter: bigint;
49
+ readonly validBefore: bigint;
50
+ readonly nonce: Hex;
51
+ }
52
+ export interface SignedTransferWithAuthorization {
53
+ readonly signature: Hex;
54
+ readonly nonce: Hex;
55
+ readonly from: Address;
56
+ readonly to: Address;
57
+ readonly value: bigint;
58
+ readonly validAfter: bigint;
59
+ readonly validBefore: bigint;
60
+ }
61
+ /**
62
+ * Generate a fresh 32-byte nonce for EIP-3009. Uses Web Crypto (available in
63
+ * Node 20+ and all browsers). Never reuse — each authorization needs a
64
+ * unique nonce to avoid replay.
65
+ */
66
+ export declare function generateAuthorizationNonce(): Hex;
67
+ /**
68
+ * Sign an EIP-3009 `TransferWithAuthorization` over USDC. Returns the
69
+ * 65-byte signature + the authorization fields the server will replay.
70
+ *
71
+ * @throws X402AssetNotSupportedError if USDC is not configured for this chain.
72
+ */
73
+ export declare function signTransferWithAuthorization(args: {
74
+ readonly account: Account;
75
+ readonly chain: Chain;
76
+ readonly verifyingContract: Address;
77
+ readonly input: TransferWithAuthorizationInput;
78
+ }): Promise<SignedTransferWithAuthorization>;
79
+ /**
80
+ * Verify a `TransferWithAuthorization` signature on the server side.
81
+ * Returns the recovered signer address (`from`) or `null` on failure.
82
+ *
83
+ * NOTE: we do NOT throw on failure — caller maps `null` → verify.valid=false
84
+ * with an error tag. Throwing here would risk leaking signature bytes via
85
+ * thrown error stacks.
86
+ */
87
+ export declare function verifyTransferWithAuthorizationSignature(args: {
88
+ readonly chainId: number;
89
+ readonly verifyingContract: Address;
90
+ readonly authorization: TransferWithAuthorizationInput;
91
+ readonly signature: Hex;
92
+ }): Promise<Address | null>;
93
+ //# sourceMappingURL=signing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signing.d.ts","sourceRoot":"","sources":["../../src/signing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;AAIzD;;;GAGG;AACH,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;;;CASjC,CAAC;AAEX;;;;GAIG;AACH,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC;CACrB;AAED,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,IAAI,GAAG,CAUhD;AAED;;;;;GAKG;AACH,wBAAsB,6BAA6B,CAAC,IAAI,EAAE;IACxD,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,8BAA8B,CAAC;CAChD,GAAG,OAAO,CAAC,+BAA+B,CAAC,CA4C3C;AAED;;;;;;;GAOG;AACH,wBAAsB,wCAAwC,CAAC,IAAI,EAAE;IACnE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC;IACpC,QAAQ,CAAC,aAAa,EAAE,8BAA8B,CAAC;IACvD,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC;CACzB,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CA6B1B"}
@@ -0,0 +1,131 @@
1
+ /**
2
+ * EIP-3009 `TransferWithAuthorization` typed-data signing for x402.
3
+ *
4
+ * Privacy invariants:
5
+ * - The private key never leaves the viem `account` object. We do not
6
+ * extract it, log it, or attach it to errors.
7
+ * - The signed payload (`signature`, `nonce`, `value`) is never logged,
8
+ * stringified into errors, or stored. Caller is responsible for sending
9
+ * it directly to the server in the `X-PAYMENT` header.
10
+ * - `nonce` is a fresh 32 bytes per call via `crypto.getRandomValues`,
11
+ * never reused.
12
+ */
13
+ import { getUSDCDomain } from '@shroud-fi/transport';
14
+ import { X402AssetNotSupportedError } from './errors.js';
15
+ /**
16
+ * EIP-3009 `TransferWithAuthorization` typed-data types.
17
+ * Exported for tests; the runtime signer constructs the same object inline.
18
+ */
19
+ export const TransferWithAuthorizationTypes = {
20
+ TransferWithAuthorization: [
21
+ { name: 'from', type: 'address' },
22
+ { name: 'to', type: 'address' },
23
+ { name: 'value', type: 'uint256' },
24
+ { name: 'validAfter', type: 'uint256' },
25
+ { name: 'validBefore', type: 'uint256' },
26
+ { name: 'nonce', type: 'bytes32' },
27
+ ],
28
+ };
29
+ /**
30
+ * Generate a fresh 32-byte nonce for EIP-3009. Uses Web Crypto (available in
31
+ * Node 20+ and all browsers). Never reuse — each authorization needs a
32
+ * unique nonce to avoid replay.
33
+ */
34
+ export function generateAuthorizationNonce() {
35
+ const bytes = new Uint8Array(32);
36
+ // Web Crypto is globally available on Node 20+; deliberately not using
37
+ // `node:crypto.randomBytes` so the module stays runtime-agnostic.
38
+ globalThis.crypto.getRandomValues(bytes);
39
+ let hex = '0x';
40
+ for (const b of bytes) {
41
+ hex += b.toString(16).padStart(2, '0');
42
+ }
43
+ return hex;
44
+ }
45
+ /**
46
+ * Sign an EIP-3009 `TransferWithAuthorization` over USDC. Returns the
47
+ * 65-byte signature + the authorization fields the server will replay.
48
+ *
49
+ * @throws X402AssetNotSupportedError if USDC is not configured for this chain.
50
+ */
51
+ export async function signTransferWithAuthorization(args) {
52
+ const { account, chain, verifyingContract, input } = args;
53
+ const usdcDomain = getUSDCDomain(chain.id);
54
+ if (usdcDomain === undefined) {
55
+ throw new X402AssetNotSupportedError();
56
+ }
57
+ const domain = {
58
+ name: usdcDomain.name,
59
+ version: usdcDomain.version,
60
+ chainId: chain.id,
61
+ verifyingContract,
62
+ };
63
+ if (account.signTypedData === undefined) {
64
+ // Local account; viem provides .signTypedData for privateKeyToAccount.
65
+ // For JSON-RPC accounts the caller must provide a wrapper. Treat as
66
+ // unsupported configuration rather than leaking the underlying error.
67
+ throw new X402AssetNotSupportedError();
68
+ }
69
+ const signature = await account.signTypedData({
70
+ domain,
71
+ types: TransferWithAuthorizationTypes,
72
+ primaryType: 'TransferWithAuthorization',
73
+ message: {
74
+ from: input.from,
75
+ to: input.to,
76
+ value: input.value,
77
+ validAfter: input.validAfter,
78
+ validBefore: input.validBefore,
79
+ nonce: input.nonce,
80
+ },
81
+ });
82
+ return {
83
+ signature,
84
+ nonce: input.nonce,
85
+ from: input.from,
86
+ to: input.to,
87
+ value: input.value,
88
+ validAfter: input.validAfter,
89
+ validBefore: input.validBefore,
90
+ };
91
+ }
92
+ /**
93
+ * Verify a `TransferWithAuthorization` signature on the server side.
94
+ * Returns the recovered signer address (`from`) or `null` on failure.
95
+ *
96
+ * NOTE: we do NOT throw on failure — caller maps `null` → verify.valid=false
97
+ * with an error tag. Throwing here would risk leaking signature bytes via
98
+ * thrown error stacks.
99
+ */
100
+ export async function verifyTransferWithAuthorizationSignature(args) {
101
+ const { chainId, verifyingContract, authorization, signature } = args;
102
+ const usdcDomain = getUSDCDomain(chainId);
103
+ if (usdcDomain === undefined)
104
+ return null;
105
+ const { recoverTypedDataAddress } = await import('viem');
106
+ try {
107
+ return await recoverTypedDataAddress({
108
+ domain: {
109
+ name: usdcDomain.name,
110
+ version: usdcDomain.version,
111
+ chainId,
112
+ verifyingContract,
113
+ },
114
+ types: TransferWithAuthorizationTypes,
115
+ primaryType: 'TransferWithAuthorization',
116
+ message: {
117
+ from: authorization.from,
118
+ to: authorization.to,
119
+ value: authorization.value,
120
+ validAfter: authorization.validAfter,
121
+ validBefore: authorization.validBefore,
122
+ nonce: authorization.nonce,
123
+ },
124
+ signature,
125
+ });
126
+ }
127
+ catch {
128
+ return null;
129
+ }
130
+ }
131
+ //# sourceMappingURL=signing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signing.js","sourceRoot":"","sources":["../../src/signing.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Shared types used by both server and client.
3
+ */
4
+ import type { Address, Hex } from 'viem';
5
+ import type { X402FacilitatorConfig, X402PaymentRequirements } from './protocol.js';
6
+ /**
7
+ * Hint object returned alongside a freshly generated challenge.
8
+ *
9
+ * The server uses these values to emit an ERC-5564 Announcement event AFTER
10
+ * the payment settles (out-of-scope for this milestone — operator wires the
11
+ * on-chain emit). Carrying it on the challenge object lets the server
12
+ * correlate "this challenge → this announcement" without re-derivation.
13
+ *
14
+ * Privacy: contains only the ephemeral public key + view tag + the freshly
15
+ * derived stealth address. None of these leak the recipient's main wallet.
16
+ */
17
+ export interface X402StealthAnnouncementHint {
18
+ readonly ephemeralPubKey: Hex;
19
+ readonly viewTag: number;
20
+ readonly stealthAddress: Address;
21
+ }
22
+ /**
23
+ * The full server-side challenge object. Comes out of `x402.challenge(...)`.
24
+ *
25
+ * `status` + `headers` + `body` are wire-shaped — operator's HTTP framework
26
+ * adapter simply spreads them onto its response. `announcement` is internal
27
+ * metadata for the operator's scanner integration.
28
+ */
29
+ export interface X402Challenge {
30
+ readonly status: 402;
31
+ readonly headers: Readonly<Record<string, string>>;
32
+ readonly body: {
33
+ readonly x402Version: 2;
34
+ readonly error: string;
35
+ readonly accepts: readonly X402PaymentRequirements[];
36
+ };
37
+ readonly announcement: X402StealthAnnouncementHint;
38
+ }
39
+ /**
40
+ * Result of `x402.verify(...)`.
41
+ *
42
+ * Privacy: no amount, no signature, no nonce. `error` is a short tag string
43
+ * only ('signature_invalid', 'amount_mismatch', 'expired', etc) — never the
44
+ * full underlying error or any bytes.
45
+ */
46
+ export interface X402PaymentVerification {
47
+ readonly valid: boolean;
48
+ readonly settledTxHash?: Hex;
49
+ readonly error?: string;
50
+ }
51
+ /**
52
+ * `createX402Server` config.
53
+ *
54
+ * Privacy: the `recipientMetaAddress` is the server agent's PUBLIC meta-address
55
+ * (`st:base:0x...`). No private keys ever appear in this config.
56
+ */
57
+ export interface X402ServerConfig {
58
+ /** Transport for reads + chain id lookups. */
59
+ readonly transport: import('@shroud-fi/transport').ShroudFiTransport;
60
+ /** ERC-6538 meta-address string (`st:base:0x...`) for the receiving agent. */
61
+ readonly recipientMetaAddress: string;
62
+ /** ERC-20 asset address (must be the canonical USDC for the chain). */
63
+ readonly asset: Address;
64
+ /** EVM chain id (must match the asset's deployment). */
65
+ readonly chainId: number;
66
+ /** Default price in token base units (uint256). */
67
+ readonly defaultPriceAtomic: bigint;
68
+ /** Optional facilitator override; defaults to PayAI free-tier. */
69
+ readonly facilitator?: X402FacilitatorConfig;
70
+ }
71
+ /**
72
+ * `createX402Client` config.
73
+ *
74
+ * Privacy: the client uses the transport's `walletClient.account` for
75
+ * signing. The private key never appears here directly — it lives inside
76
+ * the viem account, scoped to the transport's lifetime.
77
+ */
78
+ export interface X402ClientConfig {
79
+ /** Transport with a configured `walletClient` (account required). */
80
+ readonly transport: import('@shroud-fi/transport').ShroudFiTransport;
81
+ /** Optional facilitator override; defaults to PayAI free-tier. */
82
+ readonly facilitator?: X402FacilitatorConfig;
83
+ }
84
+ /**
85
+ * What a client `.fetch(...)` call surfaces beyond the standard Response.
86
+ * Non-standard `x402Settlement` property is attached when the server returned
87
+ * `X-PAYMENT-RESPONSE`. Optional — present only on successful auto-pay.
88
+ */
89
+ export interface X402PaymentResult {
90
+ readonly txHash: Hex;
91
+ readonly settledAt: number;
92
+ }
93
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;AACzC,OAAO,KAAK,EACV,qBAAqB,EACrB,uBAAuB,EACxB,MAAM,eAAe,CAAC;AAEvB;;;;;;;;;;GAUG;AACH,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,eAAe,EAAE,GAAG,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;CAClC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACnD,QAAQ,CAAC,IAAI,EAAE;QACb,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;QACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,OAAO,EAAE,SAAS,uBAAuB,EAAE,CAAC;KACtD,CAAC;IACF,QAAQ,CAAC,YAAY,EAAE,2BAA2B,CAAC;CACpD;AAED;;;;;;GAMG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,aAAa,CAAC,EAAE,GAAG,CAAC;IAC7B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,8CAA8C;IAC9C,QAAQ,CAAC,SAAS,EAAE,OAAO,sBAAsB,EAAE,iBAAiB,CAAC;IACrE,8EAA8E;IAC9E,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC,uEAAuE;IACvE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,wDAAwD;IACxD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,mDAAmD;IACnD,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,kEAAkE;IAClE,QAAQ,CAAC,WAAW,CAAC,EAAE,qBAAqB,CAAC;CAC9C;AAED;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC/B,qEAAqE;IACrE,QAAQ,CAAC,SAAS,EAAE,OAAO,sBAAsB,EAAE,iBAAiB,CAAC;IACrE,kEAAkE;IAClE,QAAQ,CAAC,WAAW,CAAC,EAAE,qBAAqB,CAAC;CAC9C;AAED;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC;IACrB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Shared types used by both server and client.
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}