Get Started
Quick Start

Quick Start

Build a passkey wallet and send your first transaction in under 5 minutes.

⚠️

Frontend Required: Passkey operations (register, authenticate) use WebAuthn browser APIs and must run in a client-side browser context (HTTPS or localhost). They cannot run in Node.js, server components, or terminal scripts. All code examples below must execute in a browser — either in a React/Next.js client component, a plain HTML page with a <script> tag, or any other browser environment.

1. Initialize the SDK

import { createSDK } from '@veridex/sdk';
 
// Initialize with testnet (default)
const sdk = createSDK('base', {
  network: 'testnet',
  relayerUrl: 'https://relayer.veridex.network',
});

2. Register a Passkey

// Prompt user to create a passkey with biometric
const credential = await sdk.passkey.register(
  'user@example.com',  // Username (displayed in passkey prompt)
  'My Veridex Wallet'  // Display name
);
 
console.log('Credential ID:', credential.credentialId);
console.log('Key Hash:', credential.keyHash);
console.log('Vault Address:', sdk.getVaultAddress());

The vault address is deterministic — the same passkey always generates the same address across all EVM chains.

3. Fund the Vault

For testnet, use these faucets:

ChainFaucet
Base Sepoliabase.org/faucet (opens in a new tab)
Optimism Sepoliaapp.optimism.io/faucet (opens in a new tab)
Arbitrum Sepoliafaucet.quicknode.com/arbitrum (opens in a new tab)
Stacks Testnetexplorer.hiro.so/sandbox/faucet (opens in a new tab)

4. Prepare and Execute a Transfer

// Prepare a transfer (shows gas cost before signing)
const prepared = await sdk.prepareTransfer({
  targetChain: 10004,  // Base Sepolia Wormhole chain ID
  token: '0x036CbD53842c5426634e7929541eC2318f3dCF7e', // USDC
  recipient: '0x742d35Cc6634C0532925a3b844Bc9e7595f5A234',
  amount: 1000000n, // 1 USDC (6 decimals)
});
 
// Get human-readable summary
const summary = await sdk.getTransactionSummary(prepared);
console.log(summary.title);       // "Transfer"
console.log(summary.description); // "Send 1.0 USDC to 0x742d...5A234"
console.log('Gas cost:', prepared.formattedCost);
 
// Execute with a signer (signs with passkey, then dispatches)
const result = await sdk.executeTransfer(prepared, signer);
console.log('Transaction hash:', result.transactionHash);

5. Check Spending Limits

import { ethers } from 'ethers';
 
// Check current limits
const limits = await sdk.getSpendingLimits();
console.log('Daily remaining:', limits.dailyRemaining);
 
// Check if a specific amount is allowed
const check = await sdk.checkSpendingLimit(ethers.parseEther('1.0'));
if (check.allowed) {
  console.log('Transfer allowed!');
} else {
  console.log('Blocked:', check.message);
}
 
// Get formatted limits for UI
const formatted = await sdk.getFormattedSpendingLimits();
console.log(`${formatted.dailyUsedPercentage}% of daily limit used`);

6. Check Balances

// Get all token balances on the current chain
const portfolio = await sdk.getVaultBalances();
 
for (const entry of portfolio.tokens) {
  console.log(`${entry.token.symbol}: ${entry.formatted}`);
}
console.log('Total USD:', portfolio.totalUsdValue);

Complete Example

import { createSDK } from '@veridex/sdk';
import { ethers } from 'ethers';
 
async function main() {
  // 1. Initialize
  const sdk = createSDK('base', {
    network: 'testnet',
    relayerUrl: 'https://relayer.veridex.network',
  });
 
  // 2. Check if user has existing passkeys
  const storedCredentials = sdk.passkey.getAllStoredCredentials();
 
  if (storedCredentials.length === 0) {
    // 3. Register new passkey (prompts biometric)
    console.log('Registering passkey...');
    await sdk.passkey.register('user@example.com', 'My Wallet');
  } else {
    // 4. Authenticate with existing passkey (shows passkey picker)
    console.log('Logging in...');
    await sdk.passkey.authenticate();
  }
 
  // 5. Get vault info
  const vault = sdk.getVaultAddress();
  console.log('Vault:', vault);
 
  // 6. Check spending limits
  const limits = await sdk.getSpendingLimits();
  console.log('Daily limit remaining:', limits.dailyRemaining);
 
  // 7. Prepare a transfer
  const prepared = await sdk.prepareTransfer({
    targetChain: 10004,
    token: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
    recipient: '0x742d35Cc6634C0532925a3b844Bc9e7595f5A234',
    amount: 100000n, // 0.1 USDC
  });
 
  // 8. Show summary to user
  const summary = await sdk.getTransactionSummary(prepared);
  console.log(`${summary.title}: ${summary.description}`);
  console.log('Gas cost:', prepared.formattedCost);
 
  if (summary.risks.length > 0) {
    console.warn('Risks:', summary.risks.map(r => r.message));
  }
}
 
main().catch(console.error);

Multi-Chain Initialization (Advanced)

For apps that need multi-chain support, use the VeridexSDK class directly with an EVMClient:

import { VeridexSDK } from '@veridex/sdk';
import { EVMClient } from '@veridex/sdk/chains/evm';
 
// Create the EVM chain client (hub chain)
const evmClient = new EVMClient({
  chainId: 84532,
  wormholeChainId: 10004,
  rpcUrl: 'https://sepolia.base.org',
  hubContractAddress: '0x66D87dE68327f48A099c5B9bE97020Feab9a7c82',
  wormholeCoreBridge: '0x79A1027a6A159502049F10906D333EC57E95F083',
  name: 'Base Sepolia',
  explorerUrl: 'https://sepolia.basescan.org',
  vaultFactory: '0xCFaEb5652aa2Ee60b2229dC8895B4159749C7e53',
  vaultImplementation: '0x0d13367C16c6f0B24eD275CC67C7D9f42878285c',
});
 
const sdk = new VeridexSDK({
  chain: evmClient,
  persistWallet: true,
  testnet: true,
  relayerUrl: '/api/relayer',
  relayerApiKey: process.env.NEXT_PUBLIC_RELAYER_API_KEY,
});

The createSDK shorthand is great for getting started. For production apps with multi-chain vaults, use VeridexSDK + EVMClient directly — see the React Integration guide.

Gasless Transfer (via Relayer)

Send tokens without the user needing gas:

// Transfer via relayer — user pays no gas
const result = await sdk.transferViaRelayer({
  targetChain: 10004,
  token: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
  recipient: '0x742d35Cc6634C0532925a3b844Bc9e7595f5A234',
  amount: 1000000n, // 1 USDC
});
 
console.log('Transaction hash:', result.transactionHash);

Agent SDK Quick Start

For AI agents that need to make autonomous payments:

import { createAgentWallet } from '@veridex/agentic-payments';
 
async function agentQuickStart() {
  // 1. Create agent with spending limits and MCP tools
  const agent = await createAgentWallet({
    masterCredential: {
      credentialId: process.env.CREDENTIAL_ID!,
      publicKeyX: BigInt(process.env.PUBLIC_KEY_X!),
      publicKeyY: BigInt(process.env.PUBLIC_KEY_Y!),
      keyHash: process.env.KEY_HASH!,
    },
    session: {
      dailyLimitUSD: 50,
      perTransactionLimitUSD: 10,
      expiryHours: 24,
      allowedChains: [10004], // Base Sepolia
    },
    mcp: { enabled: true }, // Enable MCP tools for AI model integration
    relayerUrl: 'https://relay.veridex.network',
  });
 
  // 2. Get MCP tools (for Gemini, Claude, GPT function calling)
  const tools = agent.getMCPTools();
  console.log('Available tools:', tools.map(t => t.name));
 
  // 3. Fetch paid data (x402 handled automatically)
  const response = await agent.fetch('https://paid-api.example.com/data');
  const data = await response.json();
 
  // 4. Direct payment
  const receipt = await agent.pay({
    chain: 10004,
    token: 'USDC',
    amount: '1000000',
    recipient: '0x...',
  });
 
  // 5. Check spending
  const status = agent.getSessionStatus();
  console.log(`Spent: $${status.totalSpentUSD} / $${status.limits!.dailyLimitUSD}`);
 
  // 6. Clean up
  await agent.revokeSession();
}

Next.js SSR-Safe Pattern

In Next.js, use dynamic imports to avoid SSR issues:

// lib/veridex-client.ts
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_RELAYER_URL,
    });
  }
  return sdkInstance;
}
⚠️

The await import('@veridex/sdk') ensures the SDK is only loaded in the browser, never during server-side rendering. See the Next.js Integration guide for the full pattern.

React Integration

'use client';
 
import { useState } from 'react';
import { createSDK } from '@veridex/sdk';
 
const sdk = createSDK('base', { network: 'testnet' });
 
export function WalletButton() {
  const [vault, setVault] = useState<string | null>(null);
  const [loading, setLoading] = useState(false);
 
  const handleConnect = async () => {
    setLoading(true);
    try {
      // Check for existing passkey
      const hasStored = sdk.passkey.hasStoredCredential();
      if (hasStored) {
        await sdk.passkey.authenticate();
      } else {
        await sdk.passkey.register('user@example.com', 'My Wallet');
        sdk.passkey.saveToLocalStorage();
      }
      setVault(sdk.getVaultAddress());
    } catch (error) {
      console.error('Failed to connect:', error);
    }
    setLoading(false);
  };
 
  if (vault) {
    return (
      <div>
        <p>Connected: {vault.slice(0, 6)}...{vault.slice(-4)}</p>
      </div>
    );
  }
 
  return (
    <button onClick={handleConnect} disabled={loading}>
      {loading ? 'Connecting...' : 'Connect with Passkey'}
    </button>
  );
}

Next Steps