From 7186ab3551aa4da54de976e46808c77a57b08cff Mon Sep 17 00:00:00 2001 From: vraspar Date: Fri, 20 Mar 2026 19:15:44 -0700 Subject: [PATCH] Add V2 SDK getting started pages and remove V1 nav sections MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rewrites overview and installation pages for V2 API (createX402r, role presets, action groups). Adds create-client and typescript pages. Removes Merchant, Client, Arbiter, Facilitator, and Experimental nav groups from SDK tab — files stay on disk for later cleanup. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs.json | 48 +---------- sdk/create-client.mdx | 188 ++++++++++++++++++++++++++++++++++++++++++ sdk/installation.mdx | 135 ++++++++++++++++++++---------- sdk/overview.mdx | 97 ++++++++++++++-------- sdk/typescript.mdx | 137 ++++++++++++++++++++++++++++++ 5 files changed, 480 insertions(+), 125 deletions(-) create mode 100644 sdk/create-client.mdx create mode 100644 sdk/typescript.mdx diff --git a/docs.json b/docs.json index 3ae8129..7969149 100644 --- a/docs.json +++ b/docs.json @@ -91,52 +91,8 @@ "pages": [ "sdk/overview", "sdk/installation", - "sdk/concepts", - "sdk/deploy-operator", - "sdk/examples", - "sdk/limitations" - ] - }, - { - "group": "Merchant", - "pages": [ - "sdk/merchant/getting-started", - "sdk/helpers/refundable", - "sdk/merchant/quickstart", - "sdk/merchant/refund-handling" - ] - }, - { - "group": "Client", - "pages": [ - "sdk/client/quickstart", - "sdk/client/payment-queries", - "sdk/client/escrow-management", - "sdk/client/refund-operations" - ] - }, - { - "group": "Arbiter", - "pages": [ - "sdk/arbiter/quickstart", - "sdk/arbiter/decision-submission", - "sdk/arbiter/registry" - ] - }, - { - "group": "Facilitator", - "pages": [ - "sdk/facilitator/getting-started" - ] - }, - { - "group": "Experimental", - "pages": [ - "sdk/client/subscriptions", - "sdk/merchant/subscriptions", - "sdk/arbiter/subscriptions", - "sdk/arbiter/batch-operations", - "sdk/arbiter/ai-integration" + "sdk/create-client", + "sdk/typescript" ] } ] diff --git a/sdk/create-client.mdx b/sdk/create-client.mdx new file mode 100644 index 0000000..3341c12 --- /dev/null +++ b/sdk/create-client.mdx @@ -0,0 +1,188 @@ +--- +title: "Create a Client" +description: "Configure and instantiate the x402r client" +icon: "plug" +--- + +## Full Client + +`createX402r()` returns a client with all action groups. Pass an `X402rConfig` object with your viem clients and operator address: + +```typescript +import { createPublicClient, createWalletClient, http } from 'viem' +import { baseSepolia } from 'viem/chains' +import { privateKeyToAccount } from 'viem/accounts' +import { createX402r } from '@x402r/sdk' + +const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`) + +const publicClient = createPublicClient({ + chain: baseSepolia, + transport: http(), +}) + +const walletClient = createWalletClient({ + account, + chain: baseSepolia, + transport: http(), +}) + +const client = createX402r({ + publicClient, + walletClient, + operatorAddress: '0xYourOperator...', + refundRequestAddress: '0xYourRefundRequest...', + escrowPeriodAddress: '0xYourEscrowPeriod...', +}) +``` + +## Config Reference + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `publicClient` | `PublicClient` | Yes | viem public client for read operations | +| `walletClient` | `WalletClient` | No | viem wallet client for write operations | +| `operatorAddress` | `Address` | Yes | Deployed PaymentOperator address | +| `chainId` | `number` | No | Resolved from `publicClient` if omitted | +| `network` | `string` | No | CAIP-2 identifier (e.g. `'eip155:84532'`), fallback if `chainId` is not set | +| `refundRequestAddress` | `Address` | No | Enables `refund` action group | +| `refundRequestEvidenceAddress` | `Address` | No | Enables `evidence` action group (requires `refundRequestAddress`) | +| `escrowPeriodAddress` | `Address` | No | Enables `escrow` action group | +| `freezeAddress` | `Address` | No | Enables `freeze` action group | +| `paymentIndexRecorderAddress` | `Address` | No | Enables `query` action group | +| `paymentStore` | `PaymentStore` | No | Pluggable storage for payment lookups | +| `eventFromBlock` | `bigint` | No | Starting block for event-based payment lookups | + + +`eventFromBlock` sets the lower bound for scanning on-chain events. Without it, the event fallback provider is disabled. Set this to the block your operator was deployed at. + + +## Role Presets + +Role presets call `createX402r()` internally and return a type-narrowed client. They require `walletClient` in the config. + +### Payer + +```typescript +import { createPayerClient } from '@x402r/sdk' + +const payer = createPayerClient({ + publicClient, + walletClient, + operatorAddress: '0xYourOperator...', + refundRequestAddress: '0xYourRefundRequest...', +}) + +// Type-narrowed: only payer methods are available +const state = await payer.payment.getState(paymentInfo) +const tx = await payer.refund?.request(paymentInfo, amount, nonce) +``` + +### Merchant + +```typescript +import { createMerchantClient } from '@x402r/sdk' + +const merchant = createMerchantClient({ + publicClient, + walletClient, + operatorAddress: '0xYourOperator...', + refundRequestAddress: '0xYourRefundRequest...', +}) + +// Type-narrowed: only merchant methods are available +const tx = await merchant.payment.release(paymentInfo, amount) +``` + +### Arbiter + +```typescript +import { createArbiterClient } from '@x402r/sdk' + +const arbiter = createArbiterClient({ + publicClient, + walletClient, + operatorAddress: '0xYourOperator...', + refundRequestAddress: '0xYourRefundRequest...', +}) + +// Type-narrowed: only arbiter methods are available +const tx = await arbiter.refund?.approve(paymentInfo, nonce, amount) +``` + + +Type narrowing is a DX improvement only. On-chain access control is enforced by [conditions](/contracts/conditions/overview), not by the client type. + + +## Check Conditions + +Use `canExecute()` to check if a condition slot permits an action before submitting a transaction: + +```typescript +const allowed = await client.canExecute('authorize', paymentInfo, amount) +``` + +This calls `ICondition.check()` on the condition configured for that slot on the operator. Returns `true` if no condition is set (zero address). + +## Payment Store + +`createMemoryStore()` provides an in-memory `PaymentStore` for development and testing. Data is lost when the process exits. + +```typescript +import { createX402r, createMemoryStore } from '@x402r/sdk' + +const client = createX402r({ + publicClient, + operatorAddress: '0xYourOperator...', + paymentIndexRecorderAddress: '0xYourRecorder...', + paymentStore: createMemoryStore(), +}) +``` + +For production, implement the `PaymentStore` interface with your database of choice. + +## Action Group Access + +Access action groups via dot notation on the client: + +```typescript +// Always available +await client.payment.getState(paymentInfo) +await client.operator.getConfig() +client.watch.onPayment((log) => { /* ... */ }) + +// Available when the corresponding address is configured +await client.escrow?.isDuringEscrow(paymentInfo) +await client.refund?.request(paymentInfo, amount, nonce) +await client.freeze?.isFrozen(paymentInfo) +await client.query?.getPayerPayments(payerAddress) +await client.evidence?.submit(paymentInfo, nonce, cid) +``` + +`payment`, `operator`, and `watch` are always defined. The other groups (`escrow`, `refund`, `evidence`, `freeze`, `query`) are `undefined` when their corresponding address is not provided in the config. + +## Extend + +Add custom methods or fill missing action groups with `.extend()`: + +```typescript +import { queryActions } from '@x402r/sdk' + +const extended = client.extend( + queryActions('0xRecorderAddress...', { eventFromBlock: 12345n }) +) + +// extended.query is now defined +const payments = await extended.query.getPayerPayments(payerAddress) +``` + +## Next Steps + + + + Type imports, role narrowing, and error types. + + + On-chain architecture, conditions, and recorders. + + diff --git a/sdk/installation.mdx b/sdk/installation.mdx index 7485080..b10eb21 100644 --- a/sdk/installation.mdx +++ b/sdk/installation.mdx @@ -1,70 +1,115 @@ --- title: "Installation" -description: "Install and configure the X402r SDK packages" +description: "Install the x402r SDK and set up viem clients" icon: "download" --- ## Install Packages -Install only the packages you need for your use case: - - - - ```bash - npm install @x402r/client @x402r/core viem - ``` - - - ```bash - npm install @x402r/merchant @x402r/helpers @x402r/core viem - ``` - - - ```bash - npm install @x402r/arbiter @x402r/core viem - ``` - - - ```bash - npm install @x402r/helpers @x402r/core viem - ``` - - - -## Setup viem Clients - -Create `publicClient` and `walletClient` using [viem](https://viem.sh/docs/clients/public). All SDK classes require these as constructor arguments. - -## Contract Addresses - -Get the deployed contract addresses from the network config: +For most use cases, install `@x402r/sdk` and `viem`: -```typescript -import { getNetworkConfig } from '@x402r/core'; + +```bash npm +npm install @x402r/sdk viem +``` + +```bash pnpm +pnpm add @x402r/sdk viem +``` + +```bash bun +bun add @x402r/sdk viem +``` + + +For low-level access (types, ABIs, deploy utilities, config only): + + +```bash npm +npm install @x402r/core viem +``` -const config = getNetworkConfig('eip155:84532'); // Base Sepolia +```bash pnpm +pnpm add @x402r/core viem +``` -console.log(config.authCaptureEscrow); // Escrow contract -console.log(config.refundRequest); // RefundRequest contract -console.log(config.arbiterRegistry); // ArbiterRegistry contract -console.log(config.usdc); // USDC token address +```bash bun +bun add @x402r/core viem ``` + + +For x402 server integration (marking payment options as refundable): + + +```bash npm +npm install @x402r/helpers @x402r/evm +``` + +```bash pnpm +pnpm add @x402r/helpers @x402r/evm +``` + +```bash bun +bun add @x402r/helpers @x402r/evm +``` + -Network identifiers use the [EIP-155](https://eips.ethereum.org/EIPS/eip-155) format: `eip155:`. For Base Sepolia, use `'eip155:84532'`. For Base Mainnet, use `'eip155:8453'`. +`@x402r/evm` is a peer dependency of `@x402r/helpers`. It provides the escrow scheme types used by the `refundable()` helper. +## Create viem Clients + +All SDK methods operate through viem's `PublicClient` and `WalletClient`. Create them for your target chain: + +```typescript +import { createPublicClient, createWalletClient, http } from 'viem' +import { baseSepolia } from 'viem/chains' +import { privateKeyToAccount } from 'viem/accounts' + +const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`) + +const publicClient = createPublicClient({ + chain: baseSepolia, + transport: http(), +}) + +const walletClient = createWalletClient({ + account, + chain: baseSepolia, + transport: http(), +}) +``` + Never commit private keys to version control. Use environment variables or a secrets manager. +## Get Chain Config + +Retrieve USDC addresses, factory addresses, and condition singletons for any supported chain: + +```typescript +import { getChainConfig } from '@x402r/sdk' + +const config = getChainConfig(84532) // Base Sepolia + +console.log(config.usdc) // USDC token address +console.log(config.factories.paymentOperator) // PaymentOperator factory +console.log(config.conditions.payer) // Payer condition singleton +``` + + +V2 uses numeric `chainId` (e.g. `84532`). The CAIP-2 format (`'eip155:84532'`) is only needed for `toNetworkId()` / `fromNetworkId()` interop. + + ## Next Steps - - Learn about payment states, escrow, and the refund lifecycle. + + Configure and instantiate the x402r client. - - Working examples for merchants, clients, and arbiters. + + Type imports, role narrowing, and error types. diff --git a/sdk/overview.mdx b/sdk/overview.mdx index c0e9ceb..e66c8d1 100644 --- a/sdk/overview.mdx +++ b/sdk/overview.mdx @@ -1,49 +1,78 @@ --- title: "SDK Overview" -description: "TypeScript SDK for the X402r refundable payments protocol (experimental)" +description: "TypeScript SDK for the x402r refundable payments protocol" icon: "cube" --- - -The X402r SDK is in active development (v0.0.2). APIs may change between releases. Always test on Base Sepolia before using real funds on mainnet. - - -The X402r SDK provides a complete TypeScript implementation for integrating with the X402r refundable payments protocol. It enables clients, merchants, and arbiters to interact with smart contracts for payment authorization, escrow management, and dispute resolution. +The x402r SDK provides TypeScript bindings for the x402r refundable payments protocol. It covers payment authorization, escrow, dispute resolution, and event monitoring across 12 EVM chains. ## Packages -The SDK is organized into packages designed for specific roles in the payment ecosystem: - - - Shared types, ABIs, network config, deploy utilities, and condition builders. + + Client factory, role presets, action groups, watch, and extend. - - SDK for payers to request refunds, freeze payments, and manage escrow. + + Types, ABIs, chain config, deploy utilities, and low-level viem actions. - - SDK for merchants to release payments, charge, and handle refunds. + + refundable() helper for x402 server integration. - - SDK for arbiters to resolve disputes and manage refund decisions. + + +## Action Groups + +`createX402r()` returns a client with action groups organized by domain. Some groups require optional contract addresses in the config. + +| Group | Methods | Requirement | +|-------|---------|-------------| +| `payment` | 9 | Always available | +| `escrow` | 3 | Requires `escrowPeriodAddress` | +| `refund` | 15 | Requires `refundRequestAddress` | +| `evidence` | 4 | Requires `refundRequestEvidenceAddress` | +| `freeze` | 3 | Requires `freezeAddress` | +| `query` | 3 | Requires `paymentIndexRecorderAddress` | +| `operator` | 8 | Always available | +| `watch` | 4 | Always available | + +Groups that require an address are `undefined` when that address is not provided. See [Create a Client](/sdk/create-client) for configuration details. + +## Role Presets + +Three preset factories narrow the client type for each role: + +- `createPayerClient(config)` — payer-scoped methods (request refund, freeze, query state) +- `createMerchantClient(config)` — merchant-scoped methods (authorize, charge, release, approve refund) +- `createArbiterClient(config)` — arbiter-scoped methods (deny, refuse, approve refund, unfreeze) + +These provide type narrowing for a better DX. They are not a security boundary — on-chain access control is enforced by [conditions](/contracts/conditions/overview). + +## Supported Networks + +All protocol contracts are deployed at the same addresses on every chain via CREATE3. + +| Chain | Chain ID | USDC Address | +|-------|----------|-------------| +| Base Sepolia | 84532 | `0x036CbD53842c5426634e7929541eC2318f3dCF7e` | +| Ethereum Sepolia | 11155111 | `0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238` | +| Arbitrum Sepolia | 421614 | `0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d` | +| Ethereum | 1 | `0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48` | +| Base | 8453 | `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` | +| Polygon | 137 | `0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359` | +| Arbitrum One | 42161 | `0xaf88d065e77c8cC2239327C5EDb3A432268e5831` | +| Optimism | 10 | `0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85` | +| Celo | 42220 | `0xcebA9300f2b948710d2653dD7B07f33A8B32118C` | +| Avalanche C-Chain | 43114 | `0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E` | +| Monad | 143 | `0x754704Bc059F8C67012fEd69BC8a327a5aafb603` | +| Linea | 59144 | `0x176211869cA2b568f2A7D4EE941E073a821EE1ff` | + +## Next Steps + + + + Install packages and set up viem clients. - - Framework-agnostic helper to mark x402 payment options as refundable with escrow configuration. + + Configure and instantiate the x402r client. - -## Network Support - -| Network | Chain ID | Status | -|---------|----------|--------| -| Base Sepolia | 84532 | Tested | -| Base Mainnet | 8453 | Deployed, not yet tested | -| Ethereum | 1 | Deployed, not yet tested | -| Ethereum Sepolia | 11155111 | Deployed, not yet tested | -| Arbitrum Sepolia | 421614 | Deployed, not yet tested | -| Polygon | 137 | Deployed, not yet tested | -| Arbitrum | 42161 | Deployed, not yet tested | -| Optimism | 10 | Deployed, not yet tested | -| Avalanche | 43114 | Deployed, not yet tested | -| Celo | 42220 | Deployed, not yet tested | -| Monad | 143 | Deployed, not yet tested | diff --git a/sdk/typescript.mdx b/sdk/typescript.mdx new file mode 100644 index 0000000..74a6d83 --- /dev/null +++ b/sdk/typescript.mdx @@ -0,0 +1,137 @@ +--- +title: "TypeScript" +description: "Type imports, role narrowing, and error types" +icon: "code" +--- + +## Requirements + +- TypeScript 5.0+ +- `strict: true` in `tsconfig.json` +- `moduleResolution: "bundler"` or `"node16"` + +## Type Imports + +Import types from `@x402r/sdk`: + +```typescript +import type { + PaymentInfo, + X402rConfig, + X402r, + PayerClient, + MerchantClient, + ArbiterClient, + PaymentActions, + RefundActions, + EscrowActions, + EvidenceActions, + FreezeActions, + QueryActions, + OperatorActions, + WatchActions, + PaymentStore, +} from '@x402r/sdk' +``` + +All core types (`PaymentInfo`, `ConditionSlot`, `FeeAddresses`, etc.) are re-exported from `@x402r/sdk` so you don't need to depend on `@x402r/core` directly. + +## Role Narrowing + +Each role preset returns a client type that restricts available methods via TypeScript `Pick` types. This guides developers toward the correct methods for their role without needing to read the full API surface. + +### PayerClient + +| Group | Available Methods | +|-------|-------------------| +| `payment` | `getState`, `getAmounts` | +| `refund` | `request`, `cancel`, `get`, `getByKey`, `getStatus`, `has`, `getStoredPaymentInfo`, `getPayerRequests`, `getCancelCount`, `getCancelledAmount` | +| `freeze` | `isFrozen`, `freeze` | +| `evidence` | All methods | +| `escrow` | All methods | +| `query` | All methods | +| `operator` | `getConfig`, `getFeeAddresses` | +| `watch` | All methods | + +### MerchantClient + +| Group | Available Methods | +|-------|-------------------| +| `payment` | `authorize`, `charge`, `release`, `refundPostEscrow`, `approvePostEscrowRefund`, `getPostEscrowRefundAllowance`, `getState`, `getAmounts` | +| `refund` | `approve`, `get`, `getByKey`, `getStatus`, `has`, `getStoredPaymentInfo`, `getReceiverRequests`, `getCancelCount`, `getCancelledAmount` | +| `freeze` | `isFrozen` | +| `evidence` | All methods | +| `escrow` | All methods | +| `query` | All methods | +| `operator` | All methods | +| `watch` | All methods | + +### ArbiterClient + +| Group | Available Methods | +|-------|-------------------| +| `payment` | `getState`, `getAmounts` | +| `refund` | `deny`, `refuse`, `approve`, `get`, `getByKey`, `getStatus`, `has`, `getStoredPaymentInfo`, `getOperatorRequests`, `getCancelCount`, `getCancelledAmount` | +| `freeze` | `isFrozen`, `unfreeze` | +| `evidence` | All methods | +| `escrow` | All methods | +| `query` | All methods | +| `operator` | `getConfig`, `getFeeAddresses`, `getAccumulatedProtocolFees`, `distributeFees` | +| `watch` | All methods | + + +Role narrowing is a DX improvement, not a security boundary. On-chain access control is enforced by [conditions](/contracts/conditions/overview). A payer could use `createX402r()` to call `payment.authorize()`, but the transaction would revert if the on-chain condition disallows it. + + +## Conditional Action Groups + +The `escrow`, `refund`, `evidence`, `freeze`, and `query` groups are typed as `T | undefined` on every client type. They are `undefined` when the corresponding address is not provided in the config: + +```typescript +const client = createX402r({ + publicClient, + operatorAddress: '0x...', + // No escrowPeriodAddress provided +}) + +// TypeScript knows this could be undefined +client.escrow // EscrowActions | undefined + +// Use optional chaining +const inEscrow = await client.escrow?.isDuringEscrow(paymentInfo) +``` + +This design reflects the protocol: these contracts are periphery — not every operator deploys them. If you know the address exists, use a non-null assertion or provide it in the config. + +## Error Types + +The SDK exports three error classes, all extending a base `X402rError`: + +| Error | Thrown When | +|-------|------------| +| `ValidationError` | `walletClient` is missing for a role preset, `refundRequestEvidenceAddress` is provided without `refundRequestAddress`, or chain cannot be determined from config | +| `ConfigError` | The `chainId` is not in the supported chains list | +| `ContractCallError` | A contract read or write call fails on-chain | + +```typescript +import { ValidationError, ConfigError, ContractCallError } from '@x402r/sdk' + +try { + const client = createPayerClient({ publicClient, operatorAddress: '0x...' }) +} catch (e) { + if (e instanceof ValidationError) { + // walletClient is required for createPayerClient + } +} +``` + +## Next Steps + + + + Full config reference and usage examples. + + + On-chain architecture and condition system. + +