Skip to main content
This guide covers the complete workflow for creating atomic swaps between EVM-compatible chains using the 1inch Cross Chain SDK.

Overview

EVM to EVM swaps follow a standard workflow:
  1. Get a quote for the swap
  2. Generate secrets and create the order
  3. Submit the order to the relayer
  4. Monitor and share secrets as escrows are deployed
  5. Wait for order completion

Prerequisites

Before creating an order, ensure your wallet has sufficient allowance for the source token. The token must be approved for the Limit Order Protocol contract on the source chain.

Complete Example

This example demonstrates a swap of 10 USDT from Polygon to BNB on BSC.
1

Initialize the SDK

Set up the SDK with your authentication key and blockchain provider.
import {
  SDK,
  PrivateKeyProviderConnector,
  NetworkEnum,
  PresetEnum,
  HashLock,
  OrderStatus
} from '@1inch/cross-chain-sdk'
import Web3 from 'web3'
import { randomBytes } from 'node:crypto'

const privateKey = '0x...'
const rpc = 'https://ethereum-rpc.publicnode.com'
const authKey = 'your-auth-key'
const source = 'sdk-tutorial'

const web3 = new Web3(rpc)
const walletAddress = web3.eth.accounts.privateKeyToAccount(privateKey).address

const sdk = new SDK({
  url: 'https://api.1inch.com/fusion-plus',
  authKey,
  blockchainProvider: new PrivateKeyProviderConnector(privateKey, web3)
})
2

Get a Quote

Request a quote for your desired swap. Enable estimation to get accurate pricing.
// 10 USDT (Polygon) -> BNB (BSC)
const quote = await sdk.getQuote({
  amount: '10000000',
  srcChainId: NetworkEnum.POLYGON,
  dstChainId: NetworkEnum.BINANCE,
  enableEstimate: true,
  srcTokenAddress: '0xc2132d05d31c914a87c6611c10748aeb04b58e8f', // USDT
  dstTokenAddress: '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', // BNB
  walletAddress
})

const preset = PresetEnum.fast
The quote contains:
  • presets - Available execution presets (fast, medium, slow)
  • srcChainId / dstChainId - Source and destination chain IDs
  • srcTokenAddress / dstTokenAddress - Token addresses
  • amount - Source token amount
  • quoteId - Unique identifier for this quote
3

Generate Secrets and Hash Lock

Generate cryptographic secrets required for the atomic swap.
// Generate secrets based on preset requirements
const secrets = Array.from({
  length: quote.presets[preset].secretsCount
}).map(() => '0x' + randomBytes(32).toString('hex'))

// Create hash lock for single or multiple fills
const hashLock = secrets.length === 1
  ? HashLock.forSingleFill(secrets[0])
  : HashLock.forMultipleFills(HashLock.getMerkleLeaves(secrets))

// Hash secrets for submission
const secretHashes = secrets.map((s) => HashLock.hashSecret(s))
The number of secrets depends on the preset’s secretsCount. Each secret will be revealed as escrows are deployed.
4

Create the Order

Create the order with your parameters.
const { hash, quoteId, order } = await sdk.createOrder(quote, {
  walletAddress,
  hashLock,
  preset,
  source,
  secretHashes
})

console.log({ hash }, 'order created')
The order is signed with your private key and includes all swap parameters.
5

Submit the Order

Submit the order to the 1inch relayer network.
const _orderInfo = await sdk.submitOrder(
  quote.srcChainId,
  order,
  quoteId,
  secretHashes
)

console.log({ hash }, 'order submitted')
Once submitted, resolvers can see your order and begin the fulfillment process.
6

Monitor and Share Secrets

Monitor the order status and share secrets as escrows are deployed.
async function sleep(ms: number): Promise<void> {
  return new Promise((resolve) => setTimeout(resolve, ms))
}

while (true) {
  // Check which secrets are ready to be shared
  const secretsToShare = await sdk.getReadyToAcceptSecretFills(hash)

  if (secretsToShare.fills.length) {
    for (const { idx } of secretsToShare.fills) {
      // It is your responsibility to verify the escrow addresses
      // are correct before sharing secrets
      await sdk.submitSecret(hash, secrets[idx])
      console.log({ idx }, 'shared secret')
    }
  }

  // Check if order is 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)
Always verify escrow addresses before sharing secrets. Once a secret is revealed, the resolver can withdraw funds from the escrow.

Error Handling

Implement proper error handling for production use:
try {
  const quote = await sdk.getQuote({
    amount: '10000000',
    srcChainId: NetworkEnum.POLYGON,
    dstChainId: NetworkEnum.BINANCE,
    srcTokenAddress: '0xc2132d05d31c914a87c6611c10748aeb04b58e8f',
    dstTokenAddress: '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
    walletAddress,
    enableEstimate: true
  })
} catch (error) {
  if (error.message.includes('insufficient allowance')) {
    // Handle allowance error
  } else if (error.message.includes('insufficient balance')) {
    // Handle balance error
  } else {
    // Handle other errors
    console.error('Failed to get quote:', error)
  }
}

Best Practices

Verify Escrows

Always verify escrow addresses match expected values before sharing secrets.

Monitor Status

Continuously monitor order status to handle expired or refunded orders.

Handle Timeouts

Set appropriate timeouts for the monitoring loop to avoid infinite execution.

Log Events

Log all order events for debugging and tracking purposes.

Order Presets

Choose a preset based on your requirements:
  • Fast: Quickest execution, higher fees
  • Medium: Balanced speed and fees
  • Slow: Lower fees, longer execution time
Access presets through quote.presets[PresetEnum.fast].

Next Steps

Order Lifecycle

Learn about order states and transitions

Integrator Fees

Add fees to your integration

Build docs developers (and LLMs) love