SDK Reference
Complete API reference for the Veridex Core SDK (@veridex/sdk).
Installation
npm install @veridex/sdk ethersInitialization
createSDK
Creates a new VeridexSDK instance with sensible defaults.
import { createSDK } from '@veridex/sdk';
const sdk = createSDK('base', {
network: 'testnet',
relayerUrl: 'https://relayer.veridex.network',
});Parameters:
| Parameter | Type | Description |
|---|---|---|
chain | ChainName | Chain name — see supported chains below |
config | SimpleSDKConfig | Optional configuration |
Supported chains: 'base', 'optimism', 'arbitrum', 'ethereum', 'polygon', 'monad', 'solana', 'aptos', 'sui', 'starknet', 'stacks'
interface SimpleSDKConfig {
network?: 'testnet' | 'mainnet';
rpcUrl?: string;
relayerUrl?: string;
relayerApiKey?: string;
sponsorPrivateKey?: string;
integratorSponsorKey?: string;
rpcUrls?: Record<ChainName, string>;
}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-optimizedVeridexSDK (Direct Constructor)
For full control, use the class directly with an EVMClient:
import { VeridexSDK, EVMClient } from '@veridex/sdk';
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,
testnet: true,
relayerUrl: '/api/relayer',
relayerApiKey: process.env.NEXT_PUBLIC_RELAYER_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',
},
});Dynamic Import (SSR-Safe)
For Next.js apps, use dynamic imports to avoid SSR issues:
let sdkInstance: VeridexSDK | null = 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;
}Passkey Management (sdk.passkey)
sdk.passkey.register
Register a new passkey with biometric authentication.
const credential = await sdk.passkey.register('alice', 'Alice Doe');| Parameter | Type | Description |
|---|---|---|
username | string | Username (shown in passkey prompt) |
displayName | string | Display name for the credential |
Returns: Promise<PasskeyCredential>
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
const credential = sdk.passkey.getCredential(); // PasskeyCredential | nullsdk.passkey.setCredential
sdk.passkey.setCredential(credential);sdk.passkey.getAllStoredCredentials
const credentials = sdk.passkey.getAllStoredCredentials(); // PasskeyCredential[]sdk.passkey.sign
const signature = await sdk.passkey.sign(challenge); // WebAuthnSignatureLocal Storage
sdk.passkey.saveToLocalStorage();
const credential = sdk.passkey.loadFromLocalStorage();
const hasStored = sdk.passkey.hasStoredCredential();Relayer Sync (Cross-Device)
await sdk.passkey.saveCredentialToRelayer();
const credential = await sdk.passkey.loadCredentialFromRelayer();Credential Management
sdk.setCredential(credential); // Set active credential
sdk.clearCredential(); // Clear active credential
const cred = sdk.getCredential(); // Get active credential
const has = sdk.hasCredential(); // Check if credential is setVault & Identity
sdk.getVaultAddress
Get the deterministic vault address derived from the passkey. Same address on all EVM chains.
const address = sdk.getVaultAddress(); // stringsdk.vaultExists
const exists = await sdk.vaultExists(); // booleansdk.getVaultInfo
const info = await sdk.getVaultInfo(targetChainId?); // VaultInfo | nullsdk.getUnifiedIdentity
const identity = await sdk.getUnifiedIdentity();
for (const addr of identity.addresses) {
console.log(`${addr.chainName}: ${addr.address} (deployed: ${addr.deployed})`);
}sdk.getMultiChainAddresses
Get vault addresses across all configured chains.
const addresses = sdk.getMultiChainAddresses();
// { 10004: '0x...', 10005: '0x...', 10003: '0x...' }Returns: Record<number, string> — Wormhole chain ID → vault address
sdk.getMultiChainPortfolio
Get combined portfolio across multiple chains.
const portfolios = await sdk.getMultiChainPortfolio([10004, 10005]);
for (const p of portfolios) {
console.log(`${p.chainName}: $${p.totalUsdValue}`);
}Returns: Promise<PortfolioBalance[]>
sdk.getChainConfig
const config = sdk.getChainConfig(); // ChainConfigsdk.getReceiveAddress
const addr = sdk.getReceiveAddress(); // ReceiveAddresssdk.getNonce
const nonce = await sdk.getNonce(); // bigintFeature Detection
sdk.supportsFeature
Check if the current chain supports a specific feature.
if (sdk.supportsFeature('sessions')) {
// Sessions are available
}
if (sdk.supportsFeature('crossChainBridge')) {
// Bridging is available
}Returns: boolean
sdk.getCapabilityMatrix
Get the full capability matrix for the current chain and platform.
const matrix = sdk.getCapabilityMatrix({
webauthnSupported: true,
conditionalUISupported: true,
platformAuthenticatorAvailable: true,
});Returns: PlatformCapabilityMatrix
Transfers
sdk.prepareTransfer
Prepare a transfer with gas estimation. Call before signing to show costs.
const prepared = await sdk.prepareTransfer({
targetChain: 10004,
token: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
recipient: '0x742d35Cc6634C0532925a3b844Bc9e7595f5A234',
amount: 1_000_000n, // 1 USDC
});
console.log('Gas cost:', prepared.formattedCost);
console.log('Expires:', new Date(prepared.expiresAt));Returns: Promise<PreparedTransfer>
sdk.executeTransfer
Execute a prepared transfer (requires a signer to pay gas).
const result = await sdk.executeTransfer(prepared, signer);
console.log('Tx:', result.transactionHash);Returns: Promise<TransferResult>
sdk.transferViaRelayer
Gasless transfer through the relayer — the primary transfer method. The user only needs their passkey.
import { ethers } from 'ethers';
const result = await sdk.transferViaRelayer({
targetChain: 10004,
token: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
recipient: '0x742d35Cc6634C0532925a3b844Bc9e7595f5A234',
amount: ethers.parseUnits('10', 6),
});Returns: Promise<TransferResult>
sdk.transferWithTracking
const result = await sdk.transferWithTracking(params, signer, (status) => {
console.log(status.state); // 'pending' → 'confirmed'
});sdk.getTransactionSummary
const summary = await sdk.getTransactionSummary(prepared);
console.log(summary.title); // "Transfer"
console.log(summary.description); // "Send 1.0 USDC to 0x742d...5A234"
console.log(summary.risks); // [{level:'warning', message:'Large transaction'}]Cross-Chain Bridges
sdk.prepareBridge
const prepared = await sdk.prepareBridge({
sourceChain: 10004,
destinationChain: 10005,
token: '0x...',
recipient: '0x...',
amount: 1_000_000n,
});sdk.executeBridge
const result = await sdk.executeBridge(prepared, signer, (progress) => {
console.log(`Step ${progress.step}/${progress.totalSteps}: ${progress.message}`);
});sdk.bridgeViaRelayer
Gasless bridge using the relayer.
const result = await sdk.bridgeViaRelayer(params, onProgress?);sdk.getBridgeFees
const fees = await sdk.getBridgeFees(params);
console.log('Total:', fees.formattedTotal); // "0.0012 ETH"Spending Limits
sdk.getSpendingLimits
Get raw on-chain spending limits.
const limits = await sdk.getSpendingLimits(chainId?);
console.log('Daily remaining:', limits.dailyRemaining);sdk.getFormattedSpendingLimits
Get spending limits formatted for UI display.
const formatted = await sdk.getFormattedSpendingLimits();
console.log(`${formatted.dailyUsedPercentage}% used`);
console.log(`Resets in: ${formatted.timeUntilReset}`);
console.log(`Per-tx limit: ${formatted.transactionLimit}`);sdk.checkSpendingLimit
Check if a transaction amount is within limits.
const check = await sdk.checkSpendingLimit(ethers.parseEther('1.0'));
if (!check.allowed) {
console.log(check.message);
console.log('Suggestions:', check.suggestions);
}sdk.prepareSetDailyLimit
const prepared = await sdk.prepareSetDailyLimit(ethers.parseEther('5.0'));
await sdk.executeTransfer(prepared, signer);sdk.preparePauseVault / sdk.prepareUnpauseVault
const pause = await sdk.preparePauseVault();
const unpause = await sdk.prepareUnpauseVault();Balance Watching
sdk.watchBalance
Subscribe to vault balance changes via polling. Returns an unsubscribe function.
const unsub = sdk.watchBalance(
(event) => {
for (const change of event.changes) {
console.log(`${change.token.symbol}: ${change.delta > 0n ? '+' : ''}${change.delta}`);
}
},
{ intervalMs: 10_000, emitInitial: true },
(error) => console.error('Watch error:', error),
);
// Later: stop watching
unsub();See the Balance Watching guide for full usage patterns.
Balance Management
sdk.getVaultBalances
const portfolio = await sdk.getVaultBalances();
for (const entry of portfolio.tokens) {
console.log(`${entry.token.symbol}: ${entry.formatted}`);
}sdk.getVaultNativeBalance
const native = await sdk.getVaultNativeBalance();
console.log(`${native.token.symbol}: ${native.formatted}`);sdk.getVaultTokenBalance
const balance = await sdk.getVaultTokenBalance(tokenAddress);sdk.getMultiChainBalances
const results = await sdk.getMultiChainBalances([10004, 10005, 10003]);Sponsored Vault Creation
sdk.isSponsorshipAvailable
const canSponsor = sdk.isSponsorshipAvailable(); // booleansdk.ensureSponsoredVaultsOnAllChains
Auto-create vaults on all configured chains using the sponsor key.
const result = await sdk.ensureSponsoredVaultsOnAllChains();
console.log(`Created on ${result.results.filter(r => r.success).length} chains`);sdk.createSponsoredVault
const result = await sdk.createSponsoredVault(10004); // Base Sepoliasdk.getSponsoredChains
const chains = sdk.getSponsoredChains();Backup Passkeys (Multi-Key Identity)
sdk.addBackupPasskey
const newCred = await sdk.passkey.register('alice-backup', 'Alice Backup');
const result = await sdk.addBackupPasskey(newCred, signer);sdk.listAuthorizedPasskeys
const keys = await sdk.listAuthorizedPasskeys();sdk.hasBackupPasskeys
const hasBackup = await sdk.hasBackupPasskeys(); // booleansdk.removePasskey
await sdk.removePasskey(keyHash, signer);Multisig (ADR-0037)
Access via sdk.multisig:
// Configure policy
await sdk.multisig.configurePolicy({
signature, threshold: 2, signer,
});
// Create proposal
const proposal = await sdk.multisig.proposeTransfer(params, signer);
// Approve
const approval = await sdk.multisig.approveProposal(proposal.proposalId, signer);
// Execute (once threshold reached)
if (approval.thresholdReached) {
const result = await sdk.multisig.executeProposal(proposal.proposalId, signer);
}See the Multisig Wallet guide for full setup.
Enterprise Manager
Orchestration layer for batch operations and admin dashboards.
import { EnterpriseManager } from '@veridex/sdk';
const enterprise = new EnterpriseManager({ sdk, maxConcurrency: 5 });enterprise.batchCreateVaults
const result = await enterprise.batchCreateVaults(
{ keyHashes: ['0xabc...', '0xdef...'], maxConcurrency: 3 },
(event) => console.log(event.type, event),
);
console.log(`${result.succeeded}/${result.total} vaults created`);enterprise.batchTransfer
const result = await enterprise.batchTransfer({
transfers: [
{ targetChain: 10004, token: USDC, recipient: '0xAlice', amount: 1_000_000n },
{ targetChain: 10004, token: USDC, recipient: '0xBob', amount: 2_000_000n },
],
signer,
maxConcurrency: 2,
});enterprise.batchSetSpendingLimits
const result = await enterprise.batchSetSpendingLimits({
updates: [
{ newLimit: ethers.parseEther('5.0') },
{ newLimit: ethers.parseEther('10.0') },
],
signer,
});enterprise.watchVaultBalance
const unsub = enterprise.watchVaultBalance(10004, vaultAddress, (event) => {
callWebhook(event);
});enterprise.getSpendingLimitsForVault
const limits = await enterprise.getSpendingLimitsForVault('0xVault...', 10004);See the Enterprise Manager guide for full patterns.
Error Handling
All SDK methods throw VeridexError with unified error codes:
import { VeridexError, VeridexErrorCode, normalizeError } from '@veridex/sdk';
try {
await sdk.transferViaRelayer(params);
} catch (err) {
if (err instanceof VeridexError) {
switch (err.code) {
case VeridexErrorCode.INSUFFICIENT_FUNDS:
showToast('Not enough tokens');
break;
case VeridexErrorCode.DAILY_LIMIT_EXCEEDED:
showToast('Daily limit reached');
break;
default:
if (err.retryable) { /* retry */ }
}
}
}See Error Handling for the full error code reference and chain-specific mappings.
Token Management
const tokens = sdk.getTokenList();
const usdc = sdk.getTokenBySymbol('USDC');Token Constants
import {
NATIVE_TOKEN_ADDRESS,
BASE_SEPOLIA_TOKENS,
TOKEN_REGISTRY,
getTokenList,
getTokenBySymbol,
getTokenByAddress,
isNativeToken,
} from '@veridex/sdk';Chain Presets & Utilities
import {
getChainConfig,
getSupportedChains,
getHubChains,
isChainSupported,
getDefaultHub,
CHAIN_PRESETS,
CHAIN_NAMES,
} from '@veridex/sdk';
const chains = getSupportedChains('testnet');
const config = getChainConfig('stacks', 'testnet');Chain 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';ERC-8004 Utilities
import {
getERC8004Addresses,
isERC8004Chain,
ERC8004_CHAINS,
IDENTITY_REGISTRY_ABI,
REPUTATION_REGISTRY_ABI,
} from '@veridex/sdk';
const addresses = getERC8004Addresses('mainnet');
const supported = isERC8004Chain('base'); // true| Registry | Mainnet | Testnet |
|---|---|---|
| Identity | 0x8004A169FB4a3325136EB29fA0ceB6D2e539a432 | 0x8004A818BFB912233c491871b3d84c89A494BD9e |
| Reputation | 0x8004BAa17C55a88189AE136b182e5fdA19dE9b63 | 0x8004B663056A597Dffe9eCcC1965A193B7388713 |
Transaction Tracking
sdk.transactions.track(txHash, chainId, (state) => {
console.log(state); // 'pending' | 'confirmed' | 'failed'
}, sequence);
const state = await sdk.waitForTransaction(txHash);Enterprise Factories
createEnterpriseSDK
import { createEnterpriseSDK } from '@veridex/sdk';
const sdk = createEnterpriseSDK(chain, {
network: 'mainnet',
multisig: { threshold: number, signers: Signer[] },
recovery: { guardians: string[], delay: number },
});Returns a VeridexSDK instance pre-configured with MultisigManager and RecoveryManager.
createHubSDK
import { createHubSDK } from '@veridex/sdk';
const sdk = createHubSDK(chain, { network: 'testnet' });Hub SDK for shared passkey credential management across multiple applications.
createSessionSDK
import { createSessionSDK } from '@veridex/sdk';
const sdk = createSessionSDK(chain, {
network: 'testnet',
sessionKeyHash: '0x...',
});Session-scoped SDK for backend services operating with a pre-existing session key.
MultisigManager
const multisig = sdk.multisig;
await multisig.propose({ to, value, data }); // Propose transaction
await multisig.approve(proposalId); // Approve as signer
await multisig.execute(proposalId); // Execute (threshold met)
await multisig.getProposal(proposalId); // Get proposal details
await multisig.listPending(); // List pending proposalsRecoveryManager
const recovery = sdk.recovery;
await recovery.initiateRecovery(newOwner); // Start recovery
await recovery.attestAsGuardian(requestId, signer); // Guardian attestation
await recovery.executeRecovery(requestId); // Execute after delay
await recovery.cancelRecovery(requestId); // Cancel (by current owner)
await recovery.getRecoveryStatus(requestId); // Check statusCrossOriginAuth
Enable Veridex passkey authentication in third-party applications. The SDK detects browser support and picks the best flow automatically.
import { createCrossOriginAuth } from '@veridex/sdk';
const auth = createCrossOriginAuth({
rpId: 'veridex.network', // default
authPortalUrl: 'https://auth.veridex.network', // default
relayerUrl: 'https://relayer.veridex.network/api/v1', // default
mode: 'popup', // 'popup' | 'redirect'
redirectUri: 'https://myapp.com/callback', // only for redirect mode
timeout: 120000, // 2 minutes default
});auth.supportsRelatedOrigins
Check if the browser supports WebAuthn Related Origin Requests (seamless, no popup).
const rorSupported = await auth.supportsRelatedOrigins(); // booleanauth.authenticate
Native passkey authentication (only works when ROR is supported).
const { credential, signature } = await auth.authenticate();
console.log('Key hash:', credential.keyHash);
console.log('Vault:', '0x' + credential.keyHash.slice(-40));auth.connectWithVeridex
Auth Portal flow (popup or redirect). Works on all browsers.
const session = await auth.connectWithVeridex();
console.log('Address:', session.address);
console.log('Credential:', session.credential.keyHash);Options:
| Parameter | Type | Description |
|---|---|---|
register | boolean | Open in registration mode |
username | string | Pre-fill username for registration |
displayName | string | Pre-fill display name |
createSession | boolean | Handle full session flow inside a single popup |
permissions | string[] | Session permissions (e.g. ['read', 'transfer']) |
expiresInMs | number | Session expiry duration in ms |
auth.authenticateAndCreateSession
Recommended. Full flow: authenticate + create a server-validated session in one call. Uses a single popup when ROR is unavailable (no double-prompt).
const { session, serverSession } = await auth.authenticateAndCreateSession({
permissions: ['read', 'transfer'],
expiresInMs: 3600000, // 1 hour
});
console.log('Vault address:', session.address);
console.log('Server session ID:', serverSession.id);
console.log('Expires at:', new Date(serverSession.expiresAt));
// Store for subsequent API calls
localStorage.setItem('veridex_session_id', serverSession.id);auth.createServerSession
Create a server-validated session token from a cross-origin session.
const serverSession = await auth.createServerSession(session);auth.validateServerSession
Validate an existing session token (returns null if expired/revoked).
const valid = await auth.validateServerSession('ses_abc123');
if (valid) {
console.log('Session valid, expires:', new Date(valid.expiresAt));
}auth.revokeServerSession
await auth.revokeServerSession('ses_abc123');auth.completeRedirectAuth
Call on your redirect callback page to extract the session from URL params.
const session = auth.completeRedirectAuth(); // CrossOriginSession | nullWalletBackupManager
PRF-based encrypted wallet backup and recovery. Backs up credentials to the relayer encrypted with a key derived from your passkey's PRF extension.
import { WalletBackupManager } from '@veridex/sdk';
const backup = new WalletBackupManager({
passkey: sdk.passkey,
relayerUrl: 'https://relayer.veridex.network/api/v1',
});backup.backupCredentials
Encrypt and store your wallet credentials on the relayer. The encryption key is derived from your passkey's PRF output — only you can decrypt it.
const result = await backup.backupCredentials(keyHash);
console.log('Archive ID:', result.archiveId);
console.log('Backed up:', result.credentialCount, 'credentials');What happens:
- SDK triggers a WebAuthn ceremony and extracts the PRF seed from your authenticator
- Derives an AES-GCM-256 encryption key via HKDF
- Encrypts all locally-stored credentials
- Uploads the encrypted archive to the relayer
If your device doesn't support PRF (the passkey extension for deterministic secrets), the SDK falls back to a credential-ID-based key. This is less secure — the account page will show a warning.
backup.recoverCredentials
Recover your credentials on a new device. Requires a passkey that was previously registered for this identity.
const recovered = await backup.recoverCredentials(keyHash);
console.log('Recovered:', recovered.credentials.length, 'credentials');
// Credentials are automatically saved to localStorageWhat happens:
- Fetches the encrypted archive from the relayer
- Triggers a WebAuthn ceremony to extract the same PRF seed
- Derives the same AES-GCM key
- Decrypts and restores all credentials to localStorage
backup.getBackupStatus
Check backup readiness for an identity.
const status = await backup.getBackupStatus(keyHash);
console.log('Has archive:', status.hasArchive);
console.log('PRF supported:', status.prfSupported);
console.log('Guardians:', status.guardianCount);Returns: BackupStatus
| Field | Type | Description |
|---|---|---|
hasArchive | boolean | Whether an encrypted backup exists |
archiveVersion | number | null | Archive schema version |
archiveUpdatedAt | number | null | Last update timestamp (epoch ms) |
guardianCount | number | Number of active social recovery guardians |
prfSupported | boolean | Whether PRF extension is available |
WalletBackupManager.checkPlatformSupport (static)
Check if the current platform supports PRF-based backup.
const support = await WalletBackupManager.checkPlatformSupport();
console.log('WebAuthn:', support.webauthnSupported);
console.log('PRF:', support.prfSupported);
if (!support.prfSupported) {
showWarning('Your device uses weaker backup encryption');
}InjectedWalletAdapter
import { InjectedWalletAdapter } from '@veridex/sdk';
const adapter = new InjectedWalletAdapter();
const session = await adapter.createSessionFromInjected(sessionConfig);Bridges MetaMask, WalletConnect, and other injected wallets into Veridex session key management.