This example demonstrates how to swap tokens across different blockchain networks using the Deframe API with JavaScript/TypeScript.
Overview
This example covers:
- Getting a cross-chain swap quote
- Generating transaction bytecode
- Executing the swap transaction
- Monitoring transaction status across chains
Prerequisites
- Node.js 18+
- Deframe API key
- Wallet with tokens on the origin chain
- Basic understanding of async/await
Choose Your Library
Using ethers.js v6 for blockchain interactions - the most popular Ethereum library.
Using viem for blockchain interactions - a modern, TypeScript-first alternative with better performance.
Installation
Environment Variables
Create a .env file:
DEFRAME_API_KEY=your-api-key
WALLET_ADDRESS=0x...
PRIVATE_KEY=0x...
ORIGIN_RPC_URL=https://eth-mainnet.g.alchemy.com/v2/your-key
DESTINATION_RPC_URL=https://polygon-mainnet.g.alchemy.com/v2/your-key
Never commit your .env file to version control. Add it to .gitignore.
Step-by-Step Walkthrough
1. Initialize API Client
import axios from 'axios'
const deframe = axios.create({
baseURL: 'https://api.deframe.io',
headers: {
'x-api-key': process.env.DEFRAME_API_KEY,
'Content-Type': 'application/json'
}
})
2. Get Cross-Chain Quote
const { data } = await deframe.get('/swap/quote', {
params: {
originChain: 'ethereum',
destinationChain: 'polygon',
tokenIn: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC on Ethereum
tokenOut: '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174', // USDC on Polygon
amountIn: '1000000000' // 1000 USDC (6 decimals)
}
})
const quote = data.quote
console.log('Quote ID:', quote.quoteId)
console.log('Origin Chain:', quote.originChain)
console.log('Destination Chain:', quote.destinationChain)
console.log('Expected output:', quote.tokenOut.amount)
console.log('Provider:', quote.provider)
console.log('Deadline:', quote.deadline)
Cross-chain swaps use bridge providers like TeleSwap or Mayan and may take several minutes to complete.
3. Generate Bytecode
const { data: bytecode } = await deframe.post('/swap/bytecode', {
quoteId: quote.quoteId,
originAddress: walletAddress,
destinationAddress: walletAddress,
rawQuote: quote.rawQuote
})
console.log('Chain ID:', bytecode.chainId)
console.log('Transactions to execute:', bytecode.transactionData.length)
4. Execute Transactions
import { ethers } from 'ethers'
// Connect to origin chain
const provider = new ethers.JsonRpcProvider(process.env.ORIGIN_RPC_URL)
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider)
for (const tx of bytecode.transactionData) {
const transaction = await wallet.sendTransaction({
to: tx.to,
data: tx.data,
value: tx.value,
chainId: tx.chainId
})
console.log('Transaction sent:', transaction.hash)
const receipt = await transaction.wait()
console.log('Confirmed in block:', receipt.blockNumber)
}
console.log('✅ Origin transaction completed!')
console.log('⏳ Waiting for bridge to process...')
import { createWalletClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
const account = privateKeyToAccount(process.env.PRIVATE_KEY)
const client = createWalletClient({
account,
chain: mainnet,
transport: http(process.env.ORIGIN_RPC_URL)
})
for (const tx of bytecode.transactionData) {
const hash = await client.sendTransaction({
to: tx.to,
data: tx.data,
value: BigInt(tx.value),
chain: mainnet
})
console.log('Transaction sent:', hash)
const receipt = await client.waitForTransactionReceipt({ hash })
console.log('Confirmed in block:', receipt.blockNumber)
}
console.log('✅ Origin transaction completed!')
console.log('⏳ Waiting for bridge to process...')
5. Monitor Status
Transaction status tracking is available in an upcoming release.
For now, monitor your transaction directly on-chain using the
transaction hash returned after execution.
// Poll for status updates
const swapId = quote.quoteId
let status = 'pending'
while (status !== 'success' && status !== 'failed') {
await new Promise(resolve => setTimeout(resolve, 10000)) // Wait 10s
const { data: statusData } = await deframe.get(`/swap/status/${swapId}`)
status = statusData.status
console.log('Status:', status)
if (statusData.originTxHash) {
console.log('Origin TX:', statusData.originTxHash)
}
if (statusData.destinationTxHash) {
console.log('Destination TX:', statusData.destinationTxHash)
}
}
if (status === 'success') {
console.log('🎉 Cross-chain swap completed successfully!')
} else {
console.error('❌ Swap failed')
}
Webhook Alternative
Instead of polling, you can configure webhooks to receive status updates:
// Configure webhook in your Deframe dashboard
// Webhook payload will include:
{
"swapId": "550e8400-e29b-41d4-a716-446655440000",
"status": "success",
"originTxHash": "0x123...",
"destinationTxHash": "0x456...",
"timestamp": "2024-01-24T12:35:00.000Z"
}
Error Handling
try {
// Your code here
} catch (error) {
if (error.response?.data?.error) {
const apiError = error.response.data.error
console.error('API Error:', apiError.code)
console.error('Message:', apiError.message)
if (apiError.code === 'QUOTE_EXPIRED') {
console.log('Quote expired, please request a new one')
} else if (apiError.code === 'NO_ROUTE_FOUND') {
console.log('No cross-chain route available')
}
} else {
console.error('Unexpected error:', error.message)
}
}
Running the Example
# Install dependencies
npm install
# Set environment variables
cp .env.example .env
# Edit .env with your values
# Run the example
node cross-chain-swap.js
Expected Output
1️⃣ Getting cross-chain quote...
✅ Quote received:
Quote ID: 550e8400-e29b-41d4-a716-446655440000
Origin: ethereum
Destination: polygon
Provider: TeleSwap
Amount in: 1000 USDC
Expected out: 998.5 USDC
Deadline: 2024-01-24T12:35:00.000Z
2️⃣ Generating bytecode...
✅ Bytecode generated:
Chain ID: 1 (ethereum)
Transactions: 2
3️⃣ Executing origin transactions...
Transaction 1/2 (Approve)...
Transaction sent: 0x123...
✅ Confirmed in block 12345678
Transaction 2/2 (Bridge)...
Transaction sent: 0x456...
✅ Confirmed in block 12345679
✅ Origin transaction completed!
⏳ Waiting for bridge to process...
4️⃣ Monitoring status...
Status: crossing
Origin TX: 0x456...
Status: propagated
Origin TX: 0x456...
Destination TX: 0x789...
Status: success
Origin TX: 0x456...
Destination TX: 0x789...
🎉 Cross-chain swap completed successfully!
Next Steps