Skip to main content
This guide demonstrates how to swap native blockchain assets like ETH, AVAX, BNB, and MATIC using the NativeOrdersFactory for transaction broadcasting.

Overview

Native token swaps require special handling:
  • Use 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee as the token address
  • Submit orders using submitNativeOrder() instead of submitOrder()
  • Broadcast transactions using NativeOrdersFactory
  • Include native token value in the transaction

Prerequisites

  • Wallet with sufficient native token balance
  • No allowance required (native tokens don’t need approval)
  • RPC provider supporting the source chain

Complete Example

This example swaps 0.4 AVAX from Avalanche to USDC on BSC.
1

Setup Dependencies

Import required modules including NativeOrdersFactory.
import {
  EvmCrossChainOrder,
  HashLock,
  NetworkEnum,
  OrderStatus,
  PrivateKeyProviderConnector,
  SDK,
  EvmAddress,
  NativeOrdersFactory,
  Address
} from '@1inch/cross-chain-sdk'
import { JsonRpcProvider, Wallet } from 'ethers'
import { randomBytes } from 'node:crypto'
import assert from 'node:assert'

const PRIVATE_KEY = '0x...'
const WEB3_NODE_URL = 'https://...'
const AUTH_KEY = 'auth-key'
2

Initialize Providers

Set up ethers provider and SDK connector.
const ethersRpcProvider = new JsonRpcProvider(WEB3_NODE_URL)

const ethersProviderConnector = {
  eth: {
    call(transactionConfig): Promise<string> {
      return ethersRpcProvider.call(transactionConfig)
    }
  },
  extend(): void {}
}

const connector = new PrivateKeyProviderConnector(
  PRIVATE_KEY,
  ethersProviderConnector
)

const wallet = new Wallet(PRIVATE_KEY, ethersRpcProvider)

const sdk = new SDK({
  url: 'https://api.1inch.com/fusion-plus',
  authKey: AUTH_KEY,
  blockchainProvider: connector
})
3

Get Quote for Native Token

Request a quote using the native token address.
const quote = await sdk.getQuote({
  amount: '400000000000000000', // 0.4 AVAX
  srcChainId: NetworkEnum.AVALANCHE,
  dstChainId: NetworkEnum.BINANCE,
  enableEstimate: true,
  srcTokenAddress: '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', // AVAX
  dstTokenAddress: '0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d', // USDC
  walletAddress: wallet.address
})

const preset = quote.recommendedPreset
The address 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee is used for all native tokens (ETH, AVAX, BNB, MATIC, etc.).
4

Generate Secrets and Create Order

Generate secrets and create the order.
async function sleep(ms: number): Promise<void> {
  return new Promise((resolve) => setTimeout(resolve, ms))
}

// Generate secrets
const secrets = Array.from({
  length: quote.presets[preset].secretsCount
}).map(() => '0x' + randomBytes(32).toString('hex'))

const hashLock = secrets.length === 1
  ? HashLock.forSingleFill(secrets[0])
  : HashLock.forMultipleFills(HashLock.getMerkleLeaves(secrets))

const secretHashes = secrets.map((s) => HashLock.hashSecret(s))

// Create order
const { hash, quoteId, order } = sdk.createOrder(quote, {
  walletAddress: wallet.address,
  hashLock,
  preset,
  source: 'sdk-tutorial',
  secretHashes
})

assert(order instanceof EvmCrossChainOrder)
console.log({ hash }, 'order created')
5

Submit Native Order

Submit the order using submitNativeOrder() instead of submitOrder().
const orderInfo = await sdk.submitNativeOrder(
  quote.srcChainId,
  order,
  EvmAddress.fromString(wallet.address),
  quoteId,
  secretHashes
)
console.log({ hash }, 'order submitted')
Use submitNativeOrder() for native tokens, not submitOrder(). This ensures proper handling of native token value.
6

Broadcast Transaction with NativeOrdersFactory

Create the transaction call data and broadcast it.
// Get factory for the source chain
const factory = NativeOrdersFactory.default(NetworkEnum.AVALANCHE)

// Create transaction call data
const call = factory.create(
  new Address(wallet.address),
  orderInfo.order
)

// Send transaction with native token value
const txRes = await wallet.sendTransaction({
  to: call.to.toString(),
  data: call.data,
  value: call.value
})

console.log({ txHash: txRes.hash }, 'transaction broadcasted')

// Wait for confirmation
await wallet.provider.waitForTransaction(txRes.hash, 3)
The call.value field contains the amount of native token to send.
7

Monitor and Share Secrets

Monitor escrow deployments and share secrets.
while (true) {
  const secretsToShare = await sdk.getReadyToAcceptSecretFills(hash)

  if (secretsToShare.fills.length) {
    for (const { idx } of secretsToShare.fills) {
      // Verify escrow addresses before sharing secrets
      await sdk.submitSecret(hash, secrets[idx])
      console.log({ idx }, 'shared secret')
    }
  }

  // Check if order finished
  const { status } = await sdk.getOrderStatus(hash)

  if (
    status === OrderStatus.Executed ||
    status === OrderStatus.Expired ||
    status === OrderStatus.Refunded
  ) {
    break
  }

  await sleep(1000)
}

const statusResponse = await sdk.getOrderStatus(hash)
console.log(statusResponse)

Key Differences from Token Swaps

Native tokens use a special address:
// Native token (ETH, AVAX, BNB, etc.)
srcTokenAddress: '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'

// vs ERC20 token
srcTokenAddress: '0xc2132d05d31c914a87c6611c10748aeb04b58e8f'
Use submitNativeOrder() for native tokens:
// Native tokens
const orderInfo = await sdk.submitNativeOrder(
  srcChainId,
  order,
  EvmAddress.fromString(walletAddress),
  quoteId,
  secretHashes
)

// vs ERC20 tokens
const orderInfo = await sdk.submitOrder(
  srcChainId,
  order,
  quoteId,
  secretHashes
)
Use NativeOrdersFactory to create transaction data:
const factory = NativeOrdersFactory.default(NetworkEnum.AVALANCHE)
const call = factory.create(new Address(wallet.address), orderInfo.order)

await wallet.sendTransaction({
  to: call.to.toString(),
  data: call.data,
  value: call.value // Native token amount
})
For ERC20 tokens, the order submission handles this automatically.
Native tokens don’t require approval:
// No need for:
// await token.approve(limitOrderProtocol, amount)
You can create orders immediately if you have sufficient balance.

Supported Native Tokens

ChainNative TokenAddress
EthereumETH0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
PolygonMATIC0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
BSCBNB0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
AvalancheAVAX0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
ArbitrumETH0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
OptimismETH0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee

Error Handling

try {
  const txRes = await wallet.sendTransaction({
    to: call.to.toString(),
    data: call.data,
    value: call.value
  })
  await wallet.provider.waitForTransaction(txRes.hash, 3)
} catch (error) {
  if (error.message.includes('insufficient funds')) {
    console.error('Insufficient native token balance')
  } else if (error.message.includes('gas required exceeds allowance')) {
    console.error('Insufficient gas or gas price too low')
  } else {
    console.error('Transaction failed:', error)
  }
  throw error
}

Best Practices

Wait for Confirmation

Always wait for sufficient confirmations (3+ blocks) before proceeding.

Check Balance

Verify sufficient native token balance before creating orders.

Gas Estimation

Ensure wallet has extra native tokens for gas fees.

Use Recommended Preset

Use quote.recommendedPreset for optimal execution.

Transaction Value Calculation

The call.value includes the swap amount plus any required deposits:
const call = factory.create(new Address(wallet.address), orderInfo.order)

console.log('Transaction breakdown:')
console.log('- Total value:', call.value.toString())
console.log('- To address:', call.to.toString())
console.log('- Call data length:', call.data.length)

Next Steps

EVM to EVM

Learn about ERC20 token swaps

Integrator Fees

Add fees to your integration

Build docs developers (and LLMs) love