You could read this guide to understand the flow of integrating Rango-SDK. If you prefer to dive directly into the code and explore it there, you can use the links below.
Install TS SDK
If you decide not to use our TypeScript SDK and prefer integration in other programming languages, feel free to skip this step.
To integrate Rango SDK inside your dApp or wallet, you need to install rango-sdk using npm or yarn.
npminstall--saverango-sdk# or yarnaddrango-sdk
Then you need to instantiate RangoClient and use it in the next steps.
To get the list of available blockchains, tokens, and protocols (dex or bridge) supported by Rango, you could use the getAllMetadata method like this:
constmeta=awaitrango.getAllMetadata()
Routing
Get All Routes
Using information retrieved from the meta, you could implement your own SwapBox including your blockchain and token selector. The next step is to show the preview of the best route possible when the user selects the source and the destination tokens.
The blockchain and symbol names must be exactly what is fetched from Rango's Meta API.
// Converting 0.1 BSC BNB to AVAX_CCHAIN USDT.E constroutingResponse=awaitrango.getAllRoutes({ from: {"blockchain":"BSC","symbol":"BNB","address":null }, to: {"blockchain":"AVAX_CCHAIN","symbol":"USDT.E","address":"0xc7198437980c041c805a1edcba50c1ce5db95118" }, amount:"0.1", slippage:"1.0",})
You could call this method periodically to get the updated route before the user confirms the route.
Confirm Route
Using the getAllRoutes method, you obtain a list of available routes. Once the user selects and confirms a route, you need to call the confirm method to notify Rango that the user has chosen this route for the next step and retrieve the final, updated route to display to the user.
To confirm the route, you must provide the selected route's request ID, the wallet addresses for all blockchains in the route, and optionally, a custom destination if the user wishes to send funds to a different wallet than the one specified for the related blockchain (in selectedWallets).
// user selects one of the routesconstselectedRoute=routingResponse.results[0]constconfirmResponse=awaitrango.confirmRoute({ requestId:selectedRoute.requestId, selectedWallets: {'BSC':'0xeae6d42093eae057e770010ffd6f4445f7956613','AVAX_CCHAIN':'0xeae6d42093eae057e770010ffd6f4445f7956613' }, destination:'0x6f33bb1763eebead07cf8815a62fcd7b30311fa3'})
At this stage, it is also possible to verify if the user has sufficient balance and fees for each step of the route in advance based on confirm response validation field. Also, you can compare the confirmed route with the route's output amount and alert the user if there is a significant difference.
// check if the route was okayif (!confirmResponse.result ||confirmResponse.error) {// there was a problem in confirming the route} else {// everything was okay// you could compare confirmed route with the route output amount // and warn the user if there is noticable difference// e.g. check if confirmed route output is 2% less than previous oneconstconfirmedOutput=newBigNumber(routingResponse.results[selected]?.outputAmount)constfinalOutput=newBigNumber(confirmResponse.result?.outputAmount)if (finalOutput.lt(confirmedOutput.multipliedBy(newBigNumber(0.98))) {// get double confirmation from the user } else {// proceed to executing the route }}
Route Execution
For every steps of the selected route, we need to repeat the next steps:
Creating Transaction
If the source blockchain for this step requires approval, such as EVM-based blockchains, Starknet, or Tron, and the user lacks sufficient approval, the Rango API will return an approval transaction in the response. The user must sign this transaction, and in the next createTransaction call for this step, the Rango API will provide the main transaction. Therefore, the createTransaction API response could either be an approval transaction (isApproval=true) or the main transaction (isApproval=false).
If you are verifying the balance and fee amount on your client side or you've already checked them in route confirmation step, it is advisable to set the balance and fee parameters to false to prevent duplicate checks or potential errors during validation.
Tracking Swap Status
After signing the transaction by the user and receiving transaction hash, you could periodically call Rango check-status API to track the transaction status. In Rango, each swap step could have 3 different states: running, failed and success. You only need to keep checking the status until you find out whether the transaction failed or succeeded.
conststate=awaitrango.checkStatus({ requestId:confirmedRoute.requestId, step:1,// related step txId:'0xfa88b705a5b4049adac7caff50c887d9600ef023ef1a937f8f8b6f44e90042b5'})if (response.status) {// show latest status of the swap to the userif (response.status ===TransactionStatus.SUCCESS) {// swap suceeded } elseif (response.status ===TransactionStatus.FAILED) {// swap failed } else {// swap is still running// we need to call check-status method again after a timeout (10s) }}
Complete Code Flow
Node.JS Example
// run `node --import=tsx index.ts` in the terminalimport { CreateTransactionRequest, RangoClient, TransactionStatus, TransactionType } from"rango-sdk";import { findToken } from'../shared/utils/meta.js'import { TransactionRequest, ethers } from"ethers";import { setTimeout } from'timers/promises'// setup wallet & RPC provider// please change rpc provider url if you want to test another chain rather than BSCconstprivateKey='YOUR_PRIVATE_KEY';constwallet=newethers.Wallet(privateKey);constrpcProvider=newethers.JsonRpcProvider('https://bsc-dataseed1.defibit.io');constwalletWithProvider=wallet.connect(rpcProvider);constwaleltAddress=walletWithProvider.address// initiate sdk using your api keyconstAPI_KEY="c6381a79-2817-4602-83bf-6a641a409e32"constrango=newRangoClient(API_KEY)// get blockchains and tokens meta dataconstmeta=awaitrango.getAllMetadata()// some example tokens for test purposeconstsourceBlockchain="BSC"constsourceTokenAddress="0x55d398326f99059ff775485246999027b3197955"consttargetBlockchain="BSC"consttargetTokenAddress=nullconstamount="0.001"// find selected tokens in meta.tokensconstsourceToken=findToken(meta.tokens, sourceBlockchain, sourceTokenAddress)consttargetToken=findToken(meta.tokens, targetBlockchain, targetTokenAddress)// get routeconstroutingRequest= { from: sourceToken, to: targetToken, amount, slippage:'1.0',}constroutingResponse=awaitrango.getAllRoutes(routingRequest)if (routingResponse.results.length===0) {thrownewError(`There was no route! ${routingResponse.error}`)}// confirm one of the routesconstselectedRoute=routingResponse.results[0]constselectedWallets=selectedRoute.swaps.flatMap(swap => [swap.from.blockchain,swap.to.blockchain]).filter((blockchain, index, self) =>self.indexOf(blockchain) === index).map(blockchain => ({ [blockchain]: waleltAddress })).reduce((acc, obj) => {return { ...acc,...obj }; }, {});constconfirmResponse=awaitrango.confirmRoute({ requestId:selectedRoute.requestId, selectedWallets,})constconfirmedRoute=confirmResponse.resultif (!confirmedRoute) {thrownewError(`Error in confirming route, ${confirmResponse.error}`)}let step =1constswapSteps=confirmedRoute.result?.swaps || []for (constswapof swapSteps) {constrequest:CreateTransactionRequest= { requestId:confirmedRoute.requestId, step: step, userSettings: { slippage:'1.0', infiniteApprove:false }, validations: { approve:true, balance:false, fee:false, } }let createTransactionResponse =awaitrango.createTransaction(request)let tx =createTransactionResponse.transactionif (!tx) {thrownewError(`Error creating the transaction ${createTransactionResponse.error}`) }if (tx.type ===TransactionType.EVM) {if (tx.isApprovalTx) {// sign the approve transactionconstapproveTransaction:TransactionRequest= { from:tx.from, to:tx.to, data:tx.data, value:tx.value, maxFeePerGas:tx.maxFeePerGas, maxPriorityFeePerGas:tx.maxPriorityFeePerGas, gasPrice:tx.gasPrice, gasLimit:tx.gasLimit, }const { hash } =awaitwalletWithProvider.sendTransaction(approveTransaction);// wait for approvalwhile (true) {awaitsetTimeout(5_000) const { isApproved, currentApprovedAmount, requiredApprovedAmount, txStatus } = await rango.checkApproval(confirmedRoute.requestId, hash)
if (isApproved)breakelseif (txStatus ===TransactionStatus.FAILED)thrownewError('Approve transaction failed in blockchain')elseif (txStatus ===TransactionStatus.SUCCESS) throw new Error(`Insufficient approve, current amount: ${currentApprovedAmount}, required amount: ${requiredApprovedAmount}`)
}// create the main transaction if previous one was approval transaction createTransactionResponse =awaitrango.createTransaction(request) tx =createTransactionResponse.transactionif (!tx ||tx.type !==TransactionType.EVM) {thrownewError(`Error creating the transaction ${createTransactionResponse.error}`) } }// sign the main transactionconstmainTransaction:TransactionRequest= { from:tx.from, to:tx.to, data:tx.data, value:tx.value, maxFeePerGas:tx.maxFeePerGas, maxPriorityFeePerGas:tx.maxPriorityFeePerGas, gasPrice:tx.gasPrice, gasLimit:tx.gasLimit, }const { hash } =awaitwalletWithProvider.sendTransaction(mainTransaction);// track swap statuswhile (true) {awaitsetTimeout(10_000)conststate=awaitrango.checkStatus({ requestId:confirmedRoute.requestId, step, txId: hash })conststatus=state.statusif (status ===TransactionStatus.SUCCESS) {// we could proceed with the next step of the route step +=1;break } elseif (status ===TransactionStatus.FAILED) {thrownewError(`Swap failed on step ${step}`) } } }}