@402lane/core 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/README.md ADDED
@@ -0,0 +1,19 @@
1
+ # @402lane/core
2
+
3
+ Protocol types, header codecs, network config, and EIP-3009 typed data for
4
+ [402LANE](https://402lane.vercel.app) — the x402 agent-payments toolkit for the
5
+ Robinhood Chain (USDG, chain 4663).
6
+
7
+ Ships the x402 v2 wire types (`exact` scheme), base64-JSON `PAYMENT-*` header
8
+ encode/decode, the Robinhood Chain mainnet (`eip155:4663`) and testnet (`eip155:46630`)
9
+ network config with USDG addresses, and the `TransferWithAuthorization`
10
+ EIP-712 typed-data helpers.
11
+
12
+ ```ts
13
+ import { getNetwork, encodeHeader, toBaseUnits } from "@402lane/core";
14
+ const net = getNetwork("eip155:4663"); // USDG, 6 decimals, EIP-712 domain
15
+ toBaseUnits("0.001"); // "1000"
16
+ ```
17
+
18
+ Used by `@402lane/facilitator`, `@402lane/middleware`, and `@402lane/client`.
19
+ See the [docs](https://402lane.vercel.app/docs). MIT.
@@ -0,0 +1,4 @@
1
+ /** Convert a decimal USDG string (e.g. "0.001") to base units (6 decimals). */
2
+ export declare function toBaseUnits(amount: string, decimals?: number): string;
3
+ /** Format base units back to a decimal string for display. */
4
+ export declare function fromBaseUnits(base: string | bigint, decimals?: number): string;
package/dist/amount.js ADDED
@@ -0,0 +1,20 @@
1
+ /** Convert a decimal USDG string (e.g. "0.001") to base units (6 decimals). */
2
+ export function toBaseUnits(amount, decimals = 6) {
3
+ const m = amount.trim().match(/^(\d+)(?:\.(\d+))?$/);
4
+ if (!m)
5
+ throw new Error(`402LANE: invalid amount "${amount}"`);
6
+ const [, whole, fracRaw = ""] = m;
7
+ if (fracRaw.length > decimals) {
8
+ throw new Error(`402LANE: amount "${amount}" exceeds ${decimals} decimal places`);
9
+ }
10
+ const frac = fracRaw.padEnd(decimals, "0");
11
+ return (BigInt(whole) * 10n ** BigInt(decimals) + BigInt(frac)).toString();
12
+ }
13
+ /** Format base units back to a decimal string for display. */
14
+ export function fromBaseUnits(base, decimals = 6) {
15
+ const b = BigInt(base);
16
+ const div = 10n ** BigInt(decimals);
17
+ const whole = b / div;
18
+ const frac = (b % div).toString().padStart(decimals, "0").replace(/0+$/, "");
19
+ return frac ? `${whole}.${frac}` : whole.toString();
20
+ }
@@ -0,0 +1,93 @@
1
+ import type { TypedDataDomain } from "viem";
2
+ import type { Eip3009Authorization } from "./protocol.js";
3
+ export declare const TRANSFER_WITH_AUTHORIZATION_TYPES: {
4
+ readonly TransferWithAuthorization: readonly [{
5
+ readonly name: "from";
6
+ readonly type: "address";
7
+ }, {
8
+ readonly name: "to";
9
+ readonly type: "address";
10
+ }, {
11
+ readonly name: "value";
12
+ readonly type: "uint256";
13
+ }, {
14
+ readonly name: "validAfter";
15
+ readonly type: "uint256";
16
+ }, {
17
+ readonly name: "validBefore";
18
+ readonly type: "uint256";
19
+ }, {
20
+ readonly name: "nonce";
21
+ readonly type: "bytes32";
22
+ }];
23
+ };
24
+ export declare function eip3009Domain(networkCaip2: string): TypedDataDomain;
25
+ /** Typed-data message from a wire authorization (string ints → bigint). */
26
+ export declare function toTypedMessage(auth: Eip3009Authorization): {
27
+ from: `0x${string}`;
28
+ to: `0x${string}`;
29
+ value: bigint;
30
+ validAfter: bigint;
31
+ validBefore: bigint;
32
+ nonce: `0x${string}`;
33
+ };
34
+ /** Minimal ABI surface of USDG needed by the facilitator. */
35
+ export declare const EIP3009_ABI: readonly [{
36
+ readonly type: "function";
37
+ readonly name: "balanceOf";
38
+ readonly stateMutability: "view";
39
+ readonly inputs: readonly [{
40
+ readonly name: "account";
41
+ readonly type: "address";
42
+ }];
43
+ readonly outputs: readonly [{
44
+ readonly type: "uint256";
45
+ }];
46
+ }, {
47
+ readonly type: "function";
48
+ readonly name: "authorizationState";
49
+ readonly stateMutability: "view";
50
+ readonly inputs: readonly [{
51
+ readonly name: "authorizer";
52
+ readonly type: "address";
53
+ }, {
54
+ readonly name: "nonce";
55
+ readonly type: "bytes32";
56
+ }];
57
+ readonly outputs: readonly [{
58
+ readonly type: "bool";
59
+ }];
60
+ }, {
61
+ readonly type: "function";
62
+ readonly name: "transferWithAuthorization";
63
+ readonly stateMutability: "nonpayable";
64
+ readonly inputs: readonly [{
65
+ readonly name: "from";
66
+ readonly type: "address";
67
+ }, {
68
+ readonly name: "to";
69
+ readonly type: "address";
70
+ }, {
71
+ readonly name: "value";
72
+ readonly type: "uint256";
73
+ }, {
74
+ readonly name: "validAfter";
75
+ readonly type: "uint256";
76
+ }, {
77
+ readonly name: "validBefore";
78
+ readonly type: "uint256";
79
+ }, {
80
+ readonly name: "nonce";
81
+ readonly type: "bytes32";
82
+ }, {
83
+ readonly name: "v";
84
+ readonly type: "uint8";
85
+ }, {
86
+ readonly name: "r";
87
+ readonly type: "bytes32";
88
+ }, {
89
+ readonly name: "s";
90
+ readonly type: "bytes32";
91
+ }];
92
+ readonly outputs: readonly [];
93
+ }];
@@ -0,0 +1,68 @@
1
+ import { getNetwork } from "./networks.js";
2
+ export const TRANSFER_WITH_AUTHORIZATION_TYPES = {
3
+ TransferWithAuthorization: [
4
+ { name: "from", type: "address" },
5
+ { name: "to", type: "address" },
6
+ { name: "value", type: "uint256" },
7
+ { name: "validAfter", type: "uint256" },
8
+ { name: "validBefore", type: "uint256" },
9
+ { name: "nonce", type: "bytes32" },
10
+ ],
11
+ };
12
+ export function eip3009Domain(networkCaip2) {
13
+ const net = getNetwork(networkCaip2);
14
+ return {
15
+ name: net.eip712.name,
16
+ version: net.eip712.version,
17
+ chainId: net.chain.id,
18
+ verifyingContract: net.asset,
19
+ };
20
+ }
21
+ /** Typed-data message from a wire authorization (string ints → bigint). */
22
+ export function toTypedMessage(auth) {
23
+ return {
24
+ from: auth.from,
25
+ to: auth.to,
26
+ value: BigInt(auth.value),
27
+ validAfter: BigInt(auth.validAfter),
28
+ validBefore: BigInt(auth.validBefore),
29
+ nonce: auth.nonce,
30
+ };
31
+ }
32
+ /** Minimal ABI surface of USDG needed by the facilitator. */
33
+ export const EIP3009_ABI = [
34
+ {
35
+ type: "function",
36
+ name: "balanceOf",
37
+ stateMutability: "view",
38
+ inputs: [{ name: "account", type: "address" }],
39
+ outputs: [{ type: "uint256" }],
40
+ },
41
+ {
42
+ type: "function",
43
+ name: "authorizationState",
44
+ stateMutability: "view",
45
+ inputs: [
46
+ { name: "authorizer", type: "address" },
47
+ { name: "nonce", type: "bytes32" },
48
+ ],
49
+ outputs: [{ type: "bool" }],
50
+ },
51
+ {
52
+ type: "function",
53
+ name: "transferWithAuthorization",
54
+ stateMutability: "nonpayable",
55
+ inputs: [
56
+ { name: "from", type: "address" },
57
+ { name: "to", type: "address" },
58
+ { name: "value", type: "uint256" },
59
+ { name: "validAfter", type: "uint256" },
60
+ { name: "validBefore", type: "uint256" },
61
+ { name: "nonce", type: "bytes32" },
62
+ { name: "v", type: "uint8" },
63
+ { name: "r", type: "bytes32" },
64
+ { name: "s", type: "bytes32" },
65
+ ],
66
+ outputs: [],
67
+ },
68
+ ];
@@ -0,0 +1,4 @@
1
+ export * from "./networks.js";
2
+ export * from "./protocol.js";
3
+ export * from "./eip3009.js";
4
+ export * from "./amount.js";
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export * from "./networks.js";
2
+ export * from "./protocol.js";
3
+ export * from "./eip3009.js";
4
+ export * from "./amount.js";
@@ -0,0 +1,120 @@
1
+ import { type Chain } from "viem";
2
+ /** CAIP-2 network identifiers serviced by 402LANE (Robinhood Chain). */
3
+ export declare const RH_MAINNET_CAIP2: "eip155:4663";
4
+ export declare const RH_TESTNET_CAIP2: "eip155:46630";
5
+ export type SupportedNetwork = typeof RH_MAINNET_CAIP2 | typeof RH_TESTNET_CAIP2;
6
+ export interface NetworkConfig {
7
+ caip2: SupportedNetwork;
8
+ chain: Chain;
9
+ /** USDG (Global Dollar) — the EIP-3009 settlement token. Gas is ETH. */
10
+ asset: `0x${string}`;
11
+ /** EIP-712 domain for EIP-3009 signatures over USDG. */
12
+ eip712: {
13
+ name: string;
14
+ version: string;
15
+ };
16
+ decimals: number;
17
+ explorerTx: (hash: string) => string;
18
+ }
19
+ export declare const robinhoodMainnet: {
20
+ blockExplorers: {
21
+ readonly default: {
22
+ readonly name: "Blockscout";
23
+ readonly url: "https://robinhoodchain.blockscout.com";
24
+ };
25
+ };
26
+ blockTime?: number | undefined | undefined;
27
+ contracts?: {
28
+ [x: string]: import("viem").ChainContract | {
29
+ [sourceId: number]: import("viem").ChainContract | undefined;
30
+ } | undefined;
31
+ ensRegistry?: import("viem").ChainContract | undefined;
32
+ ensUniversalResolver?: import("viem").ChainContract | undefined;
33
+ multicall3?: import("viem").ChainContract | undefined;
34
+ erc6492Verifier?: import("viem").ChainContract | undefined;
35
+ } | undefined;
36
+ ensTlds?: readonly string[] | undefined;
37
+ id: 4663;
38
+ name: "Robinhood Chain";
39
+ nativeCurrency: {
40
+ readonly name: "Ether";
41
+ readonly symbol: "ETH";
42
+ readonly decimals: 18;
43
+ };
44
+ experimental_preconfirmationTime?: number | undefined | undefined;
45
+ rpcUrls: {
46
+ readonly default: {
47
+ readonly http: readonly ["https://rpc.mainnet.chain.robinhood.com"];
48
+ };
49
+ };
50
+ sourceId?: number | undefined | undefined;
51
+ supportsTransactionReplacementDetection?: boolean | undefined | undefined;
52
+ testnet?: boolean | undefined | undefined;
53
+ custom?: Record<string, unknown> | undefined;
54
+ extendSchema?: Record<string, unknown> | undefined;
55
+ fees?: import("viem").ChainFees<undefined> | undefined;
56
+ formatters?: undefined;
57
+ prepareTransactionRequest?: ((args: import("viem").PrepareTransactionRequestParameters, options: {
58
+ client: import("viem").Client;
59
+ phase: "beforeFillTransaction" | "beforeFillParameters" | "afterFillParameters";
60
+ }) => Promise<import("viem").PrepareTransactionRequestParameters>) | [fn: ((args: import("viem").PrepareTransactionRequestParameters, options: {
61
+ client: import("viem").Client;
62
+ phase: "beforeFillTransaction" | "beforeFillParameters" | "afterFillParameters";
63
+ }) => Promise<import("viem").PrepareTransactionRequestParameters>) | undefined, options: {
64
+ runAt: readonly ("beforeFillTransaction" | "beforeFillParameters" | "afterFillParameters")[];
65
+ }] | undefined;
66
+ serializers?: import("viem").ChainSerializers<undefined, import("viem").TransactionSerializable> | undefined;
67
+ verifyHash?: ((client: import("viem").Client, parameters: import("viem").VerifyHashActionParameters) => Promise<import("viem").VerifyHashActionReturnType>) | undefined;
68
+ };
69
+ export declare const robinhoodTestnet: {
70
+ blockExplorers: {
71
+ readonly default: {
72
+ readonly name: "Blockscout";
73
+ readonly url: "https://explorer.testnet.chain.robinhood.com";
74
+ };
75
+ };
76
+ blockTime?: number | undefined | undefined;
77
+ contracts?: {
78
+ [x: string]: import("viem").ChainContract | {
79
+ [sourceId: number]: import("viem").ChainContract | undefined;
80
+ } | undefined;
81
+ ensRegistry?: import("viem").ChainContract | undefined;
82
+ ensUniversalResolver?: import("viem").ChainContract | undefined;
83
+ multicall3?: import("viem").ChainContract | undefined;
84
+ erc6492Verifier?: import("viem").ChainContract | undefined;
85
+ } | undefined;
86
+ ensTlds?: readonly string[] | undefined;
87
+ id: 46630;
88
+ name: "Robinhood Chain Testnet";
89
+ nativeCurrency: {
90
+ readonly name: "Ether";
91
+ readonly symbol: "ETH";
92
+ readonly decimals: 18;
93
+ };
94
+ experimental_preconfirmationTime?: number | undefined | undefined;
95
+ rpcUrls: {
96
+ readonly default: {
97
+ readonly http: readonly ["https://rpc.testnet.chain.robinhood.com"];
98
+ };
99
+ };
100
+ sourceId?: number | undefined | undefined;
101
+ supportsTransactionReplacementDetection?: boolean | undefined | undefined;
102
+ testnet: true;
103
+ custom?: Record<string, unknown> | undefined;
104
+ extendSchema?: Record<string, unknown> | undefined;
105
+ fees?: import("viem").ChainFees<undefined> | undefined;
106
+ formatters?: undefined;
107
+ prepareTransactionRequest?: ((args: import("viem").PrepareTransactionRequestParameters, options: {
108
+ client: import("viem").Client;
109
+ phase: "beforeFillTransaction" | "beforeFillParameters" | "afterFillParameters";
110
+ }) => Promise<import("viem").PrepareTransactionRequestParameters>) | [fn: ((args: import("viem").PrepareTransactionRequestParameters, options: {
111
+ client: import("viem").Client;
112
+ phase: "beforeFillTransaction" | "beforeFillParameters" | "afterFillParameters";
113
+ }) => Promise<import("viem").PrepareTransactionRequestParameters>) | undefined, options: {
114
+ runAt: readonly ("beforeFillTransaction" | "beforeFillParameters" | "afterFillParameters")[];
115
+ }] | undefined;
116
+ serializers?: import("viem").ChainSerializers<undefined, import("viem").TransactionSerializable> | undefined;
117
+ verifyHash?: ((client: import("viem").Client, parameters: import("viem").VerifyHashActionParameters) => Promise<import("viem").VerifyHashActionReturnType>) | undefined;
118
+ };
119
+ export declare const NETWORKS: Record<SupportedNetwork, NetworkConfig>;
120
+ export declare function getNetwork(caip2: string): NetworkConfig;
@@ -0,0 +1,56 @@
1
+ import { defineChain } from "viem";
2
+ /** CAIP-2 network identifiers serviced by 402LANE (Robinhood Chain). */
3
+ export const RH_MAINNET_CAIP2 = "eip155:4663";
4
+ export const RH_TESTNET_CAIP2 = "eip155:46630";
5
+ // Robinhood Chain is an Arbitrum Orbit (Nitro) L2. Gas is paid in ETH;
6
+ // USDG is a normal ERC-20 that implements EIP-3009 transferWithAuthorization.
7
+ export const robinhoodMainnet = defineChain({
8
+ id: 4663,
9
+ name: "Robinhood Chain",
10
+ nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
11
+ rpcUrls: { default: { http: ["https://rpc.mainnet.chain.robinhood.com"] } },
12
+ blockExplorers: {
13
+ default: { name: "Blockscout", url: "https://robinhoodchain.blockscout.com" },
14
+ },
15
+ });
16
+ export const robinhoodTestnet = defineChain({
17
+ id: 46630,
18
+ name: "Robinhood Chain Testnet",
19
+ nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
20
+ rpcUrls: { default: { http: ["https://rpc.testnet.chain.robinhood.com"] } },
21
+ blockExplorers: {
22
+ default: {
23
+ name: "Blockscout",
24
+ url: "https://explorer.testnet.chain.robinhood.com",
25
+ },
26
+ },
27
+ testnet: true,
28
+ });
29
+ export const NETWORKS = {
30
+ [RH_MAINNET_CAIP2]: {
31
+ caip2: RH_MAINNET_CAIP2,
32
+ chain: robinhoodMainnet,
33
+ // USDG on Robinhood Chain (Paxos Global Dollar). EIP-712 domain verified
34
+ // against the live on-chain DOMAIN_SEPARATOR.
35
+ asset: "0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168",
36
+ eip712: { name: "Global Dollar", version: "1" },
37
+ decimals: 6,
38
+ explorerTx: (h) => `https://robinhoodchain.blockscout.com/tx/${h}`,
39
+ },
40
+ [RH_TESTNET_CAIP2]: {
41
+ caip2: RH_TESTNET_CAIP2,
42
+ chain: robinhoodTestnet,
43
+ // TODO: USDG testnet contract address (not yet pinned). Mainnet is the
44
+ // supported target; testnet requires the deployed USDG testnet address.
45
+ asset: "0x0000000000000000000000000000000000000000",
46
+ eip712: { name: "Global Dollar", version: "1" },
47
+ decimals: 6,
48
+ explorerTx: (h) => `https://explorer.testnet.chain.robinhood.com/tx/${h}`,
49
+ },
50
+ };
51
+ export function getNetwork(caip2) {
52
+ const cfg = NETWORKS[caip2];
53
+ if (!cfg)
54
+ throw new Error(`402LANE: unsupported network "${caip2}"`);
55
+ return cfg;
56
+ }
@@ -0,0 +1,276 @@
1
+ import { z } from "zod";
2
+ /** x402 v2 wire types (exact scheme, EVM / EIP-3009). */
3
+ export declare const X402_VERSION = 2;
4
+ /** HTTP headers used by the protocol. Values are base64-encoded JSON. */
5
+ export declare const HEADER_PAYMENT_REQUIRED = "payment-required";
6
+ export declare const HEADER_PAYMENT_SIGNATURE = "payment-signature";
7
+ export declare const HEADER_PAYMENT_RESPONSE = "payment-response";
8
+ export declare const paymentRequirementsSchema: z.ZodObject<{
9
+ scheme: z.ZodLiteral<"exact">;
10
+ network: z.ZodString;
11
+ asset: z.ZodString;
12
+ payTo: z.ZodString;
13
+ /** Amount in base units of the asset (string integer). */
14
+ maxAmountRequired: z.ZodString;
15
+ resource: z.ZodString;
16
+ description: z.ZodDefault<z.ZodString>;
17
+ maxTimeoutSeconds: z.ZodDefault<z.ZodNumber>;
18
+ extra: z.ZodOptional<z.ZodObject<{
19
+ name: z.ZodString;
20
+ version: z.ZodString;
21
+ decimals: z.ZodNumber;
22
+ }, "strip", z.ZodTypeAny, {
23
+ name: string;
24
+ version: string;
25
+ decimals: number;
26
+ }, {
27
+ name: string;
28
+ version: string;
29
+ decimals: number;
30
+ }>>;
31
+ }, "strip", z.ZodTypeAny, {
32
+ description: string;
33
+ scheme: "exact";
34
+ network: string;
35
+ asset: string;
36
+ payTo: string;
37
+ maxAmountRequired: string;
38
+ resource: string;
39
+ maxTimeoutSeconds: number;
40
+ extra?: {
41
+ name: string;
42
+ version: string;
43
+ decimals: number;
44
+ } | undefined;
45
+ }, {
46
+ scheme: "exact";
47
+ network: string;
48
+ asset: string;
49
+ payTo: string;
50
+ maxAmountRequired: string;
51
+ resource: string;
52
+ description?: string | undefined;
53
+ maxTimeoutSeconds?: number | undefined;
54
+ extra?: {
55
+ name: string;
56
+ version: string;
57
+ decimals: number;
58
+ } | undefined;
59
+ }>;
60
+ export type PaymentRequirements = z.infer<typeof paymentRequirementsSchema>;
61
+ export declare const paymentRequiredBodySchema: z.ZodObject<{
62
+ x402Version: z.ZodNumber;
63
+ error: z.ZodOptional<z.ZodString>;
64
+ accepts: z.ZodArray<z.ZodObject<{
65
+ scheme: z.ZodLiteral<"exact">;
66
+ network: z.ZodString;
67
+ asset: z.ZodString;
68
+ payTo: z.ZodString;
69
+ /** Amount in base units of the asset (string integer). */
70
+ maxAmountRequired: z.ZodString;
71
+ resource: z.ZodString;
72
+ description: z.ZodDefault<z.ZodString>;
73
+ maxTimeoutSeconds: z.ZodDefault<z.ZodNumber>;
74
+ extra: z.ZodOptional<z.ZodObject<{
75
+ name: z.ZodString;
76
+ version: z.ZodString;
77
+ decimals: z.ZodNumber;
78
+ }, "strip", z.ZodTypeAny, {
79
+ name: string;
80
+ version: string;
81
+ decimals: number;
82
+ }, {
83
+ name: string;
84
+ version: string;
85
+ decimals: number;
86
+ }>>;
87
+ }, "strip", z.ZodTypeAny, {
88
+ description: string;
89
+ scheme: "exact";
90
+ network: string;
91
+ asset: string;
92
+ payTo: string;
93
+ maxAmountRequired: string;
94
+ resource: string;
95
+ maxTimeoutSeconds: number;
96
+ extra?: {
97
+ name: string;
98
+ version: string;
99
+ decimals: number;
100
+ } | undefined;
101
+ }, {
102
+ scheme: "exact";
103
+ network: string;
104
+ asset: string;
105
+ payTo: string;
106
+ maxAmountRequired: string;
107
+ resource: string;
108
+ description?: string | undefined;
109
+ maxTimeoutSeconds?: number | undefined;
110
+ extra?: {
111
+ name: string;
112
+ version: string;
113
+ decimals: number;
114
+ } | undefined;
115
+ }>, "many">;
116
+ }, "strip", z.ZodTypeAny, {
117
+ x402Version: number;
118
+ accepts: {
119
+ description: string;
120
+ scheme: "exact";
121
+ network: string;
122
+ asset: string;
123
+ payTo: string;
124
+ maxAmountRequired: string;
125
+ resource: string;
126
+ maxTimeoutSeconds: number;
127
+ extra?: {
128
+ name: string;
129
+ version: string;
130
+ decimals: number;
131
+ } | undefined;
132
+ }[];
133
+ error?: string | undefined;
134
+ }, {
135
+ x402Version: number;
136
+ accepts: {
137
+ scheme: "exact";
138
+ network: string;
139
+ asset: string;
140
+ payTo: string;
141
+ maxAmountRequired: string;
142
+ resource: string;
143
+ description?: string | undefined;
144
+ maxTimeoutSeconds?: number | undefined;
145
+ extra?: {
146
+ name: string;
147
+ version: string;
148
+ decimals: number;
149
+ } | undefined;
150
+ }[];
151
+ error?: string | undefined;
152
+ }>;
153
+ export type PaymentRequiredBody = z.infer<typeof paymentRequiredBodySchema>;
154
+ export declare const authorizationSchema: z.ZodObject<{
155
+ from: z.ZodString;
156
+ to: z.ZodString;
157
+ value: z.ZodString;
158
+ validAfter: z.ZodString;
159
+ validBefore: z.ZodString;
160
+ nonce: z.ZodString;
161
+ }, "strip", z.ZodTypeAny, {
162
+ from: string;
163
+ nonce: string;
164
+ to: string;
165
+ value: string;
166
+ validAfter: string;
167
+ validBefore: string;
168
+ }, {
169
+ from: string;
170
+ nonce: string;
171
+ to: string;
172
+ value: string;
173
+ validAfter: string;
174
+ validBefore: string;
175
+ }>;
176
+ export type Eip3009Authorization = z.infer<typeof authorizationSchema>;
177
+ export declare const paymentPayloadSchema: z.ZodObject<{
178
+ x402Version: z.ZodNumber;
179
+ scheme: z.ZodLiteral<"exact">;
180
+ network: z.ZodString;
181
+ payload: z.ZodObject<{
182
+ authorization: z.ZodObject<{
183
+ from: z.ZodString;
184
+ to: z.ZodString;
185
+ value: z.ZodString;
186
+ validAfter: z.ZodString;
187
+ validBefore: z.ZodString;
188
+ nonce: z.ZodString;
189
+ }, "strip", z.ZodTypeAny, {
190
+ from: string;
191
+ nonce: string;
192
+ to: string;
193
+ value: string;
194
+ validAfter: string;
195
+ validBefore: string;
196
+ }, {
197
+ from: string;
198
+ nonce: string;
199
+ to: string;
200
+ value: string;
201
+ validAfter: string;
202
+ validBefore: string;
203
+ }>;
204
+ signature: z.ZodString;
205
+ }, "strip", z.ZodTypeAny, {
206
+ authorization: {
207
+ from: string;
208
+ nonce: string;
209
+ to: string;
210
+ value: string;
211
+ validAfter: string;
212
+ validBefore: string;
213
+ };
214
+ signature: string;
215
+ }, {
216
+ authorization: {
217
+ from: string;
218
+ nonce: string;
219
+ to: string;
220
+ value: string;
221
+ validAfter: string;
222
+ validBefore: string;
223
+ };
224
+ signature: string;
225
+ }>;
226
+ }, "strip", z.ZodTypeAny, {
227
+ scheme: "exact";
228
+ network: string;
229
+ x402Version: number;
230
+ payload: {
231
+ authorization: {
232
+ from: string;
233
+ nonce: string;
234
+ to: string;
235
+ value: string;
236
+ validAfter: string;
237
+ validBefore: string;
238
+ };
239
+ signature: string;
240
+ };
241
+ }, {
242
+ scheme: "exact";
243
+ network: string;
244
+ x402Version: number;
245
+ payload: {
246
+ authorization: {
247
+ from: string;
248
+ nonce: string;
249
+ to: string;
250
+ value: string;
251
+ validAfter: string;
252
+ validBefore: string;
253
+ };
254
+ signature: string;
255
+ };
256
+ }>;
257
+ export type PaymentPayload = z.infer<typeof paymentPayloadSchema>;
258
+ export interface VerifyRequest {
259
+ paymentPayload: PaymentPayload;
260
+ paymentRequirements: PaymentRequirements;
261
+ }
262
+ export interface VerifyResponse {
263
+ isValid: boolean;
264
+ invalidReason?: string;
265
+ payer?: `0x${string}`;
266
+ }
267
+ export interface SettleResponse {
268
+ success: boolean;
269
+ errorReason?: string;
270
+ transaction?: `0x${string}`;
271
+ network: string;
272
+ payer?: `0x${string}`;
273
+ }
274
+ /** base64(JSON) codecs used for all PAYMENT-* headers. */
275
+ export declare function encodeHeader(value: unknown): string;
276
+ export declare function decodeHeader<S extends z.ZodTypeAny>(raw: string, schema: S): z.output<S>;
@@ -0,0 +1,57 @@
1
+ import { z } from "zod";
2
+ /** x402 v2 wire types (exact scheme, EVM / EIP-3009). */
3
+ export const X402_VERSION = 2;
4
+ /** HTTP headers used by the protocol. Values are base64-encoded JSON. */
5
+ export const HEADER_PAYMENT_REQUIRED = "payment-required";
6
+ export const HEADER_PAYMENT_SIGNATURE = "payment-signature";
7
+ export const HEADER_PAYMENT_RESPONSE = "payment-response";
8
+ const hex = /^0x[0-9a-fA-F]+$/;
9
+ const address = z.string().regex(/^0x[0-9a-fA-F]{40}$/);
10
+ export const paymentRequirementsSchema = z.object({
11
+ scheme: z.literal("exact"),
12
+ network: z.string(),
13
+ asset: address,
14
+ payTo: address,
15
+ /** Amount in base units of the asset (string integer). */
16
+ maxAmountRequired: z.string().regex(/^\d+$/),
17
+ resource: z.string(),
18
+ description: z.string().default(""),
19
+ maxTimeoutSeconds: z.number().int().positive().default(300),
20
+ extra: z
21
+ .object({
22
+ name: z.string(),
23
+ version: z.string(),
24
+ decimals: z.number().int(),
25
+ })
26
+ .optional(),
27
+ });
28
+ export const paymentRequiredBodySchema = z.object({
29
+ x402Version: z.number(),
30
+ error: z.string().optional(),
31
+ accepts: z.array(paymentRequirementsSchema).min(1),
32
+ });
33
+ export const authorizationSchema = z.object({
34
+ from: address,
35
+ to: address,
36
+ value: z.string().regex(/^\d+$/),
37
+ validAfter: z.string().regex(/^\d+$/),
38
+ validBefore: z.string().regex(/^\d+$/),
39
+ nonce: z.string().regex(/^0x[0-9a-fA-F]{64}$/),
40
+ });
41
+ export const paymentPayloadSchema = z.object({
42
+ x402Version: z.number(),
43
+ scheme: z.literal("exact"),
44
+ network: z.string(),
45
+ payload: z.object({
46
+ authorization: authorizationSchema,
47
+ signature: z.string().regex(hex),
48
+ }),
49
+ });
50
+ /** base64(JSON) codecs used for all PAYMENT-* headers. */
51
+ export function encodeHeader(value) {
52
+ return Buffer.from(JSON.stringify(value), "utf8").toString("base64");
53
+ }
54
+ export function decodeHeader(raw, schema) {
55
+ const json = JSON.parse(Buffer.from(raw, "base64").toString("utf8"));
56
+ return schema.parse(json);
57
+ }
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@402lane/core",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": "./dist/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc -p tsconfig.json",
12
+ "test": "node --test dist/test/"
13
+ },
14
+ "dependencies": {
15
+ "viem": "^2.21.0",
16
+ "zod": "^3.23.0"
17
+ },
18
+ "devDependencies": {
19
+ "typescript": "^5.5.0",
20
+ "@types/node": "^22.0.0"
21
+ },
22
+ "publishConfig": {
23
+ "access": "public"
24
+ },
25
+ "license": "MIT",
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "https://github.com/oggyfoxy/lane402"
29
+ },
30
+ "files": [
31
+ "dist",
32
+ "README.md"
33
+ ]
34
+ }