A headless TypeScript SDK for cross-chain operations, token bridging, swapping, and unified balance management. Built for backends, CLIs, and custom UI integrations.
- Prerequisites
- Installation
- Quick Start
- Core Features
- Configuration
- API Reference
- Hooks & Callbacks
- Events & Steps
- Error Handling
- TypeScript Reference
- Utilities
- Smart Optimizations
- Analytics
- Supported Networks
- Supported Tokens
- Common Pitfalls
- Skills Integration
- Resources
- Node.js
>=18.0.0 - npm
>=9.0.0
npm install @avail-project/nexus-coreimport { NexusSDK, NEXUS_EVENTS } from '@avail-project/nexus-core';
// 1) Create and initialize the SDK
const sdk = new NexusSDK({ network: 'mainnet' });
await sdk.initialize(window.ethereum);
// 2) Set hooks for user approvals
sdk.setOnIntentHook(({ intent, allow, deny }) => {
if (userConfirmsIntent(intent)) allow();
else deny();
});
sdk.setOnAllowanceHook(({ sources, allow, deny }) => {
if (userConfirmsAllowance(sources)) allow(['min']);
else deny();
});
// 3) Fetch balances
const balances = await sdk.getBalancesForBridge();
// 4) Execute a bridge
const result = await sdk.bridge(
{
token: 'USDC',
amount: 100_000_000n, // 100 USDC (6 decimals)
toChainId: 137, // Polygon
},
{
onEvent: (event) => {
if (event.name === NEXUS_EVENTS.STEPS_LIST) {
initProgress(event.args);
}
if (event.name === NEXUS_EVENTS.STEP_COMPLETE) {
updateProgress(event.args);
}
},
}
);
console.log('Bridge complete:', result.explorerUrl);- Cross-chain bridging — Move tokens seamlessly across 16+ chains
- Cross-chain swaps — Execute EXACT_IN and EXACT_OUT swaps between any supported networks
- Unified balances — Aggregate user assets and balances across all connected chains
- Optimized transfers — Automatically choose the most efficient transfer route
- Contract execution — Call smart contracts with automatic bridging and funding logic
- Transaction simulation — Estimate gas, fees, and required approvals before sending
- Complete testnet coverage — Full multi-chain test environment
- Comprehensive utilities — Address, token, and chain helpers built in
import { NexusSDK } from '@avail-project/nexus-core';
const sdk = new NexusSDK({
// Network: 'mainnet' | 'testnet' | custom NetworkConfig
network: 'mainnet',
// Enable debug logging
debug: false,
// Chain ID for SIWE (Sign-In with Ethereum) signing
siweChain: 1,
// Analytics configuration (see Analytics section)
analytics: {
enabled: true,
privacy: {
anonymizeWallets: true,
anonymizeAmounts: true,
},
},
});// Mainnet
const mainnetSdk = new NexusSDK({ network: 'mainnet' });
// Testnet
const testnetSdk = new NexusSDK({ network: 'testnet' });
// Custom network config (advanced)
const customSdk = new NexusSDK({
network: {
// Custom network configuration object
},
});Initialize the SDK with an EVM-compatible wallet provider.
await sdk.initialize(window.ethereum);| Parameter | Type | Description |
|---|---|---|
provider |
EthereumProvider |
EIP-1193 compatible provider (MetaMask, WalletConnect, etc.) |
Set or update the EVM provider without full re-initialization.
await sdk.setEVMProvider(newProvider);Check if SDK is fully initialized.
if (sdk.isInitialized()) {
// Safe to call SDK methods
}Manually trigger account change detection (useful for some wallet integrations).
sdk.triggerAccountChange();Clean up SDK resources. Call when unmounting your app.
await sdk.deinit();Get user's token balances across all supported chains for bridge operations.
const assets = await sdk.getBalancesForBridge();
// Returns UserAsset[] - array of assets with per-chain breakdown
// [
// {
// symbol: 'USDC',
// balance: '1250.50', // Total across all chains
// balanceInFiat: 1250.50, // USD value
// decimals: 6,
// icon: 'https://...',
// breakdown: [ // Per-chain balances
// {
// balance: '500.00',
// balanceInFiat: 500.00,
// chain: { id: 1, name: 'Ethereum', logo: '...' },
// contractAddress: '0xa0b86991...',
// decimals: 6,
// symbol: 'USDC',
// },
// {
// balance: '750.50',
// balanceInFiat: 750.50,
// chain: { id: 137, name: 'Polygon', logo: '...' },
// contractAddress: '0x3c499c54...',
// decimals: 6,
// symbol: 'USDC',
// },
// ],
// },
// // ... more assets (ETH, USDT, etc.)
// ]UserAsset:
type UserAsset = {
symbol: string;
balance: string; // Total balance (human-readable)
balanceInFiat: number; // USD value
decimals: number;
icon?: string;
breakdown: AssetBreakdown[];
};
type AssetBreakdown = {
balance: string;
balanceInFiat: number;
chain: { id: number; name: string; logo: string };
contractAddress: Hex;
decimals: number;
symbol: string;
};Get user's token balances for swap operations.
// All swap-supported tokens
const allBalances = await sdk.getBalancesForSwap();
// Only native tokens and stablecoins
const stableBalances = await sdk.getBalancesForSwap(true);| Parameter | Type | Default | Description |
|---|---|---|---|
onlyNativesAndStables |
boolean |
false |
Filter to only native tokens and stablecoins |
Bridge tokens from one or more source chains to a destination chain.
const result = await sdk.bridge(
{
token: 'USDC',
amount: 100_000_000n, // 100 USDC
toChainId: 137,
recipient: '0x...', // Optional: defaults to connected wallet
sourceChains: [1, 42161], // Optional: auto-selected if omitted
gas: 100000n, // Optional: gas to supply on destination
},
{
onEvent: (event) => {
// Handle progress events
},
}
);BridgeParams:
| Parameter | Type | Required | Description |
|---|---|---|---|
token |
string |
Yes | Token symbol: 'ETH', 'USDC', 'USDT', 'USDM' |
amount |
bigint |
Yes | Amount in smallest unit (e.g., 6 decimals for USDC) |
toChainId |
number |
Yes | Destination chain ID |
recipient |
Hex |
No | Recipient address (defaults to connected wallet) |
sourceChains |
number[] |
No | Specific source chains to use (auto-selected if omitted) |
gas |
bigint |
No | Gas amount to supply on destination chain |
BridgeResult:
type BridgeResult = {
explorerUrl: string; // Destination chain explorer URL
sourceTxs: Array<{
chain: { id: number; name: string; logo: string };
hash: Hex;
explorerUrl: string;
}>;
intent: ReadableIntent;
};Simulate a bridge operation to estimate fees and preview the intent.
const simulation = await sdk.simulateBridge({
token: 'USDC',
amount: 100_000_000n,
toChainId: 137,
});
console.log('Estimated fees:', simulation.intent.fees);
console.log('Source chains:', simulation.intent.sources);SimulationResult:
type SimulationResult = {
intent: ReadableIntent;
token: TokenInfo;
};Calculate the maximum amount that can be bridged for a given token.
const max = await sdk.calculateMaxForBridge({
token: 'USDC',
toChainId: 137,
});
console.log(`Max bridgeable: ${max.amount} ${max.symbol}`);
console.log('From chains:', max.sourceChainIds);BridgeMaxResult:
type BridgeMaxResult = {
amountRaw: bigint;
amount: string; // Human-readable
symbol: string;
sourceChainIds: number[];
};Bridge tokens and send to a specific recipient address.
const result = await sdk.bridgeAndTransfer(
{
token: 'USDC',
amount: 50_000_000n, // 50 USDC
toChainId: 42161, // Arbitrum
recipient: '0x742d35Cc6634C0532925a3b8D4C9db96c4b4Db45',
sourceChains: [1], // Optional
},
{
onEvent: (event) => console.log(event),
}
);TransferParams:
| Parameter | Type | Required | Description |
|---|---|---|---|
token |
string |
Yes | Token symbol |
amount |
bigint |
Yes | Amount in smallest unit |
toChainId |
number |
Yes | Destination chain ID |
recipient |
Hex |
Yes | Recipient address |
sourceChains |
number[] |
No | Specific source chains |
TransferResult:
type TransferResult = {
transactionHash: string;
explorerUrl: string;
};Simulate a bridge-and-transfer operation.
const simulation = await sdk.simulateBridgeAndTransfer({
token: 'USDC',
amount: 50_000_000n,
toChainId: 42161,
recipient: '0x...',
});Execute a smart contract call on a destination chain.
const result = await sdk.execute(
{
toChainId: 1,
to: '0xContractAddress',
data: '0x...', // Encoded function call
value: 0n, // ETH value to send
tokenApproval: {
token: 'USDC',
amount: 1_000_000n,
spender: '0xSpenderAddress',
},
// Advanced options
gasPrice: 'medium', // 'low' | 'medium' | 'high'
waitForReceipt: true,
receiptTimeout: 60000,
requiredConfirmations: 1,
},
{
onEvent: (event) => console.log(event),
}
);ExecuteParams:
| Parameter | Type | Required | Description |
|---|---|---|---|
toChainId |
number |
Yes | Target chain ID |
to |
Hex |
Yes | Contract address |
data |
Hex |
No | Encoded function call data |
value |
bigint |
No | Native token value to send |
gas |
bigint |
No | Gas limit |
gasPrice |
'low' | 'medium' | 'high' |
No | Gas price strategy |
tokenApproval |
{ token, amount, spender } |
No | Token approval before execution |
waitForReceipt |
boolean |
No | Wait for transaction receipt |
receiptTimeout |
number |
No | Receipt wait timeout (ms) |
requiredConfirmations |
number |
No | Required block confirmations |
ExecuteResult:
type ExecuteResult = {
transactionHash: string;
explorerUrl: string;
chainId: number;
receipt?: TransactionReceipt;
confirmations?: number;
gasUsed?: string;
effectiveGasPrice?: string;
approvalTransactionHash?: string;
};Simulate contract execution to estimate gas.
const simulation = await sdk.simulateExecute({
toChainId: 1,
to: '0x...',
data: '0x...',
});
console.log('Gas estimate:', simulation.gasUsed);
console.log('Gas fee:', simulation.gasFee);ExecuteSimulation:
type ExecuteSimulation = {
gasUsed: bigint;
gasPrice: bigint;
gasFee: bigint; // gasUsed * gasPrice
};Bridge tokens to a destination chain and execute a contract call.
const result = await sdk.bridgeAndExecute(
{
token: 'USDC',
amount: 100_000_000n,
toChainId: 1,
sourceChains: [8453], // Optional
execute: {
to: '0xDeFiProtocol',
data: '0x...', // deposit() call
tokenApproval: {
token: 'USDC',
amount: 100_000_000n,
spender: '0xDeFiProtocol',
},
},
},
{
onEvent: (event) => console.log(event),
}
);
if (result.bridgeSkipped) {
console.log('Used existing balance on destination');
} else {
console.log('Bridge explorer:', result.bridgeExplorerUrl);
}BridgeAndExecuteParams:
| Parameter | Type | Required | Description |
|---|---|---|---|
token |
string |
Yes | Token to bridge |
amount |
bigint |
Yes | Amount to bridge |
toChainId |
number |
Yes | Destination chain |
sourceChains |
number[] |
No | Source chains to use |
execute |
Omit<ExecuteParams, 'toChainId'> |
Yes | Contract execution params |
BridgeAndExecuteResult:
type BridgeAndExecuteResult = {
executeTransactionHash: string;
executeExplorerUrl: string;
approvalTransactionHash?: string;
bridgeExplorerUrl?: string; // undefined if bridge was skipped
toChainId: number;
bridgeSkipped: boolean;
intent?: ReadableIntent;
};Simulate bridge-and-execute to estimate costs.
const simulation = await sdk.simulateBridgeAndExecute({
token: 'USDC',
amount: 100_000_000n,
toChainId: 1,
execute: { to: '0x...', data: '0x...' },
});
console.log('Bridge simulation:', simulation.bridgeSimulation);
console.log('Execute simulation:', simulation.executeSimulation);BridgeAndExecuteSimulationResult:
type BridgeAndExecuteSimulationResult = {
bridgeSimulation: SimulationResult | null; // null if bridge not needed
executeSimulation: ExecuteSimulation;
};Swap tokens specifying the exact input amount.
const result = await sdk.swapWithExactIn(
{
from: [
{ chainId: 10, amount: 1_000_000n, tokenAddress: '0xUSDC...' },
{ chainId: 42161, amount: 500_000n, tokenAddress: '0xUSDC...' },
],
toChainId: 8453,
toTokenAddress: '0xETH...',
},
{
onEvent: (event) => {
if (event.name === NEXUS_EVENTS.SWAP_STEP_COMPLETE) {
console.log('Swap step:', event.args);
}
},
}
);ExactInSwapInput:
| Parameter | Type | Required | Description |
|---|---|---|---|
from |
Array<{ chainId, tokenAddress, amount }> |
Yes | Source tokens and amounts |
toChainId |
number |
Yes | Destination chain |
toTokenAddress |
Hex |
Yes | Output token address |
Swap tokens specifying the exact output amount.
const result = await sdk.swapWithExactOut(
{
toChainId: 8453,
toTokenAddress: '0xETH...',
toAmount: 1_000_000_000_000_000_000n, // 1 ETH
},
{
onEvent: (event) => console.log(event),
}
);ExactOutSwapInput:
| Parameter | Type | Required | Description |
|---|---|---|---|
fromSources |
Array<{ chainId, tokenAddress }> |
No | Restrict source chains/tokens for quote routing |
toChainId |
number |
Yes | Destination chain |
toTokenAddress |
Hex |
Yes | Output token address |
toAmount |
bigint |
Yes | Exact output amount desired |
toNativeAmount |
bigint |
No | Optional native gas amount for destination chain |
SwapResult:
type SwapResult = {
success: boolean;
result: SuccessfulSwapResult;
};Get chains and tokens supported for swap operations.
const supported = sdk.getSwapSupportedChains();
console.log('Supported chains:', supported);Retrieve user's historical intents with pagination.
const intents = await sdk.getMyIntents(1); // Page 1
console.log('My intents:', intents);| Parameter | Type | Default | Description |
|---|---|---|---|
page |
number |
1 |
Page number for pagination |
Request a refund for a failed or stuck intent.
const intents = await sdk.getMyIntents(1);
const intentID = Number(intents[0]?.id);
await sdk.refundIntent(intentID);Hooks are essential for building interactive UIs. They allow users to review and approve operations before execution.
Called when the SDK needs user approval for a bridge/transfer intent.
sdk.setOnIntentHook(async ({ intent, allow, deny, refresh }) => {
// Display intent details to user
console.log('Source chains:', intent.sources);
console.log('Destination:', intent.destination);
console.log('Fees:', intent.fees);
console.log('Total from sources:', intent.sourcesTotal);
// User interaction
if (userApproves) {
allow();
} else {
deny(); // Throws USER_DENIED_INTENT error
}
// Optionally refresh with different source chains
const refreshedIntent = await refresh([8453, 42161]);
console.log('Refreshed intent:', refreshedIntent);
});OnIntentHookData:
type OnIntentHookData = {
allow: () => void;
deny: () => void;
intent: ReadableIntent;
refresh: (selectedSources?: number[]) => Promise<ReadableIntent>;
};ReadableIntent Structure:
type ReadableIntent = {
// Sources (chains funds are pulled from)
sources: Array<{
amount: string;
amountRaw: bigint;
chain: { id: number; name: string; logo: string };
token: { decimals: number; symbol: string; logo: string; contractAddress: Hex };
}>;
// All available sources (before selection)
allSources: Array<{ /* same as sources */ }>;
// Destination details
destination: {
amount: string;
chainID: number;
chainName: string;
chainLogo: string | undefined;
};
// Fee breakdown
fees: {
caGas: string; // Chain abstraction gas fee
gasSupplied: string; // Gas supplied to destination
protocol: string; // Protocol fee
solver: string; // Solver fee
total: string; // Total fees
};
// Token being bridged
token: {
decimals: number;
logo: string | undefined;
name: string;
symbol: string;
};
// Total amount from all sources
sourcesTotal: string;
};Called when token approval is needed before a transaction.
sdk.setOnAllowanceHook(({ sources, allow, deny }) => {
// Display approval request to user
sources.forEach((source) => {
console.log(`Chain: ${source.chain.name}`);
console.log(`Token: ${source.token.symbol}`);
console.log(`Current allowance: ${source.allowance.current}`);
console.log(`Required minimum: ${source.allowance.minimum}`);
});
// Approve with options:
allow(['min']); // Approve exact minimum needed
allow(['max']); // Approve unlimited (type(uint256).max)
allow([1000000n]); // Approve specific amount
allow(['min', 'max']); // Different per source (by index)
// Or deny
deny(); // Throws USER_DENIED_ALLOWANCE error
});OnAllowanceHookData:
type OnAllowanceHookData = {
allow: (amounts: Array<'max' | 'min' | bigint | string>) => void;
deny: () => void;
sources: AllowanceHookSources;
};
type AllowanceHookSources = Array<{
allowance: {
current: string; // Current allowance (human-readable)
currentRaw: bigint; // Current allowance (raw)
minimum: string; // Minimum required (human-readable)
minimumRaw: bigint; // Minimum required (raw)
};
chain: {
id: number;
logo: string;
name: string;
};
token: {
contractAddress: Hex;
decimals: number;
logo: string;
name: string;
symbol: string;
};
}>;Called when user approval is needed for a swap operation.
sdk.setOnSwapIntentHook(async ({ intent, allow, deny, refresh }) => {
console.log('Swap from:', intent.sources);
console.log('Swap to:', intent.destination);
if (userApproves) {
allow();
} else {
deny();
}
// Refresh to get updated quote
const refreshedIntent = await refresh();
console.log('Refreshed swap intent:', refreshedIntent);
});OnSwapIntentHookData:
type OnSwapIntentHookData = {
allow: () => void;
deny: () => void;
intent: SwapIntent;
refresh: () => Promise<SwapIntent>;
};
type SwapIntent = {
destination: {
amount: string;
chain: { id: number; logo: string; name: string };
token: { contractAddress: Hex; decimals: number; symbol: string };
gas: {
amount: string;
token: { contractAddress: Hex; decimals: number; symbol: string };
};
};
sources: Array<{
amount: string;
chain: { id: number; logo: string; name: string };
token: { contractAddress: Hex; decimals: number; symbol: string };
}>;
};All main SDK operations accept an onEvent callback to track progress.
sdk.bridge(params, {
onEvent: (event) => {
switch (event.name) {
case NEXUS_EVENTS.STEPS_LIST: {
// Emitted once at start with all steps
const allSteps = event.args; // BridgeStepType[]
initializeProgressUI(allSteps);
break;
}
case NEXUS_EVENTS.STEP_COMPLETE: {
// Emitted as each step completes
const completedStep = event.args; // BridgeStepType
updateProgressUI(completedStep);
break;
}
case NEXUS_EVENTS.SWAP_STEP_COMPLETE: {
// For swap operations
const swapStep = event.args; // SwapStepType
updateSwapProgress(swapStep);
break;
}
}
},
});The SDK emits step-by-step progress events during operations, enabling real-time UI updates.
Bridge operations emit the following step types:
| Step Type | Type ID | Description |
|---|---|---|
INTENT_ACCEPTED |
IA |
Intent created and accepted by solver |
INTENT_HASH_SIGNED |
IHS |
User signed the intent hash |
INTENT_SUBMITTED |
IS |
Intent submitted to the network |
INTENT_FULFILLED |
IF |
Intent fulfilled by solver |
ALLOWANCE_USER_APPROVAL |
AUA_{chainId} |
Waiting for user to approve allowance |
ALLOWANCE_APPROVAL_MINED |
AAM_{chainId} |
Allowance approval transaction mined |
ALLOWANCE_ALL_DONE |
AAD |
All allowances approved |
INTENT_DEPOSIT |
ID_{index} |
Deposit initiated on source chain |
INTENT_DEPOSITS_CONFIRMED |
UIDC |
All deposits confirmed |
INTENT_COLLECTION |
IC_{index} |
Collecting funds from source |
INTENT_COLLECTION_COMPLETE |
ICC |
All funds collected |
APPROVAL |
AP |
Token approval for execution |
TRANSACTION_SENT |
TS |
Execute transaction sent |
TRANSACTION_CONFIRMED |
CN |
Execute transaction confirmed |
Step Data Structure:
type BridgeStepType = {
type: string; // Step type name
typeID: string; // Unique identifier
data?: {
// Additional data (varies by step type)
chainID?: number;
chainName?: string;
amount?: string;
explorerURL?: string;
intentID?: number;
txHash?: Hex;
};
};Swap operations emit the following step types:
| Step Type | Description |
|---|---|
SWAP_START |
Swap operation started |
DETERMINING_SWAP |
Calculating optimal swap route |
CREATE_PERMIT_EOA_TO_EPHEMERAL |
Creating permit for ephemeral wallet |
CREATE_PERMIT_FOR_SOURCE_SWAP |
Creating permit for source swap |
SOURCE_SWAP_BATCH_TX |
Executing source chain swaps |
SOURCE_SWAP_HASH |
Source swap transaction hash |
BRIDGE_DEPOSIT |
Bridge deposit for cross-chain swap |
RFF_ID |
Request for funds ID |
DESTINATION_SWAP_BATCH_TX |
Executing destination swaps |
DESTINATION_SWAP_HASH |
Destination swap transaction hash |
SWAP_COMPLETE |
Swap completed successfully |
SWAP_SKIPPED |
Swap skipped (sufficient balance exists) |
Swap Step Data Structure:
type SwapStepType = {
type: string;
typeID: string;
completed: boolean;
chain?: { id: number; name: string };
symbol?: string;
explorerURL?: string;
data?: { /* varies by step */ };
};Example of building a progress indicator:
import { NEXUS_EVENTS, type BridgeStepType } from '@avail-project/nexus-core';
// State for tracking progress
let steps: BridgeStepType[] = [];
let completedSteps: Set<string> = new Set();
sdk.bridge(params, {
onEvent: (event) => {
if (event.name === NEXUS_EVENTS.STEPS_LIST) {
// Initialize with all expected steps
steps = event.args;
renderProgress();
}
if (event.name === NEXUS_EVENTS.STEP_COMPLETE) {
// Mark step as complete
completedSteps.add(event.args.typeID);
renderProgress();
// Handle specific steps
if (event.args.type === 'INTENT_SUBMITTED') {
console.log('View on explorer:', event.args.data?.explorerURL);
}
}
},
});
function renderProgress() {
steps.forEach((step, index) => {
const isComplete = completedSteps.has(step.typeID);
const isCurrent = index === completedSteps.size;
console.log(`${isComplete ? '✓' : isCurrent ? '●' : '○'} ${step.type}`);
});
}All SDK errors are thrown as NexusError instances:
import { NexusError, ERROR_CODES } from '@avail-project/nexus-core';
try {
await sdk.bridge({ token: 'USDC', amount: 1_000_000n, toChainId: 137 });
} catch (error) {
if (error instanceof NexusError) {
console.error(`Error Code: ${error.code}`);
console.error(`Message: ${error.message}`);
console.error(`Context: ${error.data?.context}`);
console.error(`Details:`, error.data?.details);
// Handle specific errors
switch (error.code) {
case ERROR_CODES.INSUFFICIENT_BALANCE:
showInsufficientBalanceUI();
break;
case ERROR_CODES.USER_DENIED_INTENT:
// User cancelled - not an error to display
break;
case ERROR_CODES.TRANSACTION_TIMEOUT:
showRetryOption();
break;
default:
showGenericError(error.message);
}
} else {
// Unexpected error
console.error('Unexpected error:', error);
}
}NexusError Structure:
class NexusError extends Error {
readonly code: keyof typeof ERROR_CODES;
readonly data?: {
context?: string; // Where/why it happened
cause?: unknown; // Nested error
details?: Record<string, unknown>; // Additional info
};
toJSON(): object; // Serializable format
}| Error Code | Description | User Action |
|---|---|---|
| User Actions | ||
USER_DENIED_INTENT |
User rejected the intent in hook | None - user cancelled |
USER_DENIED_ALLOWANCE |
User rejected token approval | None - user cancelled |
USER_DENIED_INTENT_SIGNATURE |
User rejected signature request | None - user cancelled |
USER_DENIED_SIWE_SIGNATURE |
User rejected SIWE signature | None - user cancelled |
| Balance & Funds | ||
INSUFFICIENT_BALANCE |
Not enough tokens for operation | Show balance, suggest deposit |
NO_BALANCE_FOR_ADDRESS |
No balance found for address | Verify address |
| Validation | ||
INVALID_INPUT |
Invalid parameters provided | Check input values |
INVALID_ADDRESS_LENGTH |
Address has wrong length | Verify address format |
INVALID_VALUES_ALLOWANCE_HOOK |
Invalid allowance hook values | Check allow() arguments |
TOKEN_NOT_SUPPORTED |
Token not supported | Use supported token |
| Initialization | ||
SDK_NOT_INITIALIZED |
SDK not initialized | Call initialize() first |
SDK_INIT_STATE_NOT_EXPECTED |
Unexpected init state | Re-initialize SDK |
WALLET_NOT_CONNECTED |
No wallet connected | Connect wallet |
CONNECT_ACCOUNT_FAILED |
Failed to connect account | Retry connection |
| Chain & Network | ||
CHAIN_NOT_FOUND |
Chain ID not found | Use supported chain |
CHAIN_DATA_NOT_FOUND |
Chain data unavailable | Check network connection |
VAULT_CONTRACT_NOT_FOUND |
Vault contract not found | Contact support |
ENVIRONMENT_NOT_SUPPORTED |
Environment not supported | Use mainnet/testnet |
ENVIRONMENT_NOT_KNOWN |
Unknown environment | Check configuration |
| Transactions | ||
TRANSACTION_TIMEOUT |
Transaction timed out | Retry or check explorer |
TRANSACTION_REVERTED |
Transaction reverted | Check contract/params |
TRANSACTION_CHECK_ERROR |
Error checking transaction | Retry |
FETCH_GAS_PRICE_FAILED |
Failed to fetch gas price | Retry |
| Operations | ||
SIMULATION_FAILED |
Simulation failed | Check parameters |
QUOTE_FAILED |
Failed to get quote | Retry |
SWAP_FAILED |
Swap operation failed | Retry or adjust params |
REFUND_FAILED |
Refund request failed | Contact support |
REFUND_CHECK_ERROR |
Error checking refund | Retry |
| Intent & Solver | ||
LIQUIDITY_TIMEOUT |
Solver liquidity timeout | Retry later |
RATES_CHANGED_BEYOND_TOLERANCE |
Price moved too much | Refresh and retry |
RFF_FEE_EXPIRED |
Request for funds expired | Retry operation |
DESTINATION_REQUEST_HASH_NOT_FOUND |
Destination hash not found | Contact support |
DESTINATION_SWEEP_ERROR |
Error sweeping funds | Contact support |
| Allowance | ||
SLIPPAGE_EXCEEDED_ALLOWANCE |
Slippage exceeded | Increase allowance |
ALLOWANCE_SETTING_ERROR |
Error setting allowance | Retry approval |
| Other | ||
INTERNAL_ERROR |
Internal SDK error | Contact support |
UNKNOWN_SIGNATURE |
Unknown signature type | Contact support |
ASSET_NOT_FOUND |
Asset not found | Check token address |
COSMOS_ERROR |
Cosmos chain error | Check Cosmos config |
UNIVERSE_NOT_SUPPORTED |
Universe not supported | Use supported chain |
FEE_GRANT_REQUESTED |
Fee grant requested | Contact support |
import type {
// SDK Configuration
NexusNetwork,
AnalyticsConfig,
// Operation Parameters
BridgeParams,
TransferParams,
ExecuteParams,
BridgeAndExecuteParams,
ExactInSwapInput,
ExactOutSwapInput,
// Operation Results
BridgeResult,
TransferResult,
ExecuteResult,
BridgeAndExecuteResult,
SwapResult,
BridgeMaxResult,
// Simulation Results
SimulationResult,
ExecuteSimulation,
BridgeAndExecuteSimulationResult,
// Intent & Hook Types
ReadableIntent,
SwapIntent,
OnIntentHook,
OnIntentHookData,
OnAllowanceHook,
OnAllowanceHookData,
AllowanceHookSources,
OnSwapIntentHook,
OnSwapIntentHookData,
// Step Types
BridgeStepType,
SwapStepType,
// Balance Types
UserAsset,
AssetBreakdown,
// Metadata
ChainMetadata,
TokenMetadata,
TokenInfo,
// Errors
NexusError,
NexusErrorData,
} from '@avail-project/nexus-core';import {
// Event names
NEXUS_EVENTS,
// Chain IDs
SUPPORTED_CHAINS,
MAINNET_CHAIN_IDS,
TESTNET_CHAIN_IDS,
// Metadata
CHAIN_METADATA,
TOKEN_METADATA,
TOKEN_CONTRACT_ADDRESSES,
// Steps
BRIDGE_STEPS,
SWAP_STEPS,
// Errors
ERROR_CODES,
} from '@avail-project/nexus-core';import {
formatTokenBalance,
formatTokenBalanceParts,
formatUnits,
parseUnits,
} from '@avail-project/nexus-core';
// Format token balance for display
const formatted = formatTokenBalance(1234567890n, 6, { symbol: 'USDC' });
// "1,234.57 USDC"
// Get formatted parts separately
const parts = formatTokenBalanceParts(1234567890n, 6);
// { integer: "1,234", decimal: "57", symbol: "USDC" }
// Convert between units
const wei = parseUnits('1.5', 18); // 1500000000000000000n
const eth = formatUnits(wei, 18); // "1.5"import { isValidAddress, truncateAddress } from '@avail-project/nexus-core';
// Validate Ethereum address
const valid = isValidAddress('0x742d35Cc6634C0532925a3b8D4C9db96c4b4Db45'); // true
// Truncate for display
const short = truncateAddress('0x742d35Cc6634C0532925a3b8D4C9db96c4b4Db45');
// "0x742d...Db45"
const custom = truncateAddress('0x742d35Cc6634C0532925a3b8D4C9db96c4b4Db45', 6, 4);
// "0x742d35...Db45"import { CHAIN_METADATA, getSupportedChains } from '@avail-project/nexus-core';
// Get chain metadata
const polygon = CHAIN_METADATA[137];
console.log(polygon.name); // "Polygon"
console.log(polygon.nativeCurrency); // { name: "MATIC", symbol: "MATIC", decimals: 18 }
// Get all supported chains and tokens
const mainnet = getSupportedChains('mainnet');
const testnet = getSupportedChains('testnet');
// Via SDK instance
const chains = sdk.utils.getSupportedChains();
const isSupported = sdk.utils.isSupportedChain(137); // true// Get current token prices from Coinbase
const rates = await sdk.utils.getCoinbaseRates();
console.log(rates.ETH); // "3456.78"
console.log(rates.USDC); // "1.00"During bridge-and-execute operations, the SDK checks whether sufficient funds already exist on the destination chain:
- Balance detection — Verifies token and gas availability
- Integrated gas supply — Provides gas alongside bridged tokens
- Adaptive bridging — Skips unnecessary bridging or transfers only the shortfall
- Seamless fallback — Uses chain abstraction if local funds are insufficient
const result = await sdk.bridgeAndExecute({
token: 'USDC',
amount: 100_000_000n,
toChainId: 1,
execute: { to: '0x...', data: '0x...' },
});
if (result.bridgeSkipped) {
console.log('Executed using existing balance - no bridge needed!');
}For transfers, the SDK automatically chooses the most efficient execution path:
- Local balance checking — Confirms token and gas availability on the target chain
- Direct EVM transfers — Uses native transfers where possible (faster, cheaper)
- Chain abstraction fallback — Uses CA routing only when required
- Universal compatibility — Works with both native tokens (ETH, MATIC) and ERC-20s (USDC, USDT)
The Nexus SDK includes built-in analytics powered by PostHog to help improve the SDK and understand usage patterns. Analytics are enabled by default but can be easily customized or disabled.
By default, the SDK sends anonymous telemetry data to Avail's PostHog instance:
- SDK initialization events
- Operation performance metrics
- Session duration and success rates
- Error tracking (without sensitive data)
The SDK does not automatically call analytics.identify().
Transaction amounts can be anonymized via privacy.anonymizeAmounts, and analytics can be fully disabled via enabled: false.
Note: operation metadata may include transaction context (for example, recipient or contract addresses) in tracked events.
const sdk = new NexusSDK({
network: 'mainnet',
analytics: { enabled: false },
});const sdk = new NexusSDK({
network: 'mainnet',
analytics: {
enabled: true,
privacy: {
anonymizeWallets: true, // Hash wallet addresses
anonymizeAmounts: true, // Exclude transaction amounts
},
},
});const sdk = new NexusSDK({
network: 'mainnet',
analytics: {
enabled: true,
posthogApiKey: 'your-posthog-key',
posthogApiHost: 'https://your-posthog-instance.com',
appMetadata: {
appName: 'My DApp',
appVersion: '1.0.0',
appUrl: 'https://mydapp.com',
},
},
});// Track custom events
sdk.analytics.track('custom_event', { foo: 'bar' });
// Identify users
sdk.analytics.identify('user-id', { plan: 'premium' });
// Check if analytics is enabled
if (sdk.analytics.isEnabled()) {
console.log('Analytics active');
}
// Disable/enable at runtime
sdk.analytics.disable();
sdk.analytics.enable();| Network | Chain ID | Native | Bridge | Swap |
|---|---|---|---|---|
| Ethereum | 1 | ETH | ✅ | ❌ |
| Citrea Mainnet | 4114 | cBTC | ✅ | ❌ |
| Monad | 143 | MON | ✅ | ❌ |
| Base | 8453 | ETH | ✅ | ✅ |
| Arbitrum One | 42161 | ETH | ✅ | ✅ |
| Optimism | 10 | ETH | ✅ | ✅ |
| Polygon | 137 | MATIC | ✅ | ✅ |
| Avalanche | 43114 | AVAX | ✅ | ✅ |
| Scroll | 534352 | ETH | ✅ | ✅ |
| Kaia Mainnet | 8217 | KAIA | ✅ | ❌ |
| BNB Smart Chain | 56 | BNB | ✅ | ✅ |
| Hyper EVM | 999 | HYPE | ✅ | ❌ |
| MegaETH | 4326 | ETH | ✅ | ❌ |
| Network | Chain ID | Native | Bridge | Swap |
|---|---|---|---|---|
| Sepolia | 11155111 | ETH | ✅ | ❌ |
| Base Sepolia | 84532 | ETH | ✅ | ❌ |
| Arbitrum Sepolia | 421614 | ETH | ✅ | ❌ |
| Optimism Sepolia | 11155420 | ETH | ✅ | ❌ |
| Polygon Amoy | 80002 | MATIC | ✅ | ❌ |
| Monad Testnet | 10143 | MON | ✅ | ❌ |
| Citrea Testnet | 5115 | cBTC | ✅ | ❌ |
| Token | Name | Decimals | Networks |
|---|---|---|---|
| ETH | Ethereum | 18 | All EVM chains |
| USDC | USD Coin | 6 | All supported |
| USDT | Tether USD | 6 | Most supported |
| USDM | USDm | 18 | MegaETH |
- SDK method amounts are atomic units (
bigint), not human-readable decimal strings. bridge/bridgeAndTransfer/bridgeAndExecuteuse token symbols (for example,USDC), while swap methods use token contract addresses.refundIntentrequires anintentID(number), usually fromgetMyIntents().setEVMProvider()only updates/attaches a provider; callinitialize()early to set up full session state.
This repo ships Codex/skills.sh skills under skills/ to help agents integrate the SDK end-to-end.
# Install all skills
npx skills add availproject/nexus-sdk
# Install single skill (recommended)
npx skills add https://github.com/availproject/nexus-sdk --skill nexus-sdk-integration
# Install from specific branch
npx skills add https://github.com/availproject/nexus-sdk --skill nexus-sdk-integration --ref developnexus-sdk-integration— Parent/orchestrator skillnexus-sdk-setup— SDK setup and configurationnexus-sdk-hooks-events— Hooks and event handlingnexus-sdk-bridge-flows— Bridge operation flowsnexus-sdk-swap-flows— Swap operation flowsnexus-sdk-balances-metadata-utils— Balances and utilities
- GitHub: availproject/nexus-sdk
- Documentation: docs.availproject.org
- Discord: Avail Discord