UNPKG

@zkp2p/client-sdk

Version:

Browser-first TypeScript SDK for ZKP2P with React hooks, unified authentication, and peerauth extension integration

1,039 lines (855 loc) 30.6 kB
# @zkp2p/client-sdk [![npm version](https://img.shields.io/npm/v/@zkp2p/client-sdk.svg)](https://www.npmjs.com/package/@zkp2p/client-sdk) [![GitHub Release](https://img.shields.io/github/v/release/zkp2p/zkp2p-client-sdk?display_name=tag)](https://github.com/zkp2p/zkp2p-client-sdk/releases) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![TypeScript](https://img.shields.io/badge/TypeScript-5.0%2B-blue)](https://www.typescriptlang.org/) Browser-first TypeScript SDK for integrating ZKP2P into web applications. Built with React hooks, unified authentication, and comprehensive type safety. ## Features - **Unified Authentication**: Single method for authentication and proof generation - **React Hooks**: Complete set of hooks for seamless React integration - **Enhanced Callbacks**: Granular progress tracking and error handling - **Comprehensive Constants**: All platforms, currencies, and chain data exported - **TypeScript First**: Full type safety and IntelliSense support - **Multi-Chain Support**: Base (Production & Staging), Base Sepolia, and Hardhat networks - **Extension Integration**: Built-in support for peerauth browser extension - **Payment Platforms**: Support for Venmo, Revolut, CashApp, Wise, MercadoPago, Zelle, PayPal, and Monzo - **Data Enrichment**: Automatic enrichment of intents and deposits with payment metadata ## Project Structure - `@zkp2p/client-sdk` root export exposes the current stable client and types. - Versioned subpaths: - `@zkp2p/client-sdk/v1` — current stable surface (recommended import) - `@zkp2p/client-sdk/v2` — scaffold for future API; intentionally minimal - Browser-only helpers under `@zkp2p/client-sdk/extension` (peerauth helpers, metadata orchestration). ## Installation ```bash npm install @zkp2p/client-sdk viem # or yarn add @zkp2p/client-sdk viem # or pnpm add @zkp2p/client-sdk viem ``` ## Releases - GitHub Releases: https://github.com/zkp2p/zkp2p-client-sdk/releases - Changelog (package): ./CHANGELOG.md ## Quick Start ### Versioned Imports (Recommended) Google-style subpath imports provide compile-time isolation between API versions and better tree-shaking: ```ts // Explicitly target v1 (current stable) import { Zkp2pClient } from '@zkp2p/client-sdk/v1'; // v2 scaffold exists but is not yet implemented in this package version // import { createClient } from '@zkp2p/client-sdk/v2'; ``` The root import `@zkp2p/client-sdk` continues to expose the current default (v1) for backward compatibility. ### Basic Client Setup ```typescript import { Zkp2pClient, SUPPORTED_CHAIN_IDS } from '@zkp2p/client-sdk/v1'; import { createWalletClient, custom } from 'viem'; import { base } from 'viem/chains'; // Create viem wallet client const walletClient = createWalletClient({ chain: base, transport: custom(window.ethereum), }); // Initialize ZKP2P client (Production) const client = new Zkp2pClient({ walletClient, apiKey: 'YOUR_API_KEY', chainId: SUPPORTED_CHAIN_IDS.BASE_MAINNET, // 8453 environment: 'production', // optional, defaults to 'production' }); // Or use staging environment for Base mainnet const stagingClient = new Zkp2pClient({ walletClient, apiKey: 'YOUR_API_KEY', chainId: SUPPORTED_CHAIN_IDS.BASE_MAINNET, // 8453 environment: 'staging', // Use staging contract addresses }); ``` ### Fetching Quotes ```typescript import { Currency, PAYMENT_PLATFORMS } from '@zkp2p/client-sdk/v1'; // Get quotes for multiple platforms const quotes = await client.getQuote({ paymentPlatforms: ['wise', 'revolut', 'venmo'], fiatCurrency: Currency.USD, user: '0xYourAddress', recipient: '0xRecipientAddress', destinationChainId: SUPPORTED_CHAIN_IDS.BASE_MAINNET, destinationToken: client.getUsdcAddress(), amount: '100', // $100 USD }); console.log('Available quotes:', quotes); ``` ### Register Payee Details (payeeHash) ```typescript // 1) Validate platform-specific details const validation = await client.validatePayeeDetails({ processorName: 'mercadopago', depositData: { identifier: 'user@example.com', accountHolderName: 'Alice Doe' }, }); if (!validation.responseObject.isValid) { console.error('Invalid payee details:', validation.responseObject.errors); throw new Error('Please correct payee details'); } // 2) Register details to obtain a payeeHash (hashedOnchainId) const created = await client.registerPayeeDetails({ processorName: 'mercadopago', depositData: { identifier: 'user@example.com', accountHolderName: 'Alice Doe' }, }); const payeeHash = created.responseObject.hashedOnchainId; // aka payeeHash ``` ### Validate and Register (one call) ```typescript const { isValid, validation, registration } = await client.validateAndRegisterPayeeDetails({ processorName: 'mercadopago', depositData: { identifier: 'user@example.com', accountHolderName: 'Alice Doe' }, }); if (!isValid) { console.error('Invalid details', validation.responseObject); } const payeeHash = registration?.responseObject.hashedOnchainId; ``` ### Listing Registered Payees ```typescript const { responseObject: makers } = await client.listPayees('mercadopago'); makers.forEach(m => console.log(m.processorName, m.hashedOnchainId)); ``` ### Intents by Recipient ```typescript const intents = await client.getIntentsByRecipient({ recipientAddress: '0xRecipient', status: ['SIGNALED','FULFILLED'] }); ``` ### Deposit Spreads (Maker dashboards) ```typescript // Read await client.getDepositSpread(123); await client.listDepositSpreads(); await client.getSpreadsByDepositIds([1,2,3]); // Write await client.createSpread({ depositId: 123, spread: 0.01, minPrice: null, maxPrice: null }); await client.updateSpread(123, { spread: 0.0125 }); await client.upsertSpread(123, { spread: 0.01 }); await client.deleteSpread(123); ``` ## SSR Usage (Next.js, Remix) The `extension` entry is browser-only. When server-rendering, guard access and use dynamic import: ```ts // Safe access pattern const isBrowser = typeof window !== 'undefined'; if (isBrowser) { const { ExtensionMetadataFlow } = await import('@zkp2p/client-sdk/extension'); // use ExtensionMetadataFlow } ``` In React frameworks (Next.js), prefer `dynamic(() => import('@zkp2p/client-sdk/extension'), { ssr: false })` for UI components that rely on the extension. ## Security Notes - Do not commit API keys. Provide `apiKey` (or `authorizationToken`) at runtime via app config. - Extension messaging validates `event.origin`. Only listen to trusted origins and propagate data defensively. - Validate user-provided payee details with `validatePayeeDetails` before registering or signaling intents. ## Quality & Tooling - Lint: `npm run lint` (ESLint with TypeScript + import and Prettier compatibility) - Format: `npm run format` / `npm run format:write` (Prettier) - Types: `npm run typecheck` (strict TS) - Tests: `npm run test` (Vitest unit tests) - Build: `npm run build` (tsup ESM/CJS + d.ts) ## Contributing & Development ```bash cd packages/client-sdk npm ci npm run build npm run test npm run lint && npm run format ``` We follow Conventional Commits for releases. See `PUBLISHING.md` for package publishing guidance. ### Auth Options Client supports both `x-api-key` and optional `Authorization: Bearer <token>` for hybrid auth. ```typescript const client = new Zkp2pClient({ walletClient, apiKey: 'YOUR_API_KEY', authorizationToken: 'JWT_OR_OAUTH_TOKEN', chainId: 8453, }); ``` ### Statuses and Types - Orders API statuses: `SIGNALED | FULFILLED | PRUNED`. SDK returns these for API history calls. - On-chain views remain exposed via `getAccountDeposits`/`getAccountIntent` parsers. - Historical responses automatically convert ISO timestamps into `Date` objects. ## React Integration ### Complete React Example ```tsx import React, { useState } from 'react'; import { useZkp2pClient, useQuote, useSignalIntent, useCreateDeposit, useFulfillIntent, useExtensionOrchestrator, PLATFORM_METADATA, Currency, type PaymentPlatformType } from '@zkp2p/client-sdk/v1'; function ZKP2PApp() { const [selectedPlatform, setSelectedPlatform] = useState<PaymentPlatformType>('venmo'); // Initialize client with hooks const { client, isInitialized, error: clientError } = useZkp2pClient({ walletClient: window.walletClient, // Your viem wallet client apiKey: process.env.REACT_APP_ZKP2P_API_KEY!, chainId: 8453, // Base mainnet }); // Quote management const { fetchQuote, quote, isLoading: quoteLoading, error: quoteError } = useQuote({ client, onSuccess: (quote) => { console.log('Quote received:', quote); }, onError: (error) => { console.error('Quote error:', error); }, }); // Signal intent hook const { signalIntent, response: intentResponse, isLoading: intentLoading } = useSignalIntent({ client, onSuccess: (response) => { console.log('Intent signaled:', response); }, }); // Extension orchestrator for proof generation const { authenticate, payments, proofs, proofBytes, isAuthenticating, isGeneratingProof, progress, error: proofError, } = useExtensionOrchestrator({ debug: true, autoDispose: true, }); // Fulfill intent with proof const { fulfillIntent, txHash, isLoading: fulfillLoading } = useFulfillIntent({ client, onSuccess: (hash) => { console.log('Intent fulfilled! Transaction:', hash); }, }); // Handle authentication and proof generation const handleAuthenticateAndProve = async () => { if (!intentResponse?.intentHash) { alert('Please signal an intent first'); return; } const result = await authenticate(selectedPlatform, { autoGenerateProof: { intentHashHex: intentResponse.intentHash, itemIndex: 0, onProofGenerated: (proofs) => { console.log('Proofs generated:', proofs); }, onProofError: (error) => { console.error('Proof generation failed:', error); }, onProgress: (progress) => { console.log('Progress:', progress); }, }, onPaymentsReceived: (payments) => { console.log('Payments received:', payments); }, }); // Automatically fulfill intent with generated proofs if (result?.proofs && intentResponse?.intentHash) { await fulfillIntent({ intentHash: intentResponse.intentHash, paymentProofs: result.proofs.map(proof => ({ proof })), }); } }; // Handle quote fetching const handleFetchQuote = async () => { await fetchQuote({ paymentPlatforms: [selectedPlatform], fiatCurrency: Currency.USD, user: '0xYourAddress', recipient: '0xRecipientAddress', destinationChainId: 8453, destinationToken: client?.getUsdcAddress() || '0x', amount: '100', }); }; if (!isInitialized) { return <div>Initializing ZKP2P client...</div>; } if (clientError) { return <div>Error initializing client: {clientError.message}</div>; } return ( <div className="zkp2p-app"> <h1>ZKP2P Integration</h1> {/* Platform Selection */} <div className="platform-selector"> <h2>Select Payment Platform</h2> {Object.entries(PLATFORM_METADATA).map(([key, platform]) => ( <button key={key} onClick={() => setSelectedPlatform(key as PaymentPlatformType)} className={selectedPlatform === key ? 'selected' : ''} > {platform.logo} {platform.displayName} </button> ))} </div> {/* Quote Section */} <div className="quote-section"> <h2>Get Quote</h2> <button onClick={handleFetchQuote} disabled={quoteLoading}> {quoteLoading ? 'Fetching...' : 'Fetch Quote'} </button> {quote && ( <div className="quote-display"> <h3>Quote Details:</h3> <pre>{JSON.stringify(quote, null, 2)}</pre> </div> )} {quoteError && <div className="error">Error: {quoteError.message}</div>} </div> {/* Authentication & Proof Generation */} <div className="proof-section"> <h2>Generate Payment Proof</h2> <button onClick={handleAuthenticateAndProve} disabled={isAuthenticating || isGeneratingProof} > {isAuthenticating ? 'Authenticating...' : isGeneratingProof ? `Generating Proof... ${progress?.stage || ''}` : 'Authenticate & Generate Proof'} </button> {/* Display progress */} {progress && ( <div className="progress"> <p>Stage: {progress.stage}</p> <p>Proof Index: {progress.proofIndex}</p> {progress.message && <p>Message: {progress.message}</p>} </div> )} {/* Display generated proofs */} {proofs && ( <div className="proof-display"> <h3>Generated Proofs:</h3> <p>Number of proofs: {proofs.length}</p> <p>Proof bytes: {proofBytes}</p> </div> )} {/* Display errors */} {proofError && <div className="error">Error: {proofError.message}</div>} </div> {/* Transaction Status */} {txHash && ( <div className="success"> <h3>✅ Transaction Successful!</h3> <p>Hash: {txHash}</p> <a href={`https://basescan.org/tx/${txHash}`} target="_blank" rel="noopener noreferrer" > View on BaseScan </a> </div> )} </div> ); } export default ZKP2PApp; ``` ### Individual Hook Examples #### `useCreateDeposit` - Create Liquidity Deposits ```tsx import { useCreateDeposit, Currency, type CreateDepositConversionRate } from '@zkp2p/client-sdk/v1'; function DepositCreator() { const { client } = useZkp2pClient({ /* ... */ }); const { createDeposit, txHash, depositDetails, isLoading, error } = useCreateDeposit({ client, onSuccess: ({ hash, depositDetails }) => { console.log('Deposit created:', hash); console.log('Deposit details:', depositDetails); }, }); const handleCreateDeposit = async () => { const conversionRates: CreateDepositConversionRate[][] = [[ { currency: Currency.USD, conversionRate: '1000000' }, // 1:1 USD ]]; await createDeposit({ token: client!.getUsdcAddress(), amount: BigInt('1000000'), // 1 USDC intentAmountRange: { min: BigInt('500000'), // 0.5 USDC minimum max: BigInt('2000000'), // 2 USDC maximum }, conversionRates, processorNames: ['venmo'], depositData: [{ venmoUsername: 'alice123', }], }); }; return ( <button onClick={handleCreateDeposit} disabled={isLoading}> {isLoading ? 'Creating Deposit...' : 'Create Deposit'} </button> ); } ``` #### `useSignalIntent` - Signal Trading Intent ```tsx import { useSignalIntent, Currency } from '@zkp2p/client-sdk/v1'; function IntentSignaler() { const { client } = useZkp2pClient({ /* ... */ }); const { signalIntent, response, isLoading } = useSignalIntent({ client, onSuccess: (response) => { console.log('Intent hash:', response.intentHash); console.log('Timestamp:', response.timestamp); }, }); const handleSignalIntent = async () => { await signalIntent({ processorName: 'wise', depositId: '123', tokenAmount: '1000000', // 1 USDC payeeDetails: JSON.stringify({ email: 'alice@example.com', accountNumber: '12345678', }), toAddress: '0xRecipientAddress', currency: Currency.USD, }); }; return ( <button onClick={handleSignalIntent} disabled={isLoading}> {isLoading ? 'Signaling...' : 'Signal Intent'} </button> ); } ``` ## Extension Integration ### Unified Authentication Flow (Recommended) ```typescript import { PLATFORM_METADATA } from '@zkp2p/client-sdk/v1'; import { ExtensionOrchestrator } from '@zkp2p/client-sdk/extension'; async function authenticateAndGenerateProof() { const orchestrator = new ExtensionOrchestrator({ debug: true, metadataTimeoutMs: 60000, }); try { // Single call for authentication and proof generation const result = await orchestrator.authenticateAndGenerateProof('revolut', { paymentMethod: 1, autoGenerateProof: { intentHashHex: '0x123...abc', itemIndex: 0, onProofGenerated: (proofs) => { console.log(`✅ Generated ${proofs.length} proof(s)`); }, onProofError: (error) => { console.error('❌ Proof generation failed:', error); }, onProgress: (progress) => { console.log(`⏳ ${progress.stage} - Proof ${progress.proofIndex + 1}`); }, }, onPaymentsReceived: (payments) => { console.log(`📱 Received ${payments.length} payments`); }, }); // Access results console.log('Payments:', result.payments); console.log('Proofs:', result.proofs); console.log('Proof bytes:', result.proofBytes); // Submit to blockchain if (result.proofs && result.proofBytes) { await client.fulfillIntent({ intentHash: '0x123...abc', paymentProofs: result.proofs.map(p => ({ proof: p })), }); } } finally { orchestrator.dispose(); } } ``` ### Manual Proof Generation Flow ```typescript import { ExtensionProofFlow, ExtensionMetadataFlow, metadataUtils, intentHashHexToDecimalString, assembleProofBytes } from '@zkp2p/client-sdk/extension'; async function manualProofFlow() { // Step 1: Get payment metadata const metaFlow = new ExtensionMetadataFlow({ debug: true }); const payments = await new Promise((resolve) => { const unsub = metaFlow.subscribe((platform, record) => { if (platform === 'venmo') { const visible = metadataUtils.filterVisible(record.metadata); const sorted = metadataUtils.sortByDateDesc(visible); unsub(); resolve(sorted); } }); // Request metadata from extension metaFlow.requestMetadata('list_transactions', 'venmo'); }); // Step 2: User selects a payment const selectedPayment = payments[0]; // In real app, let user choose // Step 3: Generate proof(s) const proofFlow = new ExtensionProofFlow({ debug: true }); const proofs = await proofFlow.generateProofs( 'venmo', intentHashHexToDecimalString('0x123...abc'), selectedPayment.originalIndex, { requiredProofs: 1, // Venmo requires 1 proof timeoutMs: 120000, pollIntervalMs: 3000, }, (progress) => { console.log('Progress:', progress); } ); // Step 4: Build proof bytes and submit const proofBytes = assembleProofBytes(proofs, { paymentMethod: 1 }); await client.fulfillIntent({ intentHash: '0x123...abc', paymentProofs: proofs.map(p => ({ proof: p })), }); // Cleanup metaFlow.dispose(); proofFlow.dispose(); } ``` ## Working with Constants ### Platform Information ```typescript import { PAYMENT_PLATFORMS, PLATFORM_METADATA, type PaymentPlatformType } from '@zkp2p/client-sdk/v1'; // List all supported platforms console.log('Supported platforms:', PAYMENT_PLATFORMS); // ['wise', 'venmo', 'revolut', 'cashapp', 'mercadopago', 'zelle', 'paypal', 'monzo'] // Get platform metadata PAYMENT_PLATFORMS.forEach(platform => { const meta = PLATFORM_METADATA[platform]; console.log(`${meta.logo} ${meta.displayName}: ${meta.requiredProofs} proof(s) required`); }); // Type-safe platform usage function processPlatform(platform: PaymentPlatformType) { const metadata = PLATFORM_METADATA[platform]; console.log(`Processing ${metadata.displayName}...`); } ``` ### Currency Information ```typescript import { Currency, currencyInfo, type CurrencyType, type CurrencyData } from '@zkp2p/client-sdk/v1'; // Use currency constants const usdCurrency: CurrencyType = Currency.USD; const eurCurrency: CurrencyType = Currency.EUR; // Get detailed currency information const usdInfo: CurrencyData = currencyInfo[Currency.USD]; console.log(`${usdInfo.currencySymbol} - ${usdInfo.currencyName}`); // $ - United States Dollar // List all supported currencies Object.values(Currency).forEach(code => { const info = currencyInfo[code]; console.log(`${info.countryCode}: ${info.currencySymbol} ${info.currencyCode}`); }); ``` ### Chain and Contract Information ```typescript import { SUPPORTED_CHAIN_IDS, DEPLOYED_ADDRESSES, DEFAULT_BASE_API_URL, DEFAULT_WITNESS_URL, type SupportedChainId } from '@zkp2p/client-sdk'; // Supported chains console.log('Base Mainnet:', SUPPORTED_CHAIN_IDS.BASE_MAINNET); // 8453 console.log('Base Sepolia:', SUPPORTED_CHAIN_IDS.BASE_SEPOLIA); // 84532 console.log('Scroll:', SUPPORTED_CHAIN_IDS.SCROLL_MAINNET); // 534352 // Get contract addresses for a specific chain const baseContracts = DEPLOYED_ADDRESSES[SUPPORTED_CHAIN_IDS.BASE_MAINNET]; console.log('Escrow:', baseContracts.escrow); console.log('USDC:', baseContracts.usdc); console.log('Venmo Verifier:', baseContracts.venmo); // API endpoints console.log('API URL:', DEFAULT_BASE_API_URL); console.log('Witness URL:', DEFAULT_WITNESS_URL); ``` ## Advanced Usage ### On-chain Views Enrichment When fetching on-chain deposits and intents, the SDK automatically enriches the data with payment metadata when an API key is provided: ```typescript // Fetch deposits with automatic enrichment const deposits = await client.getAccountDeposits('0xYourAddress'); // Each deposit's verifiers will include: // - paymentMethod: Platform key (e.g., 'venmo', 'revolut', 'paypal') // - paymentData: Platform-specific metadata from API (when available) deposits.forEach(deposit => { deposit.verifiers.forEach(verifier => { console.log('Platform:', verifier.verificationData.paymentMethod); console.log('Payment Data:', verifier.verificationData.paymentData); }); }); // Fetch intent with automatic enrichment const intent = await client.getAccountIntent('0xYourAddress'); if (intent) { // Top-level intent includes enriched data console.log('Payment Platform:', intent.intent.paymentMethod); console.log('Payment Data:', intent.intent.paymentData); // Verifiers also include enriched data intent.deposit.verifiers.forEach(verifier => { console.log('Verifier Platform:', verifier.verificationData.paymentMethod); console.log('Verifier Data:', verifier.verificationData.paymentData); }); } ``` **Notes:** - Enrichment is best-effort and won't throw errors if it fails - `paymentMethod` is always set when the verifier is a recognized platform - `paymentData` requires a valid API key and may not always be available - The enrichment happens automatically - no additional configuration needed ### Custom Timeout Configuration ```typescript const client = new Zkp2pClient({ walletClient, apiKey: 'YOUR_API_KEY', chainId: 8453, timeouts: { api: 30000, // 30 seconds for API calls transaction: 60000, // 60 seconds for transactions proofGeneration: 120000, // 2 minutes for proof generation extension: 60000, // 60 seconds for extension communication }, }); ``` ### Error Handling ```typescript import { ZKP2PError, ValidationError, NetworkError, APIError, ContractError, ProofGenerationError, ErrorCode } from '@zkp2p/client-sdk'; try { await client.signalIntent({ /* ... */ }); } catch (error) { if (error instanceof ValidationError) { console.error('Validation failed:', error.message); console.error('Error code:', error.code); } else if (error instanceof NetworkError) { console.error('Network error:', error.message); } else if (error instanceof APIError) { console.error('API error:', error.message); } else if (error instanceof ContractError) { console.error('Smart contract error:', error.message); } else if (error instanceof ProofGenerationError) { console.error('Proof generation failed:', error.message); } else { console.error('Unknown error:', error); } } ``` ### Logging Configuration ```typescript import { logger, setLogLevel } from '@zkp2p/client-sdk/v1'; // Set log level setLogLevel('debug'); // 'debug' | 'info' | 'warn' | 'error' | 'none' // Use logger in your app logger.debug('Debug message'); logger.info('Info message'); logger.warn('Warning message'); logger.error('Error message'); ``` ### Proof Encoding Utilities ```typescript import { encodeProofAsBytes, encodeTwoProofs, encodeManyProofs, encodeProofAndPaymentMethodAsBytes, assembleProofBytes, type ReclaimProof } from '@zkp2p/client-sdk/v1'; import { parseExtensionProof } from '@zkp2p/client-sdk/extension'; // Parse proof from extension const extensionPayload = '...'; // From extension const reclaimProof: ReclaimProof = parseExtensionProof(extensionPayload); // Encode single proof const singleBytes = encodeProofAsBytes(reclaimProof); // Encode two proofs (for platforms requiring 2 proofs) const twoBytes = encodeTwoProofs(proof1, proof2); // Encode many proofs const manyBytes = encodeManyProofs([proof1, proof2, proof3]); // Add payment method to encoded bytes const taggedBytes = encodeProofAndPaymentMethodAsBytes(singleBytes, 1); // Assemble proofs with optional payment method const assembled = assembleProofBytes([proof1, proof2], { paymentMethod: 1 }); ``` ## Environment Configuration ### Vite ```bash # .env VITE_ZKP2P_API_KEY=your_api_key_here VITE_ZKP2P_RPC_URL=https://base-mainnet.g.alchemy.com/v2/your_key VITE_ZKP2P_BASE_API_URL=https://api.zkp2p.xyz/v1 VITE_ZKP2P_WITNESS_URL=https://witness-proxy.zkp2p.xyz ``` ```typescript // main.tsx import { Zkp2pClient } from '@zkp2p/client-sdk/v1'; const client = new Zkp2pClient({ walletClient, apiKey: import.meta.env.VITE_ZKP2P_API_KEY!, chainId: 8453, rpcUrl: import.meta.env.VITE_ZKP2P_RPC_URL, baseApiUrl: import.meta.env.VITE_ZKP2P_BASE_API_URL, witnessUrl: import.meta.env.VITE_ZKP2P_WITNESS_URL, }); ``` ### Next.js ```bash # .env.local NEXT_PUBLIC_ZKP2P_API_KEY=your_api_key_here NEXT_PUBLIC_ZKP2P_RPC_URL=https://base-mainnet.g.alchemy.com/v2/your_key ``` ```typescript // app/providers.tsx 'use client'; import { Zkp2pClient } from '@zkp2p/client-sdk/v1'; const client = new Zkp2pClient({ walletClient, apiKey: process.env.NEXT_PUBLIC_ZKP2P_API_KEY!, chainId: 8453, rpcUrl: process.env.NEXT_PUBLIC_ZKP2P_RPC_URL, }); ``` ### Create React App ```bash # .env REACT_APP_ZKP2P_API_KEY=your_api_key_here REACT_APP_ZKP2P_RPC_URL=https://base-mainnet.g.alchemy.com/v2/your_key ``` ```typescript // App.tsx const client = new Zkp2pClient({ walletClient, apiKey: process.env.REACT_APP_ZKP2P_API_KEY!, chainId: 8453, rpcUrl: process.env.REACT_APP_ZKP2P_RPC_URL, }); ``` ## Complete API Reference ### Client Methods | Method | Description | Returns | |--------|-------------|---------| | `getQuote(request)` | Get quotes from liquidity providers | `QuoteResponse` | | `createDeposit(params)` | Create a new liquidity deposit | `{ hash, depositDetails }` | | `signalIntent(params)` | Signal intent to trade | `SignalIntentResponse & { txHash? }` | | `fulfillIntent(params)` | Fulfill intent with payment proof | `Hash` | | `withdrawDeposit(params)` | Withdraw a deposit | `Hash` | | `cancelIntent(params)` | Cancel a pending intent | `Hash` | | `releaseFundsToPayer(params)` | Release escrowed funds | `Hash` | | `validatePayeeDetails(params)` | Validate payee information | `ValidatePayeeDetailsResponse` | | `registerPayeeDetails(params)` | Register payee and get `hashedOnchainId` | `RegisterPayeeDetailsResponse` | | `validateAndRegisterPayeeDetails(params)` | Validate then register; returns both | `{ isValid, validation, registration? }` | | `listPayees(processorName?)` | List registered payees (makers) | `PresentedMaker[]` | | `getIntentsByRecipient(params)` | Intents for a recipient address | `Intent[]` | | `getDepositSpread(id)` | Get spread for deposit | API response | | `listDepositSpreads()` | List all spreads | API response | | `getSpreadsByDepositIds(ids)` | Bulk spreads | API response | | `createSpread(body)` | Create spread | API response | | `updateSpread(id, body)` | Update spread | API response | | `upsertSpread(id, body)` | Upsert spread | API response | | `deleteSpread(id)` | Delete spread | API response | | `getAccountDeposits(address)` | Get account's deposits | `EscrowDepositView[]` | | `getAccountIntent(address)` | Get account's current intent | `EscrowIntentView` | ### React Hooks | Hook | Purpose | Key Returns | |------|---------|-------------| | `useZkp2pClient` | Initialize client | `{ client, isInitialized, error }` | | `useQuote` | Manage quotes | `{ fetchQuote, quote, isLoading, error }` | | `useSignalIntent` | Signal intents | `{ signalIntent, response, isLoading }` | | `useCreateDeposit` | Create deposits | `{ createDeposit, txHash, depositDetails }` | | `useRegisterPayeeDetails` | Register payee and get payeeHash | `{ registerPayeeDetails, response, isLoading }` | | `useValidatePayeeDetails` | Validate payee details | `{ validatePayeeDetails, response, isLoading }` | | `usePayeeRegistration` | Validate then register flow | `{ validateAndRegister, result, isLoading }` | | `useFulfillIntent` | Fulfill intents | `{ fulfillIntent, txHash, isLoading }` | | `useExtensionOrchestrator` | Extension integration | `{ authenticate, payments, proofs }` | ## Testing ```typescript // Example test setup import { Zkp2pClient } from '@zkp2p/client-sdk/v1'; import { createWalletClient, http } from 'viem'; import { hardhat } from 'viem/chains'; const testClient = new Zkp2pClient({ walletClient: createWalletClient({ chain: hardhat, transport: http(), }), apiKey: 'TEST_KEY', chainId: 31337, // Hardhat }); ``` ## Contributing We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details. ## License MIT License - see [LICENSE](LICENSE) for details. ## Links - [NPM Package](https://www.npmjs.com/package/@zkp2p/client-sdk) - [GitHub Repository](https://github.com/zkp2p/zkp2p-client-sdk) - [Documentation](https://docs.zkp2p.xyz) ## Support - GitHub Issues: [Create an issue](https://github.com/zkp2p/zkp2p-client-sdk/issues) - Email: support@zkp2p.xyz