Sera Protocol Integration
Build payment solutions with Veridex authentication and Sera DEX settlement.
Sera Protocol is a decentralized exchange with an orderbook model, enabling atomic on-chain stablecoin settlement. Combined with Veridex passkey authentication, it provides a complete payment gateway solution.
Overview
Prerequisites
Quick Start
1. Install Dependencies
bun add @veridex/sdk ethers axios2. Configure Environment
# Ethereum Sepolia RPC
NEXT_PUBLIC_RPC_URL=https://eth-sepolia.g.alchemy.com/v2/YOUR_KEY
# Sera GraphQL API
NEXT_PUBLIC_GRAPHQL_URL=https://api.goldsky.com/api/public/project_cmicv6kkbhyto01u3agb155hg/subgraphs/sera-pro/1.0.9/gn
# Settlement wallet (keep secure!)
SETTLEMENT_WALLET_KEY=your-private-key3. Initialize Services
This uses dynamic imports to avoid SSR issues in Next.js:
import { WalletManager } from '@veridex/sdk';
import { SeraService } from './sera-service';
// Veridex SDK, lazy-loaded singleton to avoid SSR issues
let sdkInstance: any = null;
export async function getVeridexSDK() {
if (!sdkInstance) {
const { createSDK } = await import('@veridex/sdk');
sdkInstance = createSDK('base', {
network: 'testnet',
relayerUrl: process.env.NEXT_PUBLIC_VERIDEX_RELAYER_URL,
relayerApiKey: process.env.NEXT_PUBLIC_RELAYER_API_KEY,
});
}
return sdkInstance;
}
// Sera for settlement
const sera = new SeraService(process.env.NEXT_PUBLIC_RPC_URL!);The await import('@veridex/sdk') pattern ensures the SDK is only loaded in the browser, never during server-side rendering. See the Next.js Integration guide for the full pattern.
Contract Addresses
| Contract | Address |
|---|---|
| Sera Router | 0x82bfe1b31b6c1c3d201a0256416a18d93331d99e |
| Market Factory | 0xe54648526027e236604f0d91413a6aad3a80c01e |
| Order Canceler | 0x53ad1ffcd7afb1b14c5f18be8f256606efb11b1b |
| Veridex VaultFactory | 0x07F608AFf6d63b68029488b726d895c4Bb593038 |
| Veridex VaultImpl | 0xD66153fccFB6731fB6c4944FbD607ba86A76a1f6 |
Payment Flow
Customer connects using Veridex passkey or WalletConnect
// Option 1: Passkey (recommended)
await veridex.passkey.authenticate();
// Option 2: WalletConnect
const { address } = await connectWalletConnect();Create a payment intent and get signing challenge
const { transferId, challenge } = await veridex.prepareTransfer({
recipient: merchantAddress,
amount: BigInt('99990000'), // 99.99 USDC (6 decimals)
token: USDC_ADDRESS,
});Biometric prompt for payment authorization
const signature = await veridex.passkey.sign(challenge);Submit signed transaction
const { txHash } = await veridex.executeTransfer(prepared, signature);Convert received payment to merchant's preferred currency
// Place limit order on Sera DEX
await sera.placeLimitBid(signer, {
market: usdcEurcMarket,
priceIndex: currentPrice,
rawAmount: amount,
});
// Poll for fill
const orders = await sera.getOrderStatus(address, market);
// Claim when filled
await sera.claimProceeds(signer, orders);Sera Service Implementation
Price Conversion
Sera uses indexed pricing:
// Price formula
price = minPrice + (tickSpace × priceIndex)
// Example: Convert $1.05 to price index
const priceIndex = (price - minPrice) / tickSpace;
// Amount conversion
quoteAmount = rawAmount × quoteUnit
rawAmount = quoteAmount / quoteUnitAlways fetch current market parameters from GraphQL before placing orders to ensure accurate price indices.
Security Best Practices
Error Handling
try {
await sera.placeLimitBid(signer, params);
} catch (error) {
if (error.message.includes('insufficient allowance')) {
// Approve tokens first
await token.approve(ROUTER_ADDRESS, amount);
await sera.placeLimitBid(signer, params);
} else if (error.message.includes('deadline')) {
// Retry with fresh deadline
params.deadline = Math.floor(Date.now() / 1000) + 3600;
} else {
throw error;
}
}Example: Complete Payment Gateway
Sera Dashboard
Full-featured payment dashboard with invoice management, payment links, and settlement tracking.
// Complete payment flow
async function processPayment(invoiceId: string) {
const invoice = await db.invoice.findUnique({ where: { id: invoiceId } });
// 1. Customer pays via Veridex
const { txHash } = await executePayment(invoice.amount);
// 2. Update invoice
await db.invoice.update({
where: { id: invoiceId },
data: { status: 'paid', paymentTxHash: txHash },
});
// 3. Settle via Sera (if currency conversion needed)
if (invoice.settlementCurrency !== invoice.paymentCurrency) {
const settlement = await settleViaSera(
invoice.amount,
invoice.paymentCurrency,
invoice.settlementCurrency
);
await db.invoice.update({
where: { id: invoiceId },
data: {
status: 'settled',
settlementTxHash: settlement.txHash,
},
});
}
// 4. Send webhook
await sendWebhook(invoice.merchantId, 'invoice.settled', invoice);
}