Skip to main content
The Avail Nexus SDK enables you to execute smart contract calls on any supported chain, with automatic cross-chain funding when needed.

Overview

The SDK provides three execution methods:
  • execute() — Execute a contract call on a specific chain
  • bridgeAndExecute() — Bridge tokens and execute a contract call
  • bridgeAndTransfer() — Bridge tokens and send to a recipient
All methods include:
  • Automatic token approvals before execution
  • Gas estimation and price optimization
  • Transaction receipt waiting and confirmation tracking
  • Bridge skip optimization when sufficient funds exist

Basic Contract Execution

Execute a smart contract call on the target chain:
import { NexusSDK, NEXUS_EVENTS } from '@avail-project/nexus-core';

const sdk = new NexusSDK({ network: 'mainnet' });
await sdk.initialize(window.ethereum);

// Execute a contract call
const result = await sdk.execute(
  {
    toChainId: 1, // Ethereum
    to: '0xContractAddress',
    data: '0x...', // Encoded function call
    value: 0n, // ETH to send with call
  },
  {
    onEvent: (event) => {
      if (event.name === NEXUS_EVENTS.STEP_COMPLETE) {
        console.log('Step:', event.args);
      }
    },
  }
);

console.log('Transaction:', result.transactionHash);
console.log('Explorer:', result.explorerUrl);

Execute Parameters

toChainId
number
required
Target chain ID where the contract exists
to
Hex
required
Contract address to call
data
Hex
default:"'0x'"
Encoded function call data. Use ethers/viem to encode function calls
value
bigint
default:"0n"
Native token value (ETH, MATIC, etc.) to send with the call
gas
bigint
default:"auto-estimated"
Gas limit for the transaction
gasPrice
'low' | 'medium' | 'high'
default:"'medium'"
Gas price strategy
tokenApproval
object
Token approval before execution:
  • token (string): Token symbol
  • amount (bigint): Amount to approve
  • spender (Hex): Spender address (usually the contract)
waitForReceipt
boolean
default:"true"
Wait for transaction receipt before returning
receiptTimeout
number
default:"60000"
Receipt wait timeout in milliseconds
requiredConfirmations
number
default:"1"
Required block confirmations

Execute Result

type ExecuteResult = {
  transactionHash: string;
  explorerUrl: string;
  chainId: number;
  receipt?: TransactionReceipt;
  confirmations?: number;
  gasUsed?: string;
  effectiveGasPrice?: string;
  approvalTransactionHash?: string; // If tokenApproval was used
};

Execute with Token Approval

Automatically approve tokens before contract execution:
import { encodeFunctionData } from 'viem';

const depositCalldata = encodeFunctionData({
  abi: defiProtocolAbi,
  functionName: 'deposit',
  args: [100_000_000n], // 100 USDC
});

const result = await sdk.execute({
  toChainId: 1,
  to: '0xDeFiProtocol',
  data: depositCalldata,
  tokenApproval: {
    token: 'USDC',
    amount: 100_000_000n,
    spender: '0xDeFiProtocol',
  },
});

if (result.approvalTransactionHash) {
  console.log('Approval tx:', result.approvalTransactionHash);
}
console.log('Execution tx:', result.transactionHash);

Simulating Execution

Estimate gas costs before executing:
const simulation = await sdk.simulateExecute({
  toChainId: 1,
  to: '0xContractAddress',
  data: '0x...',
  value: 0n,
});

console.log('Estimated gas:', simulation.gasUsed);
console.log('Gas price:', simulation.gasPrice);
console.log('Total gas fee:', simulation.gasFee);

// Convert to human-readable
const gasCostInETH = Number(simulation.gasFee) / 1e18;
console.log(`Estimated cost: ${gasCostInETH} ETH`);
Simulation is free and doesn’t require gas. Use it to show users transaction costs before execution.

Bridge and Execute

Bridge tokens to a destination chain and execute a contract call:
import { BridgeAndExecuteParams } from '@avail-project/nexus-core';

const result = await sdk.bridgeAndExecute(
  {
    token: 'USDC',
    amount: 100_000_000n, // 100 USDC
    toChainId: 1, // Ethereum
    execute: {
      to: '0xDeFiProtocol',
      data: depositCalldata,
      tokenApproval: {
        token: 'USDC',
        amount: 100_000_000n,
        spender: '0xDeFiProtocol',
      },
    },
  },
  {
    onEvent: (event) => {
      if (event.name === NEXUS_EVENTS.STEP_COMPLETE) {
        console.log('Step:', event.args.type);
      }
    },
  }
);

if (result.bridgeSkipped) {
  console.log('Used existing balance - no bridge needed!');
} else {
  console.log('Bridge explorer:', result.bridgeExplorerUrl);
}

console.log('Execution explorer:', result.executeExplorerUrl);

Bridge and Execute Parameters

token
string
required
Token to bridge (e.g., ‘USDC’, ‘USDT’, ‘ETH’)
amount
bigint
required
Amount to bridge in smallest unit
toChainId
number
required
Destination chain ID
sourceChains
number[]
default:"auto-selected"
Specific source chains to bridge from
execute
ExecuteParams
required
Contract execution parameters (same as execute() but without toChainId)

Bridge and Execute Result

type BridgeAndExecuteResult = {
  executeTransactionHash: string;
  executeExplorerUrl: string;
  approvalTransactionHash?: string;
  bridgeExplorerUrl?: string; // undefined if bridge was skipped
  toChainId: number;
  bridgeSkipped: boolean; // true if sufficient balance existed
  intent?: ReadableIntent;
};

Bridge Skip Optimization

The SDK automatically checks if you have sufficient funds on the destination chain:
const result = await sdk.bridgeAndExecute({
  token: 'USDC',
  amount: 50_000_000n,
  toChainId: 1,
  execute: {
    to: '0xContract',
    data: '0x...',
  },
});

if (result.bridgeSkipped) {
  console.log('✨ Bridge skipped - used existing balance!');
  console.log('Saved time and gas fees!');
} else {
  console.log('Bridged from:', result.intent?.sources.length, 'chains');
}

Smart Optimization

When you have enough tokens on the destination chain, the SDK skips the bridge entirely and executes directly. This saves time and gas costs.

Simulating Bridge and Execute

Estimate costs for the entire operation:
const simulation = await sdk.simulateBridgeAndExecute({
  token: 'USDC',
  amount: 100_000_000n,
  toChainId: 1,
  execute: {
    to: '0xContract',
    data: '0x...',
  },
});

// Check if bridge is needed
if (simulation.bridgeSimulation) {
  console.log('Bridge fees:', simulation.bridgeSimulation.intent.fees);
  console.log('Bridge sources:', simulation.bridgeSimulation.intent.sources);
} else {
  console.log('Bridge not needed - sufficient balance exists');
}

// Check execution costs
console.log('Execution gas:', simulation.executeSimulation.gasUsed);
console.log('Execution fee:', simulation.executeSimulation.gasFee);

Bridge and Transfer

Bridge tokens and send to a specific recipient:
import { TransferParams } from '@avail-project/nexus-core';

const result = await sdk.bridgeAndTransfer(
  {
    token: 'USDC',
    amount: 50_000_000n, // 50 USDC
    toChainId: 42161, // Arbitrum
    recipient: '0x742d35Cc6634C0532925a3b8D4C9db96c4b4Db45',
  },
  {
    onEvent: (event) => {
      if (event.name === NEXUS_EVENTS.STEP_COMPLETE) {
        console.log('Step:', event.args.type);
      }
    },
  }
);

console.log('Transfer complete:', result.explorerUrl);

Transfer Parameters

token
string
required
Token symbol to bridge
amount
bigint
required
Amount in smallest unit
toChainId
number
required
Destination chain ID
recipient
Hex
required
Recipient address on destination chain
sourceChains
number[]
default:"auto-selected"
Specific source chains to use

Transfer Result

type TransferResult = {
  transactionHash: string;
  explorerUrl: string;
};

Simulating Transfers

const simulation = await sdk.simulateBridgeAndTransfer({
  token: 'USDC',
  amount: 50_000_000n,
  toChainId: 42161,
  recipient: '0x...',
});

console.log('Transfer fees:', simulation.intent.fees);
console.log('Sources:', simulation.intent.sources);

Real-World Example: Bridge and Execute

From the SDK’s example suite:
import { BridgeAndExecuteParams, NEXUS_EVENTS, NexusSDK } from '@avail-project/nexus-core';

export async function bridgeAndExecute(
  params: BridgeAndExecuteParams,
  sdk: NexusSDK
): Promise<boolean> {
  console.log('Starting bridge and execute...');

  try {
    const result = await sdk.bridgeAndExecute(params, {
      onEvent: (event) => {
        if (event.name === NEXUS_EVENTS.STEP_COMPLETE) {
          console.log('Step completed:', {
            type: event.args.type,
            data: event.args.data,
          });
        }
      },
    });

    console.log('Bridge and execute successful!');
    console.log('Execute tx:', result.executeTransactionHash);
    
    if (result.bridgeSkipped) {
      console.log('Bridge was skipped - used existing balance');
    } else {
      console.log('Bridge explorer:', result.bridgeExplorerUrl);
    }

    return true;
  } catch (error) {
    console.error('Bridge and execute failed:', error);
    return false;
  }
}

Real-World Example: Bridge and Transfer

From the SDK’s example suite:
import { NEXUS_EVENTS, NexusSDK, TransferParams } from '@avail-project/nexus-core';

export async function bridgeAndTransfer(
  params: TransferParams,
  sdk: NexusSDK
): Promise<boolean> {
  console.log('Starting bridge and transfer...');

  try {
    const result = await sdk.bridgeAndTransfer(params, {
      onEvent: (event) => {
        if (event.name === NEXUS_EVENTS.STEP_COMPLETE) {
          console.log('Step completed:', event.args);
        }
      },
    });

    console.log('Bridge and transfer successful!');
    console.log('Explorer:', result.explorerUrl);
    return true;
  } catch (error) {
    console.error('Bridge and transfer failed:', error);
    return false;
  }
}

Gas Price Strategies

Control transaction costs with gas price options:
// Fast confirmation (higher cost)
const result = await sdk.execute({
  toChainId: 1,
  to: '0xContract',
  data: '0x...',
  gasPrice: 'high',
});

// Balanced (recommended)
const result = await sdk.execute({
  toChainId: 1,
  to: '0xContract',
  data: '0x...',
  gasPrice: 'medium', // default
});

// Slower but cheaper
const result = await sdk.execute({
  toChainId: 1,
  to: '0xContract',
  data: '0x...',
  gasPrice: 'low',
});

Transaction Confirmations

Wait for multiple confirmations:
const result = await sdk.execute({
  toChainId: 1,
  to: '0xContract',
  data: '0x...',
  waitForReceipt: true,
  receiptTimeout: 120000, // 2 minutes
  requiredConfirmations: 3, // Wait for 3 blocks
});

console.log('Confirmations:', result.confirmations);
console.log('Gas used:', result.gasUsed);
console.log('Effective gas price:', result.effectiveGasPrice);

Error Handling

import { NexusError, ERROR_CODES } from '@avail-project/nexus-core';

try {
  await sdk.execute(params);
} catch (error) {
  if (error instanceof NexusError) {
    switch (error.code) {
      case ERROR_CODES.SIMULATION_FAILED:
        console.error('Contract call will fail:', error.message);
        // Show user why (e.g., insufficient allowance, wrong params)
        break;
      case ERROR_CODES.TRANSACTION_TIMEOUT:
        console.error('Transaction confirmation timed out');
        // Show explorer link so user can check status
        break;
      case ERROR_CODES.TRANSACTION_REVERTED:
        console.error('Transaction reverted:', error.message);
        // Contract rejected the call
        break;
      case ERROR_CODES.INSUFFICIENT_BALANCE:
        console.error('Not enough tokens');
        break;
      case ERROR_CODES.FETCH_GAS_PRICE_FAILED:
        console.error('Failed to estimate gas - retry');
        break;
      default:
        console.error('Execution error:', error.message);
    }
  }
}

Best Practices

Always Simulate

Call simulateExecute() or simulateBridgeAndExecute() before executing to catch errors early and show accurate costs.

Handle Token Approvals

Use the tokenApproval parameter for automatic approval before contract execution. This saves users a manual approval step.

Set Appropriate Timeouts

Adjust receiptTimeout based on the target chain’s block time. Ethereum: 30-60s, Polygon: 5-10s, Arbitrum: 1-5s.

Monitor Confirmations

For high-value transactions, require multiple confirmations (3-6 blocks) to reduce reorg risk.

Next Steps

Bridge Tokens

Learn about basic bridge operations

Swap Tokens

Execute cross-chain swaps

Error Handling

Handle execution errors properly

Check Balances

Query balances before execution

Build docs developers (and LLMs) love