Quickstart
This guide walks you through creating a complete cross-chain swap from Polygon to BNB Chain. You’ll swap 10 USDT on Polygon for BNB on BNB Chain.
Complete Example
Here’s a working example that demonstrates the full cross-chain swap workflow:
import {
HashLock ,
NetworkEnum ,
OrderStatus ,
PresetEnum ,
PrivateKeyProviderConnector ,
SDK
} 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 )
})
async function sleep ( ms : number ) : Promise < void > {
return new Promise (( resolve ) => setTimeout ( resolve , ms ))
}
async function main () : Promise < void > {
// 10 USDT (Polygon) -> BNB (BSC)
// Step 1: Get a quote
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
// Step 2: 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 ))
// Step 3: Create order
const { hash , quoteId , order } = await sdk . createOrder ( quote , {
walletAddress ,
hashLock ,
preset ,
source ,
secretHashes
})
console . log ({ hash }, 'order created' )
// Step 4: Submit order
const _orderInfo = await sdk . submitOrder (
quote . srcChainId ,
order ,
quoteId ,
secretHashes
)
console . log ({ hash }, 'order submitted' )
// Step 5: Monitor and submit secrets
while ( true ) {
const secretsToShare = await sdk . getReadyToAcceptSecretFills ( hash )
if ( secretsToShare . fills . length ) {
for ( const { idx } of secretsToShare . fills ) {
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 )
}
main ()
Step-by-Step Breakdown
Let’s break down each step of the swap process:
Initialize the SDK
Set up your SDK instance with authentication and a blockchain provider: const sdk = new SDK ({
url: 'https://api.1inch.com/fusion-plus' ,
authKey ,
blockchainProvider: new PrivateKeyProviderConnector ( privateKey , web3 )
})
The blockchain provider is required for creating orders. It’s used to sign transactions on the source chain.
Request a quote
Get pricing and routing information for your swap: const quote = await sdk . getQuote ({
amount: '10000000' , // 10 USDT (6 decimals)
srcChainId: NetworkEnum . POLYGON ,
dstChainId: NetworkEnum . BINANCE ,
enableEstimate: true ,
srcTokenAddress: '0xc2132d05d31c914a87c6611c10748aeb04b58e8f' , // USDT
dstTokenAddress: '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' , // BNB
walletAddress
})
Use 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee as the token address for native assets (ETH, BNB, MATIC, etc.).
Generate cryptographic secrets
Create random secrets that will secure your swap: const preset = PresetEnum . fast
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 ))
Presets explained:
PresetEnum.fast - Fastest execution, may have higher fees
PresetEnum.medium - Balanced speed and cost
PresetEnum.slow - Lowest fees, longer execution time
quote.recommendedPreset - Automatically selected optimal preset
Create the order
Generate a signed order with your quote and hash lock: const { hash , quoteId , order } = await sdk . createOrder ( quote , {
walletAddress ,
hashLock ,
preset ,
source , // Identifier for your integration
secretHashes
})
console . log ({ hash }, 'order created' )
This creates a signed order but doesn’t submit it to the network yet.
Submit the order
Send your order to the network for execution: const orderInfo = await sdk . submitOrder (
quote . srcChainId ,
order ,
quoteId ,
secretHashes
)
console . log ({ hash }, 'order submitted' )
At this point, your order is visible to resolvers who will begin deploying escrows.
Monitor and submit secrets
Watch for escrow deployments and submit secrets to complete the swap: while ( true ) {
const secretsToShare = await sdk . getReadyToAcceptSecretFills ( hash )
if ( secretsToShare . fills . length ) {
for ( const { idx } of secretsToShare . fills ) {
// Submit the secret to unlock the escrow
await sdk . submitSecret ( hash , secrets [ idx ])
console . log ({ idx }, 'shared secret' )
}
}
// Check if order is complete
const { status } = await sdk . getOrderStatus ( hash )
if (
status === OrderStatus . Executed ||
status === OrderStatus . Expired ||
status === OrderStatus . Refunded
) {
break
}
await sleep ( 1000 )
}
In production, you should verify escrow addresses and conditions before submitting secrets. The SDK provides methods to inspect escrow details.
Check final status
Verify the swap completed successfully: const statusResponse = await sdk . getOrderStatus ( hash )
console . log ( statusResponse )
Possible final statuses:
OrderStatus.Executed - Swap completed successfully
OrderStatus.Expired - Order expired before completion
OrderStatus.Refunded - Order failed and funds were refunded
Prerequisites
Before running this example, ensure:
Your wallet has sufficient USDT on Polygon for the swap amount
Your wallet has enough MATIC to pay for gas fees on Polygon
You’ve approved the Limit Order Protocol contract to spend your USDT
Token Approval
Before creating an order, approve the Limit Order Protocol contract:
import { LimitOrderContract } from '@1inch/cross-chain-sdk'
// Get the contract address for your source chain
const contractAddress = LimitOrderContract . getAddress ( NetworkEnum . POLYGON )
// Approve USDT spending (use your Web3/Ethers instance)
const usdtContract = new web3 . eth . Contract ( ERC20_ABI , '0xc2132d05d31c914a87c6611c10748aeb04b58e8f' )
await usdtContract . methods . approve (
contractAddress ,
'10000000' // Amount to approve
). send ({ from: walletAddress })
Understanding Order Status
You can query order status at any time:
const status = await sdk . getOrderStatus ( orderHash )
console . log ({
status: status . status , // Current status enum
fills: status . fills , // Fill details
srcRemainingAmount: status . srcRemainingAmount , // Unfilled source amount
dstFilledAmount: status . dstFilledAmount // Filled destination amount
})
Error Handling
Wrap your swap logic in proper error handling:
try {
await main ()
} catch ( error ) {
if ( error . message . includes ( 'insufficient allowance' )) {
console . error ( 'Please approve token spending first' )
} else if ( error . message . includes ( 'insufficient balance' )) {
console . error ( 'Insufficient token balance' )
} else {
console . error ( 'Swap failed:' , error )
}
}
Next Steps
EVM to EVM Guide Deep dive into EVM-to-EVM swaps with advanced features
Solana Swaps Learn how to swap between Solana and EVM chains
Native Token Swaps Swap native assets like ETH, BNB, and AVAX
Order Lifecycle Understand the complete order execution flow