@lucid-fdn/pay 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,181 @@
1
+ # @lucid-fdn/pay
2
+
3
+ Drop-in `fetch()` replacement with automatic x402 payments for AI agents. Multi-chain: Base, Ethereum, Arbitrum, Optimism, Polygon, ApeChain, Monad, Solana, Sui.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @lucid-fdn/pay
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```ts
14
+ import { createWalletClient, http } from "viem";
15
+ import { privateKeyToAccount } from "viem/accounts";
16
+ import { base } from "viem/chains";
17
+ import { createLucidFetch, ViemWallet } from "@lucid-fdn/pay";
18
+
19
+ const client = createWalletClient({
20
+ account: privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`),
21
+ chain: base,
22
+ transport: http(),
23
+ });
24
+
25
+ const lucidFetch = createLucidFetch({
26
+ wallet: new ViemWallet(client),
27
+ maxAmountPerRequest: "100000", // 0.10 USDC (6 decimals)
28
+ });
29
+
30
+ // Use exactly like fetch() -- payments are handled automatically
31
+ const response = await lucidFetch(
32
+ "https://api.lucid.foundation/v1/chat/completions",
33
+ {
34
+ method: "POST",
35
+ headers: { "Content-Type": "application/json" },
36
+ body: JSON.stringify({
37
+ model: "gpt-4o",
38
+ messages: [{ role: "user", content: "Hello" }],
39
+ }),
40
+ },
41
+ );
42
+ ```
43
+
44
+ ## How It Works
45
+
46
+ 1. Your request is sent to the API as a normal `fetch()` call.
47
+ 2. If the server returns HTTP 402, the response body contains an x402 v2 `options[]` array — one entry per supported chain and facilitator, each with the recipient address, token, amount, and chain.
48
+ 3. `@lucid-fdn/pay` selects the option matching your wallet's chain (or falls back to the first option), checks the amount against your budget, sends an on-chain USDC transfer, and retries with `X-Payment-Proof` (tx hash) and `X-Payment-Chain` headers.
49
+ 4. The server delegates verification to the appropriate facilitator and returns the response.
50
+
51
+ Works with any x402-enabled API, including Lucid TrustGate and MCPGate endpoints.
52
+
53
+ ### Supported Chains
54
+
55
+ | Chain | Token | Facilitators |
56
+ |-------|-------|-------------|
57
+ | Base | USDC | Direct, Coinbase, PayAI, Thirdweb |
58
+ | Ethereum | USDC | PayAI, Thirdweb |
59
+ | Arbitrum | USDC | PayAI, Thirdweb |
60
+ | Optimism | USDC | PayAI, Thirdweb |
61
+ | Polygon | USDC | Thirdweb |
62
+ | ApeChain | USDC | Thirdweb |
63
+ | Monad | USDC | Direct, PayAI, Thirdweb |
64
+ | Solana | USDC | PayAI |
65
+ | Sui | USDC | Sui (native) |
66
+
67
+ ## API Reference
68
+
69
+ ### `createLucidFetch(config): lucidFetch`
70
+
71
+ Returns a configured fetch function that handles x402 payments automatically.
72
+
73
+ ```ts
74
+ const lucidFetch = createLucidFetch(config);
75
+ const response = await lucidFetch(url, init);
76
+ ```
77
+
78
+ ### `lucidFetch(url, init?, config?)`
79
+
80
+ One-shot convenience function. Accepts an inline config as the third argument. If no config is provided, behaves as a standard `fetch()`.
81
+
82
+ ```ts
83
+ import { lucidFetch } from "@lucid-fdn/pay";
84
+
85
+ const response = await lucidFetch(
86
+ "https://api.lucid.foundation/v1/chat/completions",
87
+ { method: "POST", body: "..." },
88
+ { wallet: myWallet },
89
+ );
90
+ ```
91
+
92
+ ### Configuration (`LucidPayConfig`)
93
+
94
+ | Option | Type | Default | Description |
95
+ |--------|------|---------|-------------|
96
+ | `wallet` | `PaymentWallet` | required | Wallet adapter used for payments |
97
+ | `maxAmountPerRequest` | `string` | no limit | Maximum amount per request in micro-units (USDC has 6 decimals, so `"1000000"` = 1 USDC) |
98
+ | `maxRetries` | `number` | `1` | Number of retries after payment |
99
+ | `onPayment` | `(info: PaymentInfo) => void` | -- | Called after a successful payment |
100
+ | `onPaymentSkipped` | `(info) => void` | -- | Called when a payment exceeds the budget |
101
+
102
+ ### Per-Request Overrides (`LucidFetchOptions`)
103
+
104
+ Extends standard `RequestInit`. You can override the wallet or budget on individual requests:
105
+
106
+ ```ts
107
+ const response = await lucidFetch(url, {
108
+ method: "POST",
109
+ body: "...",
110
+ wallet: alternateWallet, // override wallet for this call
111
+ maxAmount: "50000", // override budget for this call
112
+ });
113
+ ```
114
+
115
+ ### `PaymentInfo`
116
+
117
+ Object passed to the `onPayment` callback:
118
+
119
+ | Field | Type | Description |
120
+ |-------|------|-------------|
121
+ | `txHash` | `string` | On-chain transaction hash |
122
+ | `amount` | `string` | Amount paid (micro-units) |
123
+ | `recipient` | `string` | Payment recipient address |
124
+ | `chain` | `string` | Chain identifier (e.g. `"base-sepolia"`) |
125
+ | `token` | `string` | Token symbol (e.g. `"USDC"`) |
126
+ | `url` | `string` | The URL that required payment |
127
+
128
+ ## Wallets
129
+
130
+ ### `ViemWallet` (production)
131
+
132
+ Wraps a [viem](https://viem.sh) `WalletClient` to sign and send real ERC-20 transfers on-chain. Consumers bring their own `viem` dependency.
133
+
134
+ ```ts
135
+ import { createWalletClient, http } from "viem";
136
+ import { privateKeyToAccount } from "viem/accounts";
137
+ import { base } from "viem/chains";
138
+ import { ViemWallet } from "@lucid-fdn/pay";
139
+
140
+ const wallet = new ViemWallet(
141
+ createWalletClient({
142
+ account: privateKeyToAccount("0x..."),
143
+ chain: base,
144
+ transport: http(),
145
+ }),
146
+ );
147
+ ```
148
+
149
+ ### `MemoryWallet` (testing)
150
+
151
+ In-memory wallet that records payments without sending real transactions. Useful for tests and local development.
152
+
153
+ ```ts
154
+ import { MemoryWallet } from "@lucid-fdn/pay";
155
+
156
+ const wallet = new MemoryWallet("0xYourAddress", "base-sepolia");
157
+
158
+ // After running requests:
159
+ console.log(wallet.payments); // array of recorded payments
160
+ ```
161
+
162
+ ### Custom Wallets
163
+
164
+ Implement the `PaymentWallet` interface to use any signing backend:
165
+
166
+ ```ts
167
+ import type { PaymentWallet } from "@lucid-fdn/pay";
168
+
169
+ const myWallet: PaymentWallet = {
170
+ address: "0x...",
171
+ chain: "base",
172
+ async sendPayment({ to, amount, tokenAddress, chain }) {
173
+ // Sign and broadcast an ERC-20 transfer
174
+ return txHash;
175
+ },
176
+ };
177
+ ```
178
+
179
+ ## License
180
+
181
+ MIT
@@ -0,0 +1,5 @@
1
+ export { createLucidFetch, lucidFetch } from './lucid-fetch.js';
2
+ export type { LucidPayConfig, LucidFetchOptions, PaymentWallet, PaymentInfo, X402PaymentOption, X402PaymentBlock, X402Response, } from './types.js';
3
+ export { MemoryWallet } from './wallets/memory-wallet.js';
4
+ export { ViemWallet } from './wallets/viem-wallet.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAG/D,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,aAAa,EACb,WAAW,EACX,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,GACb,MAAM,YAAY,CAAA;AAGnB,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ // Core
2
+ export { createLucidFetch, lucidFetch } from './lucid-fetch.js';
3
+ // Wallets
4
+ export { MemoryWallet } from './wallets/memory-wallet.js';
5
+ export { ViemWallet } from './wallets/viem-wallet.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO;AACP,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAa/D,UAAU;AACV,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA"}
@@ -0,0 +1,22 @@
1
+ import type { LucidPayConfig, LucidFetchOptions } from './types.js';
2
+ /**
3
+ * Create a configured lucidFetch function.
4
+ *
5
+ * Usage:
6
+ * const lucidFetch = createLucidFetch({ wallet: myWallet })
7
+ * const response = await lucidFetch('https://api.example.com/v1/chat', { method: 'POST', body: '...' })
8
+ * // If 402 returned, payment is handled automatically
9
+ */
10
+ export declare function createLucidFetch(config: LucidPayConfig): (url: string | URL | Request, init?: LucidFetchOptions) => Promise<Response>;
11
+ /**
12
+ * Convenience: create a one-shot lucidFetch with inline config.
13
+ *
14
+ * Usage:
15
+ * import { lucidFetch } from '@lucid/pay'
16
+ * const response = await lucidFetch('https://api.example.com/chat', {
17
+ * method: 'POST',
18
+ * body: JSON.stringify({ model: 'gpt-4o', messages: [...] }),
19
+ * }, { wallet: myWallet })
20
+ */
21
+ export declare function lucidFetch(url: string | URL | Request, init?: LucidFetchOptions, config?: LucidPayConfig): Promise<Response>;
22
+ //# sourceMappingURL=lucid-fetch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lucid-fetch.d.ts","sourceRoot":"","sources":["../src/lucid-fetch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,iBAAiB,EAIlB,MAAM,YAAY,CAAA;AAEnB;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,cAAc,IAEnD,KAAK,MAAM,GAAG,GAAG,GAAG,OAAO,EAC3B,OAAO,iBAAiB,KACvB,OAAO,CAAC,QAAQ,CAAC,CA6FrB;AAED;;;;;;;;;GASG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,EAC3B,IAAI,CAAC,EAAE,iBAAiB,EACxB,MAAM,CAAC,EAAE,cAAc,GACtB,OAAO,CAAC,QAAQ,CAAC,CAOnB"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Create a configured lucidFetch function.
3
+ *
4
+ * Usage:
5
+ * const lucidFetch = createLucidFetch({ wallet: myWallet })
6
+ * const response = await lucidFetch('https://api.example.com/v1/chat', { method: 'POST', body: '...' })
7
+ * // If 402 returned, payment is handled automatically
8
+ */
9
+ export function createLucidFetch(config) {
10
+ return async function lucidFetch(url, init) {
11
+ const urlStr = url instanceof Request ? url.url : url.toString();
12
+ const wallet = init?.wallet ?? config.wallet;
13
+ const maxAmount = init?.maxAmount ?? config.maxAmountPerRequest;
14
+ const maxRetries = config.maxRetries ?? 1;
15
+ // First attempt — normal fetch
16
+ let response = await fetch(url, init);
17
+ // Not 402 — return as-is
18
+ if (response.status !== 402)
19
+ return response;
20
+ // Parse x402 payment block
21
+ let x402Body;
22
+ try {
23
+ x402Body = await response.json();
24
+ }
25
+ catch {
26
+ // Not a valid x402 response — return original 402
27
+ return response;
28
+ }
29
+ if (!x402Body?.x402?.options || x402Body.x402.options.length === 0) {
30
+ return response;
31
+ }
32
+ // Select a compatible payment option — prefer wallet's chain, fall back to first option
33
+ const options = x402Body.x402.options;
34
+ const payment = options.find(o => o.chain === wallet.chain) ?? options[0];
35
+ // Budget check
36
+ if (maxAmount) {
37
+ const requested = BigInt(payment.amount);
38
+ const max = BigInt(maxAmount);
39
+ if (requested > max) {
40
+ config.onPaymentSkipped?.({ amount: payment.amount, max: maxAmount });
41
+ return response; // Return original 402
42
+ }
43
+ }
44
+ // Check expiry
45
+ const now = Math.floor(Date.now() / 1000);
46
+ if (x402Body.x402.expires && now > x402Body.x402.expires) {
47
+ return response; // Expired — return 402
48
+ }
49
+ // Execute payment
50
+ let txHash;
51
+ try {
52
+ txHash = await wallet.sendPayment({
53
+ to: payment.recipient,
54
+ amount: payment.amount,
55
+ tokenAddress: payment.tokenAddress,
56
+ chain: payment.chain,
57
+ });
58
+ }
59
+ catch {
60
+ // Payment failed — return original 402
61
+ return response;
62
+ }
63
+ // Notify caller
64
+ const paymentInfo = {
65
+ txHash,
66
+ amount: payment.amount,
67
+ recipient: payment.recipient,
68
+ chain: payment.chain,
69
+ token: payment.token,
70
+ url: urlStr,
71
+ };
72
+ config.onPayment?.(paymentInfo);
73
+ // Retry with payment proof + chain hint
74
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
75
+ const retryHeaders = new Headers(init?.headers);
76
+ retryHeaders.set('X-Payment-Proof', txHash);
77
+ retryHeaders.set('X-Payment-Chain', payment.chain);
78
+ // If server returned a session ID, include it
79
+ const sessionId = response.headers.get('X-Payment-Session');
80
+ if (sessionId) {
81
+ retryHeaders.set('X-Payment-Session', sessionId);
82
+ }
83
+ response = await fetch(url, {
84
+ ...init,
85
+ headers: retryHeaders,
86
+ });
87
+ if (response.status !== 402)
88
+ return response;
89
+ }
90
+ return response;
91
+ };
92
+ }
93
+ /**
94
+ * Convenience: create a one-shot lucidFetch with inline config.
95
+ *
96
+ * Usage:
97
+ * import { lucidFetch } from '@lucid/pay'
98
+ * const response = await lucidFetch('https://api.example.com/chat', {
99
+ * method: 'POST',
100
+ * body: JSON.stringify({ model: 'gpt-4o', messages: [...] }),
101
+ * }, { wallet: myWallet })
102
+ */
103
+ export async function lucidFetch(url, init, config) {
104
+ if (!config) {
105
+ // No config — just regular fetch
106
+ return fetch(url, init);
107
+ }
108
+ const fn = createLucidFetch(config);
109
+ return fn(url, init);
110
+ }
111
+ //# sourceMappingURL=lucid-fetch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lucid-fetch.js","sourceRoot":"","sources":["../src/lucid-fetch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ /** Single payment option within an x402 block */
2
+ export type X402PaymentOption = {
3
+ chain: string;
4
+ token: string;
5
+ tokenAddress: string;
6
+ amount: string;
7
+ recipient: string;
8
+ facilitator: string;
9
+ scheme: string;
10
+ };
11
+ /** x402 payment block from 402 response */
12
+ export type X402PaymentBlock = {
13
+ version: string;
14
+ description: string;
15
+ options: X402PaymentOption[];
16
+ expires: number;
17
+ };
18
+ /** 402 response body */
19
+ export type X402Response = {
20
+ error: string;
21
+ x402: X402PaymentBlock;
22
+ };
23
+ /** Wallet adapter interface — abstract over different wallet types */
24
+ export type PaymentWallet = {
25
+ /** The wallet address */
26
+ address: string;
27
+ /** Chain the wallet operates on */
28
+ chain: string;
29
+ /** Sign and send a USDC transfer, return the tx hash */
30
+ sendPayment(params: {
31
+ to: string;
32
+ amount: string;
33
+ tokenAddress: string;
34
+ chain: string;
35
+ }): Promise<string>;
36
+ };
37
+ /** Configuration for lucidFetch */
38
+ export type LucidPayConfig = {
39
+ /** Wallet to use for payments */
40
+ wallet: PaymentWallet;
41
+ /** Maximum amount willing to pay per request (micro-units). Default: no limit */
42
+ maxAmountPerRequest?: string;
43
+ /** Maximum retries after payment. Default: 1 */
44
+ maxRetries?: number;
45
+ /** Callback when a payment is made */
46
+ onPayment?: (info: PaymentInfo) => void;
47
+ /** Callback when payment is skipped (over budget) */
48
+ onPaymentSkipped?: (info: {
49
+ amount: string;
50
+ max: string;
51
+ }) => void;
52
+ };
53
+ /** Information about a payment that was made */
54
+ export type PaymentInfo = {
55
+ txHash: string;
56
+ amount: string;
57
+ recipient: string;
58
+ chain: string;
59
+ token: string;
60
+ url: string;
61
+ };
62
+ /** Options for lucidFetch — extends standard RequestInit */
63
+ export type LucidFetchOptions = RequestInit & {
64
+ /** Override wallet for this request */
65
+ wallet?: PaymentWallet;
66
+ /** Override max amount for this request */
67
+ maxAmount?: string;
68
+ };
69
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,iDAAiD;AACjD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,YAAY,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAED,2CAA2C;AAC3C,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,iBAAiB,EAAE,CAAA;IAC5B,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,wBAAwB;AACxB,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,gBAAgB,CAAA;CACvB,CAAA;AAED,sEAAsE;AACtE,MAAM,MAAM,aAAa,GAAG;IAC1B,yBAAyB;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAA;IACb,wDAAwD;IACxD,WAAW,CAAC,MAAM,EAAE;QAClB,EAAE,EAAE,MAAM,CAAA;QACV,MAAM,EAAE,MAAM,CAAA;QACd,YAAY,EAAE,MAAM,CAAA;QACpB,KAAK,EAAE,MAAM,CAAA;KACd,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;CACpB,CAAA;AAED,mCAAmC;AACnC,MAAM,MAAM,cAAc,GAAG;IAC3B,iCAAiC;IACjC,MAAM,EAAE,aAAa,CAAA;IACrB,iFAAiF;IACjF,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,gDAAgD;IAChD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,sCAAsC;IACtC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,CAAA;IACvC,qDAAqD;IACrD,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAA;CACnE,CAAA;AAED,gDAAgD;AAChD,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;CACZ,CAAA;AAED,4DAA4D;AAC5D,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG;IAC5C,uCAAuC;IACvC,MAAM,CAAC,EAAE,aAAa,CAAA;IACtB,2CAA2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,24 @@
1
+ import type { PaymentWallet } from '../types.js';
2
+ /**
3
+ * In-memory test wallet that tracks payments without real signing.
4
+ * Use for testing or as a reference implementation.
5
+ */
6
+ export declare class MemoryWallet implements PaymentWallet {
7
+ address: string;
8
+ chain: string;
9
+ payments: Array<{
10
+ to: string;
11
+ amount: string;
12
+ tokenAddress: string;
13
+ chain: string;
14
+ txHash: string;
15
+ }>;
16
+ constructor(address: string, chain?: string);
17
+ sendPayment(params: {
18
+ to: string;
19
+ amount: string;
20
+ tokenAddress: string;
21
+ chain: string;
22
+ }): Promise<string>;
23
+ }
24
+ //# sourceMappingURL=memory-wallet.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-wallet.d.ts","sourceRoot":"","sources":["../../src/wallets/memory-wallet.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEhD;;;GAGG;AACH,qBAAa,YAAa,YAAW,aAAa;IAChD,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAK;gBAE7F,OAAO,EAAE,MAAM,EAAE,KAAK,GAAE,MAAuB;IAKrD,WAAW,CAAC,MAAM,EAAE;QACxB,EAAE,EAAE,MAAM,CAAA;QACV,MAAM,EAAE,MAAM,CAAA;QACd,YAAY,EAAE,MAAM,CAAA;QACpB,KAAK,EAAE,MAAM,CAAA;KACd,GAAG,OAAO,CAAC,MAAM,CAAC;CAKpB"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * In-memory test wallet that tracks payments without real signing.
3
+ * Use for testing or as a reference implementation.
4
+ */
5
+ export class MemoryWallet {
6
+ address;
7
+ chain;
8
+ payments = [];
9
+ constructor(address, chain = 'base-sepolia') {
10
+ this.address = address;
11
+ this.chain = chain;
12
+ }
13
+ async sendPayment(params) {
14
+ const txHash = `0x${Date.now().toString(16)}${Math.random().toString(16).slice(2, 10)}`;
15
+ this.payments.push({ ...params, txHash });
16
+ return txHash;
17
+ }
18
+ }
19
+ //# sourceMappingURL=memory-wallet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-wallet.js","sourceRoot":"","sources":["../../src/wallets/memory-wallet.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,OAAO,YAAY;IACvB,OAAO,CAAQ;IACf,KAAK,CAAQ;IACb,QAAQ,GAA+F,EAAE,CAAA;IAEzG,YAAY,OAAe,EAAE,QAAgB,cAAc;QACzD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;QACtB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;IACpB,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,MAKjB;QACC,MAAM,MAAM,GAAG,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAA;QACvF,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;QACzC,OAAO,MAAM,CAAA;IACf,CAAC;CACF"}
@@ -0,0 +1,53 @@
1
+ import type { PaymentWallet } from '../types.js';
2
+ /**
3
+ * Viem-based wallet adapter for real on-chain USDC payments.
4
+ *
5
+ * Usage:
6
+ * ```ts
7
+ * import { createWalletClient, http } from 'viem'
8
+ * import { privateKeyToAccount } from 'viem/accounts'
9
+ * import { baseSepolia } from 'viem/chains'
10
+ * import { ViemWallet } from '@lucid/pay'
11
+ *
12
+ * const client = createWalletClient({
13
+ * account: privateKeyToAccount('0x...'),
14
+ * chain: baseSepolia,
15
+ * transport: http(),
16
+ * })
17
+ * const wallet = new ViemWallet(client)
18
+ * ```
19
+ */
20
+ export declare class ViemWallet implements PaymentWallet {
21
+ address: string;
22
+ chain: string;
23
+ private client;
24
+ constructor(client: WalletClientLike, chain?: string);
25
+ sendPayment(params: {
26
+ to: string;
27
+ amount: string;
28
+ tokenAddress: string;
29
+ chain: string;
30
+ }): Promise<string>;
31
+ }
32
+ /**
33
+ * Minimal interface matching viem's WalletClient.
34
+ * Avoids requiring viem as a direct dependency — consumers bring their own.
35
+ */
36
+ type WalletClientLike = {
37
+ account?: {
38
+ address: string;
39
+ } | null;
40
+ chain?: {
41
+ name?: string;
42
+ } | null;
43
+ sendTransaction(args: {
44
+ to: `0x${string}`;
45
+ data: `0x${string}`;
46
+ account: {
47
+ address: string;
48
+ };
49
+ chain: unknown;
50
+ }): Promise<string>;
51
+ };
52
+ export {};
53
+ //# sourceMappingURL=viem-wallet.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viem-wallet.d.ts","sourceRoot":"","sources":["../../src/wallets/viem-wallet.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEhD;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,UAAW,YAAW,aAAa;IAC9C,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,MAAM,CAAkB;gBAEpB,MAAM,EAAE,gBAAgB,EAAE,KAAK,CAAC,EAAE,MAAM;IAS9C,WAAW,CAAC,MAAM,EAAE;QACxB,EAAE,EAAE,MAAM,CAAA;QACV,MAAM,EAAE,MAAM,CAAA;QACd,YAAY,EAAE,MAAM,CAAA;QACpB,KAAK,EAAE,MAAM,CAAA;KACd,GAAG,OAAO,CAAC,MAAM,CAAC;CAepB;AAED;;;GAGG;AACH,KAAK,gBAAgB,GAAG;IACtB,OAAO,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IACpC,KAAK,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IAChC,eAAe,CAAC,IAAI,EAAE;QACpB,EAAE,EAAE,KAAK,MAAM,EAAE,CAAA;QACjB,IAAI,EAAE,KAAK,MAAM,EAAE,CAAA;QACnB,OAAO,EAAE;YAAE,OAAO,EAAE,MAAM,CAAA;SAAE,CAAA;QAC5B,KAAK,EAAE,OAAO,CAAA;KACf,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;CACpB,CAAA"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Viem-based wallet adapter for real on-chain USDC payments.
3
+ *
4
+ * Usage:
5
+ * ```ts
6
+ * import { createWalletClient, http } from 'viem'
7
+ * import { privateKeyToAccount } from 'viem/accounts'
8
+ * import { baseSepolia } from 'viem/chains'
9
+ * import { ViemWallet } from '@lucid/pay'
10
+ *
11
+ * const client = createWalletClient({
12
+ * account: privateKeyToAccount('0x...'),
13
+ * chain: baseSepolia,
14
+ * transport: http(),
15
+ * })
16
+ * const wallet = new ViemWallet(client)
17
+ * ```
18
+ */
19
+ export class ViemWallet {
20
+ address;
21
+ chain;
22
+ client;
23
+ constructor(client, chain) {
24
+ if (!client.account?.address) {
25
+ throw new Error('WalletClient must have an account attached');
26
+ }
27
+ this.client = client;
28
+ this.address = client.account.address;
29
+ this.chain = chain ?? client.chain?.name?.toLowerCase().replace(/\s+/g, '-') ?? 'base';
30
+ }
31
+ async sendPayment(params) {
32
+ // ERC-20 transfer(address,uint256) selector: 0xa9059cbb
33
+ const amountHex = BigInt(params.amount).toString(16).padStart(64, '0');
34
+ const toAddress = params.to.slice(2).padStart(64, '0');
35
+ const data = `0xa9059cbb${toAddress}${amountHex}`;
36
+ const hash = await this.client.sendTransaction({
37
+ to: params.tokenAddress,
38
+ data,
39
+ account: this.client.account,
40
+ chain: this.client.chain,
41
+ });
42
+ return hash;
43
+ }
44
+ }
45
+ //# sourceMappingURL=viem-wallet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viem-wallet.js","sourceRoot":"","sources":["../../src/wallets/viem-wallet.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,OAAO,UAAU;IACrB,OAAO,CAAQ;IACf,KAAK,CAAQ;IACL,MAAM,CAAkB;IAEhC,YAAY,MAAwB,EAAE,KAAc;QAClD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAA;QAC/D,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;QACpB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAA;QACrC,IAAI,CAAC,KAAK,GAAG,KAAK,IAAI,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,MAAM,CAAA;IACxF,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,MAKjB;QACC,wDAAwD;QACxD,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC,CAAA;QACtE,MAAM,SAAS,GAAG,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC,CAAA;QACtD,MAAM,IAAI,GAAG,aAAa,SAAS,GAAG,SAAS,EAAmB,CAAA;QAElE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC;YAC7C,EAAE,EAAE,MAAM,CAAC,YAA6B;YACxC,IAAI;YACJ,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,OAAQ;YAC7B,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK;SACzB,CAAC,CAAA;QAEF,OAAO,IAAI,CAAA;IACb,CAAC;CACF"}
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@lucid-fdn/pay",
3
+ "version": "0.3.0",
4
+ "description": "Drop-in fetch() replacement that handles x402 payments automatically",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "package.json",
17
+ "README.md"
18
+ ],
19
+ "scripts": {
20
+ "build": "tsc -p tsconfig.json",
21
+ "test": "vitest run",
22
+ "prepublishOnly": "npm run build"
23
+ },
24
+ "keywords": ["x402", "payment", "ai", "agent", "fetch", "usdc", "web3"],
25
+ "license": "MIT",
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "https://github.com/raijinlabs/lucid-plateform-core",
29
+ "directory": "packages/pay"
30
+ },
31
+ "homepage": "https://lucid.foundation",
32
+ "publishConfig": {
33
+ "access": "public"
34
+ },
35
+ "devDependencies": {
36
+ "vitest": "^1.0.0",
37
+ "typescript": "^5.0.0"
38
+ }
39
+ }