@avail-project/nexus-core
v1.1.2
Published
Nexus headless SDK for cross-chain transactions
Readme
@avail-project/nexus-core
A headless TypeScript SDK for cross-chain operations, token bridging, swapping, and unified balance management. Built for backends, CLIs, and custom UI integrations.
Table of Contents
- 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
Prerequisites
- Node.js
>=18.0.0 - npm
>=9.0.0
Installation
npm install @avail-project/nexus-coreQuick Start
import { 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);Core Features
- 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
Configuration
SDK Initialization Options
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,
},
},
});Network Configuration
// 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
},
});API Reference
Initialization & Lifecycle
initialize(provider)
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.) |
setEVMProvider(provider)
Set or update the EVM provider without full re-initialization.
await sdk.setEVMProvider(newProvider);isInitialized()
Check if SDK is fully initialized.
if (sdk.isInitialized()) {
// Safe to call SDK methods
}triggerAccountChange()
Manually trigger account change detection (useful for some wallet integrations).
sdk.triggerAccountChange();deinit()
Clean up SDK resources. Call when unmounting your app.
await sdk.deinit();Balance Operations
getBalancesForBridge()
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;
};getBalancesForSwap(onlyNativesAndStables?)
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 Operations
bridge(params, options?)
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;
};simulateBridge(params)
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;
};calculateMaxForBridge(params)
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[];
};Transfer Operations
bridgeAndTransfer(params, options?)
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;
};simulateBridgeAndTransfer(params)
Simulate a bridge-and-transfer operation.
const simulation = await sdk.simulateBridgeAndTransfer({
token: 'USDC',
amount: 50_000_000n,
toChainId: 42161,
recipient: '0x...',
});Execute Operations
execute(params, options?)
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;
};simulateExecute(params)
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
};bridgeAndExecute(params, options?)
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;
};simulateBridgeAndExecute(params)
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 Operations
swapWithExactIn(input, options?)
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 |
swapWithExactOut(input, options?)
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;
};getSwapSupportedChains()
Get chains and tokens supported for swap operations.
const supported = sdk.getSwapSupportedChains();
console.log('Supported chains:', supported);Intent Management
getMyIntents(page?)
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 |
refundIntent(intentID: number)
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 & Callbacks
Hooks are essential for building interactive UIs. They allow users to review and approve operations before execution.
Intent Hook
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;
};Allowance Hook
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;
};
}>;Swap Intent Hook
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 };
}>;
};Event Callbacks
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;
}
}
},
});Events & Steps
The SDK emits step-by-step progress events during operations, enabling real-time UI updates.
Bridge Steps
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 Steps
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 */ };
};Building Progress UIs
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}`);
});
}Error Handling
NexusError Class
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 Codes Reference
| 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 |
TypeScript Reference
Core Types
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';Constants
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';Utilities
Formatting Functions
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"Address Utilities
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"Chain & Token Info
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); // truePrice Rates
// Get current token prices from Coinbase
const rates = await sdk.utils.getCoinbaseRates();
console.log(rates.ETH); // "3456.78"
console.log(rates.USDC); // "1.00"Smart Optimizations
Bridge Skip Optimization
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!');
}Direct Transfer Optimization
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)
Analytics
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.
Default Behavior
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.
Disabling Analytics
const sdk = new NexusSDK({
network: 'mainnet',
analytics: { enabled: false },
});Privacy Controls
const sdk = new NexusSDK({
network: 'mainnet',
analytics: {
enabled: true,
privacy: {
anonymizeWallets: true, // Hash wallet addresses
anonymizeAmounts: true, // Exclude transaction amounts
},
},
});Custom Analytics (BYO PostHog)
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',
},
},
});Accessing Analytics Programmatically
// 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();Supported Networks
Mainnets
| 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 | ✅ | ❌ |
Testnets
| 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 | ✅ | ❌ |
Supported Tokens
| 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 |
Common Pitfalls
- 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.
Skills Integration
This repo ships Codex/skills.sh skills under skills/ to help agents integrate the SDK end-to-end.
Install Skills
# 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 developAvailable Skills
nexus-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
Resources
- GitHub: availproject/nexus-sdk
- Documentation: docs.availproject.org
- Discord: Avail Discord
