API Reference
Core SDK

SDK Reference

Complete API reference for the Veridex Core SDK (@veridex/sdk).

Installation

npm install @veridex/sdk ethers

Initialization

createSDK

Creates a new VeridexSDK instance with sensible defaults.

import { createSDK } from '@veridex/sdk';
 
const sdk = createSDK(chain, config?);

Parameters:

ParameterTypeDescription
chainChainNameChain name (see supported chains below)
configSimpleSDKConfigOptional configuration

Supported chain names: 'base', 'optimism', 'arbitrum', 'ethereum', 'polygon', 'monad', 'solana', 'aptos', 'sui', 'starknet', 'stacks'

Config:

interface SimpleSDKConfig {
  network?: 'testnet' | 'mainnet';     // Default: 'testnet'
  rpcUrl?: string;                      // Custom RPC URL
  relayerUrl?: string;                  // Relayer for gasless transactions
  relayerApiKey?: string;               // Relayer API key
  sponsorPrivateKey?: string;           // For gasless vault creation
  integratorSponsorKey?: string;        // Platform-level sponsorship
  rpcUrls?: Record<ChainName, string>;  // Multi-chain RPC URLs
}

Example:

// Simplest — testnet by default
const sdk = createSDK('base');
 
// With relayer for gasless transactions
const sdk = createSDK('base', {
  network: 'testnet',
  relayerUrl: 'https://relayer.veridex.network',
});
 
// Stacks
const stacksSdk = createSDK('stacks', { network: 'testnet' });

VeridexSDK (Direct Constructor)

For full control over chain configuration, use the VeridexSDK class directly with an EVMClient. This is the pattern used for multi-chain support.

import { VeridexSDK } from '@veridex/sdk';
import { EVMClient } from '@veridex/sdk/chains/evm';
 
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,
  queryApiKey: process.env.NEXT_PUBLIC_WORMHOLE_QUERY_API_KEY,
  sponsorPrivateKey: process.env.NEXT_PUBLIC_VERIDEX_SPONSOR_KEY,
  chainRpcUrls: {
    10004: 'https://sepolia.base.org',
    10005: 'https://sepolia.optimism.io',
    10003: 'https://sepolia-rollup.arbitrum.io/rpc',
  },
});

Config:

interface VeridexSDKConfig {
  chain: EVMClient;                              // Hub chain client
  persistWallet?: boolean;                       // Persist wallet state (default: true)
  testnet?: boolean;                             // Use testnet (default: true)
  relayerUrl?: string;                           // Relayer URL for gasless transactions
  relayerApiKey?: string;                        // Relayer API key
  queryApiKey?: string;                          // Wormhole query API key
  sponsorPrivateKey?: string;                    // For gasless vault creation
  integratorSponsorKey?: string;                 // Platform-level sponsorship
  chainRpcUrls?: Record<number, string>;         // RPC URLs keyed by Wormhole chain ID
}

Dynamic Import (SSR-Safe)

For Next.js apps, use dynamic imports 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_RELAYER_URL,
    });
  }
  return sdkInstance;
}

Convenience Factories

import { createHubSDK, createTestnetSDK, createMainnetSDK, createSessionSDK } from '@veridex/sdk';
 
const hubSdk = createHubSDK();                    // Base hub chain
const testSdk = createTestnetSDK('optimism');      // Force testnet
const mainSdk = createMainnetSDK('base');          // Force mainnet
const sessSdk = createSessionSDK('base');          // Session-optimized

Passkey Management (sdk.passkey)

The passkey property is a PasskeyManager instance.

sdk.passkey.register

Register a new passkey with biometric authentication.

const credential = await sdk.passkey.register(username, displayName);

Parameters:

ParameterTypeDescription
usernamestringUsername (shown in passkey prompt)
displayNamestringDisplay name for the credential

Returns: Promise<PasskeyCredential>

interface PasskeyCredential {
  credentialId: string;
  publicKeyX: bigint;
  publicKeyY: bigint;
  keyHash: string;
}

sdk.passkey.authenticate

Authenticate with an existing passkey (shows passkey picker).

const { credential, signature } = await sdk.passkey.authenticate();

Returns: Promise<{ credential: PasskeyCredential; signature: WebAuthnSignature }>


sdk.passkey.getCredential

Get the currently active credential (set by register or authenticate).

const credential = sdk.passkey.getCredential();

Returns: PasskeyCredential | null


sdk.passkey.setCredential

Manually set the active credential.

sdk.passkey.setCredential(credential);

sdk.passkey.getAllStoredCredentials

Get all passkey credentials saved in local storage.

const credentials = sdk.passkey.getAllStoredCredentials();

Returns: PasskeyCredential[]


sdk.passkey.sign

Sign a challenge with the passkey.

const signature = await sdk.passkey.sign(challenge);

Returns: Promise<WebAuthnSignature>


sdk.passkey.saveToLocalStorage

Save the current credential to localStorage for auto-login on next visit.

sdk.passkey.saveToLocalStorage();

sdk.passkey.loadFromLocalStorage

Load a saved credential from localStorage.

const credential = sdk.passkey.loadFromLocalStorage();
if (credential) {
  sdk.setCredential(credential);
}

Returns: PasskeyCredential | null


sdk.passkey.hasStoredCredential

Check if a credential exists in localStorage.

const hasStored = sdk.passkey.hasStoredCredential();

Returns: boolean


sdk.passkey.saveCredentialToRelayer

Sync the credential to the relayer for cross-device recovery.

await sdk.passkey.saveCredentialToRelayer();

sdk.passkey.loadCredentialFromRelayer

Recover a credential from the relayer (cross-device login).

const credential = await sdk.passkey.loadCredentialFromRelayer();

Returns: Promise<PasskeyCredential | null>


Credential Management

sdk.setCredential

Set the active credential on the SDK instance (used after loading from storage or cross-origin auth).

sdk.setCredential(credential);

sdk.clearCredential

Clear the active credential and reset SDK state.

sdk.clearCredential();

Vault & Identity

sdk.getVaultAddress

Get the deterministic vault address derived from the passkey.

const address = sdk.getVaultAddress();

Returns: string — Same address on all EVM chains for the same passkey.


sdk.getChainConfig

Get the current chain's configuration.

const config = sdk.getChainConfig();

sdk.getUnifiedIdentity

Get the unified identity across all chains, including vault addresses, deployment status, and key hash.

const identity = await sdk.getUnifiedIdentity();

Returns: Promise<UnifiedIdentity>

interface UnifiedIdentity {
  keyHash: string;
  addresses: Array<{
    wormholeChainId: number;
    chainName: string;
    address: string;
    deployed: boolean;
  }>;
}

Example:

const identity = await sdk.getUnifiedIdentity();
const baseAddr = identity.addresses.find(a => a.wormholeChainId === 10004);
console.log('Base vault:', baseAddr?.address, 'deployed:', baseAddr?.deployed);

sdk.vaultExists

Check if the vault is deployed on the current chain.

const exists = await sdk.vaultExists();

Returns: Promise<boolean>


sdk.getReceiveAddress

Get the address that can receive tokens (vault address if deployed, otherwise the computed address).

const receiveAddr = sdk.getReceiveAddress();

Returns: string


sdk.getNonce

Get the current nonce for the authenticated passkey.

const nonce = await sdk.getNonce();

Returns: Promise<bigint>


Transfers

sdk.prepareTransfer

Prepare a transfer with gas estimation. Call this before signing to show the user costs.

const prepared = await sdk.prepareTransfer(params);

Parameters:

interface TransferParams {
  targetChain: number;   // Wormhole chain ID
  token: string;         // Token address or 'native'
  recipient: string;     // Recipient address
  amount: bigint;        // Amount in smallest unit
}

Returns: Promise<PreparedTransfer>

interface PreparedTransfer {
  params: TransferParams;
  actionPayload: string;
  nonce: bigint;
  challenge: string;
  estimatedGas: bigint;
  gasPrice: bigint;
  messageFee: bigint;
  totalCost: bigint;
  formattedCost: string;
  preparedAt: number;
  expiresAt: number;      // 5 minutes TTL
}

Example:

const prepared = await sdk.prepareTransfer({
  targetChain: 10004,
  token: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
  recipient: '0x742d35Cc6634C0532925a3b844Bc9e7595f5A234',
  amount: 1000000n,
});
 
console.log('Gas cost:', prepared.formattedCost);
console.log('Expires:', new Date(prepared.expiresAt));

sdk.executeTransfer

Execute a prepared transfer (requires a signer to pay gas).

const result = await sdk.executeTransfer(prepared, signer);

Returns: Promise<DispatchResult>

interface DispatchResult {
  transactionHash: string;
  sequence: bigint;
  userKeyHash: string;
  targetChain: number;
  blockNumber: number;
}

sdk.transferViaRelayer

Execute a gasless transfer through the relayer. The user only needs their passkey — no MetaMask or gas tokens required. This is the primary transfer method used by both the test-app and sera/dashboard.

const result = await sdk.transferViaRelayer(params);

Parameters: TransferParams (same as prepareTransfer)

Returns: Promise<TransferResult>

interface TransferResult {
  transactionHash: string;
  sequence?: bigint;
  status: 'pending' | 'confirmed' | 'failed';
}

Example:

import { ethers } from 'ethers';
 
const result = await sdk.transferViaRelayer({
  targetChain: 10004,  // Base Sepolia
  token: '0x036CbD53842c5426634e7929541eC2318f3dCF7e', // USDC
  recipient: '0x742d35Cc6634C0532925a3b844Bc9e7595f5A234',
  amount: ethers.parseUnits('10', 6), // 10 USDC
});
 
console.log('Tx:', result.transactionHash);

sdk.getTransactionSummary

Get a human-readable summary of a prepared transaction.

const summary = await sdk.getTransactionSummary(prepared);

Returns: Promise<TransactionSummary>

interface TransactionSummary {
  title: string;           // e.g., "Transfer"
  description: string;     // e.g., "Send 1.0 USDC to 0x742d...5A234"
  details: ActionDetails;
  risks: RiskWarning[];    // e.g., large_transaction, unknown_recipient
  gasCost: string;
  expiresIn: number;
}

Example:

const prepared = await sdk.prepareTransfer({ ... });
const summary = await sdk.getTransactionSummary(prepared);
 
console.log(summary.title);        // "Transfer"
console.log(summary.description);  // "Send 1.0 USDC to 0x742d...5A234"
if (summary.risks.length > 0) {
  console.warn('Risks:', summary.risks.map(r => r.message));
}

Cross-Chain Bridges

sdk.prepareBridge

Prepare a cross-chain bridge with fee estimation.

const prepared = await sdk.prepareBridge(params);

Parameters:

interface BridgeParams {
  sourceChain: number;        // Source Wormhole chain ID
  destinationChain: number;   // Destination Wormhole chain ID
  token: string;
  recipient: string;
  amount: bigint;
}

sdk.executeBridge

Execute a prepared bridge with cross-chain tracking.

const result = await sdk.executeBridge(prepared, signer, onProgress?);

Progress callback:

sdk.executeBridge(prepared, signer, (progress) => {
  console.log(`Step ${progress.step}/${progress.totalSteps}: ${progress.message}`);
  // Steps: signing → dispatching → waiting_confirmations → fetching_vaa → relaying → completed
});

sdk.bridgeViaRelayer

Execute a gasless bridge using the relayer.

const result = await sdk.bridgeViaRelayer(params, onProgress?);

sdk.bridgeWithTracking

Convenience method that prepares and executes a bridge in one call.

const result = await sdk.bridgeWithTracking(params, signer, onProgress?);

sdk.getBridgeFees

Estimate bridge fees without executing.

const fees = await sdk.getBridgeFees(params);

Returns: Promise<CrossChainFees>

interface CrossChainFees {
  sourceGas: bigint;
  messageFee: bigint;
  relayerFee: bigint;
  totalCost: bigint;
  formattedTotal: string;
  currency: string;
}

Spending Limits (sdk.spendingLimits)

sdk.getSpendingLimits

Get current on-chain spending limits for your vault.

const limits = await sdk.getSpendingLimits(chainId?);

Returns: Promise<SpendingLimits>


sdk.getFormattedSpendingLimits

Get spending limits formatted for UI display.

const formatted = await sdk.getFormattedSpendingLimits();
console.log(`${formatted.dailyUsedPercentage}% of daily limit used`);
console.log(`Resets in: ${formatted.timeUntilReset}`);

sdk.checkSpendingLimit

Check if a transaction amount is within limits.

import { ethers } from 'ethers';
 
const check = await sdk.checkSpendingLimit(ethers.parseEther('1.0'));
if (!check.allowed) {
  console.log(check.message);
  console.log('Suggestions:', check.suggestions);
}

Returns: Promise<LimitCheckResult>


sdk.prepareSetDailyLimit

Prepare a transaction to update the daily spending limit.

const prepared = await sdk.prepareSetDailyLimit(ethers.parseEther('5.0'));
// Sign and execute with sdk.executeTransfer(prepared, signer)

sdk.preparePauseVault

Prepare an emergency pause transaction.

const prepared = await sdk.preparePauseVault();

Sponsored Vault Creation

sdk.isSponsorshipAvailable

Check if the SDK has a sponsor key configured for gasless vault creation.

const canSponsor = sdk.isSponsorshipAvailable();

Returns: boolean


sdk.ensureSponsoredVaultsOnAllChains

Auto-create vaults on all configured chains using the sponsor key. No gas required from the user. This is called automatically after registration in the test-app.

const result = await sdk.ensureSponsoredVaultsOnAllChains();
console.log(`Created vaults on ${result.results.filter(r => r.success).length} chains`);

Returns: Promise<{ results: Array<{ chainId: number; success: boolean; error?: string }> }>


Token Management

sdk.getTokenList

Get the list of supported tokens on the current chain.

const tokens = sdk.getTokenList();
for (const token of tokens) {
  console.log(`${token.symbol}: ${token.address} (${token.decimals} decimals)`);
}

Returns: TokenInfo[]

interface TokenInfo {
  address: string;
  symbol: string;
  name: string;
  decimals: number;
  wormholeChainId: number;
  logoUrl?: string;
}

Balance Management

sdk.getVaultNativeBalance

Get the native token balance of the vault.

const native = await sdk.getVaultNativeBalance();
console.log(`${native.token.symbol}: ${native.formatted}`);

sdk.getVaultBalances

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);

sdk.getVaultTokenBalance

Get balance of a specific token.

const balance = await sdk.getVaultTokenBalance(tokenAddress);
console.log(`${balance.token.symbol}: ${balance.formatted}`);

sdk.getMultiChainBalances

Get balances across multiple chains.

const results = await sdk.getMultiChainBalances([10004, 10005, 10003]);
for (const chain of results) {
  console.log(`${chain.chainName}: ${chain.tokens.length} tokens`);
}

sdk.balance (Low-Level)

Direct access to the BalanceManager for advanced queries:

const portfolio = await sdk.balance.getPortfolioBalance(chainId, address);
const multi = await sdk.balance.getMultiChainBalances(address, [10004, 10005]);

Transaction Tracking (sdk.transactions)

sdk.transactions.track

Track a transaction's status.

sdk.transactions.track(txHash, chainId, callback?, sequence?);

Gas Sponsorship (sdk.sponsor)

sdk.sponsor

Gasless vault creation for new users.

const result = await sdk.sponsor.createVault(chainId, credential);

Chain Clients

The SDK provides chain-specific clients:

import {
  EVMClient,
  SolanaClient,
  AptosClient,
  SuiClient,
  StarknetClient,
  StacksClient,
} from '@veridex/sdk';

Session Key Utilities

import {
  SessionManager,
  generateSecp256k1KeyPair,
  computeSessionKeyHash,
  signWithSessionKey,
  hashAction,
  verifySessionSignature,
  deriveEncryptionKey,
  encrypt,
  decrypt,
  createSessionStorage,
} from '@veridex/sdk';

Chain Presets & Utilities

import {
  getChainConfig,
  getSupportedChains,
  getHubChains,
  isChainSupported,
  getDefaultHub,
  CHAIN_PRESETS,
  CHAIN_NAMES,
} from '@veridex/sdk';
 
// Get all supported chains
const chains = getSupportedChains('testnet');
// ['base', 'optimism', 'arbitrum', 'solana', 'aptos', 'sui', 'starknet', 'stacks']
 
// Get chain config
const config = getChainConfig('stacks', 'testnet');
console.log('Wormhole ID:', config.wormholeChainId); // 50003

Token Constants

import {
  NATIVE_TOKEN_ADDRESS,
  BASE_SEPOLIA_TOKENS,
  TOKEN_REGISTRY,
  getTokenList,
  getTokenBySymbol,
  getTokenByAddress,
  isNativeToken,
} from '@veridex/sdk';
 
const usdc = getTokenBySymbol(10004, 'USDC');
console.log('USDC address:', usdc?.address);

ERC-8004 Utilities (erc8004/)

The core SDK provides low-level ERC-8004 contract utilities for direct registry interaction.

import {
  // Addresses
  getERC8004Addresses,
  isERC8004Chain,
  ERC8004_CHAINS,
 
  // ABIs
  IDENTITY_REGISTRY_ABI,
  IDENTITY_REGISTRY_READ_ABI,
  REPUTATION_REGISTRY_ABI,
  REPUTATION_REGISTRY_READ_ABI,
  VALIDATION_REGISTRY_ABI,
 
  // Types
  type ERC8004AgentRegistration,
  type ERC8004MetadataEntry,
  type ERC8004FeedbackEntry,
  type ERC8004FeedbackSummary,
  type ERC8004ValidationStatus,
  type UniversalAgentIdentifier,
} from '@veridex/sdk';

getERC8004Addresses

Get canonical ERC-8004 registry addresses for a network.

const addresses = getERC8004Addresses('mainnet');
// {
//   identityRegistry: '0x8004A169FB4a3325136EB29fA0ceB6D2e539a432',
//   reputationRegistry: '0x8004BAa17C55a88189AE136b182e5fdA19dE9b63',
// }
 
const testnetAddresses = getERC8004Addresses('testnet');
// {
//   identityRegistry: '0x8004A818BFB912233c491871b3d84c89A494BD9e',
//   reputationRegistry: '0x8004B663056A597Dffe9eCcC1965A193B7388713',
// }

isERC8004Chain

Check if a chain has ERC-8004 singleton registries deployed.

const supported = isERC8004Chain('base');      // true
const supported2 = isERC8004Chain('monad');    // true
const supported3 = isERC8004Chain('solana');   // false (non-EVM)

ERC8004_CHAINS

List of all chains with ERC-8004 singletons:

console.log(ERC8004_CHAINS);
// ['base', 'ethereum', 'polygon', 'arbitrum', 'optimism', 'linea', 'megaeth', 'monad', ...]

Canonical Addresses

The same singleton addresses work on every EVM chain (deployed via CREATE2):

RegistryMainnetTestnet
Identity0x8004A169FB4a3325136EB29fA0ceB6D2e539a4320x8004A818BFB912233c491871b3d84c89A494BD9e
Reputation0x8004BAa17C55a88189AE136b182e5fdA19dE9b630x8004B663056A597Dffe9eCcC1965A193B7388713

Types

Full TypeScript types are available:

import type {
  // Config
  VeridexConfig, SimpleSDKConfig, ChainConfig, ChainName, NetworkType,
 
  // Passkey
  PasskeyCredential, WebAuthnSignature,
 
  // Cross-Origin Authentication
  CrossOriginAuth, CrossOriginAuthConfig, CrossOriginSession,
  ServerSessionToken, AuthPortalMessage,
  createCrossOriginAuth, sendAuthResponse, sendAuthError,
  DEFAULT_AUTH_PORTAL_URL, DEFAULT_RELAYER_URL, AUTH_MESSAGE_TYPES,
 
  // Actions
  TransferParams, ExecuteParams, BridgeParams,
  DispatchResult, PreparedTransfer, PreparedBridge,
 
  // Results
  TransferResult, BridgeResult, CrossChainFees,
 
  // Spending Limits
  SpendingLimits, FormattedSpendingLimits, LimitCheckResult,
 
  // Sessions
  SessionConfig, SessionSignature, KeyPair,
 
  // Balances
  TokenBalance, PortfolioBalance,
 
  // Transaction Summaries
  TransactionSummary, RiskWarning,
 
  // Vault & Identity
  VaultInfo, UnifiedIdentity,
 
  // ERC-8004
  ERC8004AgentRegistration, ERC8004MetadataEntry,
  ERC8004FeedbackEntry, ERC8004FeedbackSummary,
  ERC8004ValidationStatus, UniversalAgentIdentifier,
} from '@veridex/sdk';