npm package: @lucid-fdn/pay
Description: Drop-in fetch() replacement that handles x402 payments automatically
Latest version: 0.3.0

# @lucid-fdn/pay

Drop-in `fetch()` replacement with automatic x402 payments for AI agents. Multi-chain: Base, Ethereum, Arbitrum, Optimism, Polygon, ApeChain, Monad, Solana, Sui.

## Install

```bash
npm install @lucid-fdn/pay
```

## Quick Start

```ts
import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { base } from "viem/chains";
import { createLucidFetch, ViemWallet } from "@lucid-fdn/pay";

const client = createWalletClient({
  account: privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`),
  chain: base,
  transport: http(),
});

const lucidFetch = createLucidFetch({
  wallet: new ViemWallet(client),
  maxAmountPerRequest: "100000", // 0.10 USDC (6 decimals)
});

// Use exactly like fetch() -- payments are handled automatically
const response = await lucidFetch(
  "https://api.lucid.foundation/v1/chat/completions",
  {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      model: "gpt-4o",
      messages: [{ role: "user", content: "Hello" }],
    }),
  },
);
```

## How It Works

1. Your request is sent to the API as a normal `fetch()` call.
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.
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.
4. The server delegates verification to the appropriate facilitator and returns the response.

Works with any x402-enabled API, including Lucid TrustGate and MCPGate endpoints.

### Supported Chains

| Chain | Token | Facilitators |
|-------|-------|-------------|
| Base | USDC | Direct, Coinbase, PayAI, Thirdweb |
| Ethereum | USDC | PayAI, Thirdweb |
| Arbitrum | USDC | PayAI, Thirdweb |
| Optimism | USDC | PayAI, Thirdweb |
| Polygon | USDC | Thirdweb |
| ApeChain | USDC | Thirdweb |
| Monad | USDC | Direct, PayAI, Thirdweb |
| Solana | USDC | PayAI |
| Sui | USDC | Sui (native) |

## API Reference

### `createLucidFetch(config): lucidFetch`

Returns a configured fetch function that handles x402 payments automatically.

```ts
const lucidFetch = createLucidFetch(config);
const response = await lucidFetch(url, init);
```

### `lucidFetch(url, init?, config?)`

One-shot convenience function. Accepts an inline config as the third argument. If no config is provided, behaves as a standard `fetch()`.

```ts
import { lucidFetch } from "@lucid-fdn/pay";

const response = await lucidFetch(
  "https://api.lucid.foundation/v1/chat/completions",
  { method: "POST", body: "..." },
  { wallet: myWallet },
);
```

### Configuration (`LucidPayConfig`)

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `wallet` | `PaymentWallet` | required | Wallet adapter used for payments |
| `maxAmountPerRequest` | `string` | no limit | Maximum amount per request in micro-units (USDC has 6 decimals, so `"1000000"` = 1 USDC) |
| `maxRetries` | `number` | `1` | Number of retries after payment |
| `onPayment` | `(info: PaymentInfo) => void` | -- | Called after a successful payment |
| `onPaymentSkipped` | `(info) => void` | -- | Called when a payment exceeds the budget |

### Per-Request Overrides (`LucidFetchOptions`)

Extends standard `RequestInit`. You can override the wallet or budget on individual requests:

```ts
const response = await lucidFetch(url, {
  method: "POST",
  body: "...",
  wallet: alternateWallet, // override wallet for this call
  maxAmount: "50000",      // override budget for this call
});
```

### `PaymentInfo`

Object passed to the `onPayment` callback:

| Field | Type | Description |
|-------|------|-------------|
| `txHash` | `string` | On-chain transaction hash |
| `amount` | `string` | Amount paid (micro-units) |
| `recipient` | `string` | Payment recipient address |
| `chain` | `string` | Chain identifier (e.g. `"base-sepolia"`) |
| `token` | `string` | Token symbol (e.g. `"USDC"`) |
| `url` | `string` | The URL that required payment |

## Wallets

### `ViemWallet` (production)

Wraps a [viem](https://viem.sh) `WalletClient` to sign and send real ERC-20 transfers on-chain. Consumers bring their own `viem` dependency.

```ts
import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { base } from "viem/chains";
import { ViemWallet } from "@lucid-fdn/pay";

const wallet = new ViemWallet(
  createWalletClient({
    account: privateKeyToAccount("0x..."),
    chain: base,
    transport: http(),
  }),
);
```

### `MemoryWallet` (testing)

In-memory wallet that records payments without sending real transactions. Useful for tests and local development.

```ts
import { MemoryWallet } from "@lucid-fdn/pay";

const wallet = new MemoryWallet("0xYourAddress", "base-sepolia");

// After running requests:
console.log(wallet.payments); // array of recorded payments
```

### Custom Wallets

Implement the `PaymentWallet` interface to use any signing backend:

```ts
import type { PaymentWallet } from "@lucid-fdn/pay";

const myWallet: PaymentWallet = {
  address: "0x...",
  chain: "base",
  async sendPayment({ to, amount, tokenAddress, chain }) {
    // Sign and broadcast an ERC-20 transfer
    return txHash;
  },
};
```

## License

MIT