npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@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

  • Node.js >=18.0.0
  • npm >=9.0.0

Installation

npm install @avail-project/nexus-core

Quick 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); // true

Price 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/bridgeAndExecute use token symbols (for example, USDC), while swap methods use token contract addresses.
  • refundIntent requires an intentID (number), usually from getMyIntents().
  • setEVMProvider() only updates/attaches a provider; call initialize() 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 develop

Available Skills

  • nexus-sdk-integration — Parent/orchestrator skill
  • nexus-sdk-setup — SDK setup and configuration
  • nexus-sdk-hooks-events — Hooks and event handling
  • nexus-sdk-bridge-flows — Bridge operation flows
  • nexus-sdk-swap-flows — Swap operation flows
  • nexus-sdk-balances-metadata-utils — Balances and utilities

Resources