🛝API Flow
Rango Exchange Main API Flow
Scenario
Here is a sample interaction scenario between a dApp and Rango Main API/SDK. This flow is designed to be as straightforward as possible, but additional steps can be taken to enhance functionality.
1. The dApp calls Meta method to get list of all supported blockchains, swappers and tokens which are used to show a proper swap box for the user.
Sample Code:
const metaResponse = await axios.get('https://api.rango.exchange/meta', {
params: {
'apiKey': 'c6381a79-2817-4602-83bf-6a641a409e32'
}
});
Use the fetched metadata to display available blockchains and their tokens to the user. Allow the user to select the source and destination tokens.
2. The user selects to swap 1 BSC.BNB
to AVAX_CCHAIN.USDT--0x9702230a8ea53601f5cd2dc00fdbc13d4df4a8c7
.
Here is the sample code:
const tokens = meta.tokens;
const BNB_ADDRESS = null
const USDT_ADDRESS = '0xc7198437980c041c805a1edcba50c1ce5db95118'
const BSC_BNB = tokens.find(t => t.address === BNB_ADDRESS && t.blockchain === 'BSC')
const AVAX_USDT = tokens.find(t => t.address === USDT_ADDRESS && t.blockchain === 'AVAX_CCHAIN')
3. The dApp retrieves the best possible route between the tokens by calling the Get All Possible Routes API. If the user doesn't select and confirm one of the routes within the timeout period (e.g. after 30s), this step should be repeated to ensure the output amount and routes are up to date.
Here is the sample code:
const routingResponse = await axios.post(
'https://api.rango.exchange/routing/bests',
{
'from': {
'blockchain': 'BSC',
'symbol': 'BNB',
'address': null,
},
'to': {
'blockchain': 'AVAX_CCHAIN',
'symbol': 'USDT.E',
'address': '0xc7198437980c041c805a1edcba50c1ce5db95118'
},
'amount': '1',
'slippage': '1.0'
},
{
params: {
'apiKey': 'c6381a79-2817-4602-83bf-6a641a409e32'
},
headers: {
'content-type': 'application/json'
}
}
);
// check if the route was okay
if (!routingResponse.results || routingResponse.error) {
// no routes found
// you could show diagnosis messages to user if it is not empty
// sample: "diagnosisMessages":["Your input amount might be too low!"]
console.log(routingResponse.diagnosisMessages)
} else {
// everything was okay
}
4. The user selects one of the routes to start the executing the route.
This is an example of selected route which includes two steps:
Step 1: Swap BSC.BNB to BSC.USDT via 1Inch.
Step 2: Swap BSC.USDT to AVAX_CCHAIN.USDT via Stargate Bridge.
5. The dApp call the Confirm Route API to notify Rango that this route has been selected for execution. 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.
Here is the sample code:
const confirmResponse = await axios.post(
'https://api.rango.exchange/routing/confirm',
{
'selectedWallets': {
'BSC': '0xeae6d42093eae057e770010ffd6f4445f7956613',
'AVAX_CCHAIN': '0xeae6d42093eae057e770010ffd6f4445f7956613'
},
'destination': '0x6f33bb1763eebead07cf8815a62fcd7b30311fa3',
'requestId': '33e0b996-da5e-4922-9fdc-f7206247fc34'
},
{
params: {
'apiKey': 'c6381a79-2817-4602-83bf-6a641a409e32'
},
headers: {
'content-type': 'application/json'
}
}
);
// check if the route was okay
if (!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 one
const confirmedOutput = new BigNumber(routingResponse.results[selected]?.outputAmount)
const finalOutput = new BigNumber(confirmResponse.result?.outputAmount)
if (finalOutput.lt(confirmedOutput.multipliedBy(new BigNumber(0.98))) {
// get double confirmation from the user
} else {
// proceed to executing the route
}
}
For every steps of the selected route, we need to repeat the next steps:
6. The dApp calls the Create Transaction API to get transaction data for this step.
The response of create transaction API could be an approve transaction (isApproval=true
) or the main transaction. (isApproval=false
)
const createTransactionResponse = await axios.post(
'https://api.rango.exchange/tx/create',
{
'requestId': '1978d8fa-335d-4915-a039-77f1a17315f5',
'step': 1,
'userSettings': {
'slippage': 3,
'infiniteApprove': false
},
'validations': {
'balance': true,
'fee': true,
'approve': true
}
},
{
params: {
'apiKey': 'c6381a79-2817-4602-83bf-6a641a409e32'
},
headers: {
'content-type': 'application/json'
}
}
);
if (createTransactionResponse.transaction) {
// everything was okay
} else {
// there was a problem in creating transaction
console.log(createTransactionResponse.error)
}
How to set validation parameters?
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.
7. If the transaction is related to a blockchain with approve requirement, i.e. all EVM based blockchains, Starknet and Tron, and user doesn't have enough approval, dApp could generate approve transaction and ask user to sign it.
Is it possible to generate approve transaction on client side without using Rango API?
It is important to use approve transaction data generated by Rango API and not hard-coding something on your client side for creating approve transaction, because for some protocols (some bridges), the contract that should be approved is dynamically generated via their API based on the route.
Sample Code for EVM transactions:
// sample type guard
export const isEvmTransaction = (tx: {
type: TransactionType
}): transaction is EvmTransaction => tx.type === TransactionType.EVM
// how to build and sign EVM approve transaction
const tx = createTransactionResponse.transaction
if (isEvmTransacation(tx)) {
if (tx.isApproval) {
// user doesn't have enough approval and needs to sign approve tx
let approveTx = {
from: tx.from,
to: tx.to,
data: tx.data,
value: tx.value,
gasLimit: tx.gasLimit
}
if (tx.gasPrice) {
swapTx = { gasPrice: tx.gasPrice, ...swapTx }
} else if (tx.maxPriorityFeePerGas && tx.maxFeePerGas) {
swapTx = {
maxFeePerGas: tx.maxFeePerGas,
maxPriorityFeePerGas: tx.maxPriorityFeePerGas,
...swapTx
}
}
const approveTxHash = (await signer.sendTransaction(approveTx)).hash
} else {
// user already has enough approve amoaunt
// we could proceed to 8th step (main transaction)
}
}
8. The dApp periodically calls Check Approval API to make sure approve transaction is mined successfully and user has enough approval for the swap.
For checking approval transaction status, you could also check it directly from the RPC endpoint if you prefer and skip calling Rango API for this purpose.
Here is the sample code:
const response = await axios.get('https://api.rango.exchange/tx/b3a12c6d-86b8-4c21-97e4-809151dd4036/check-approval', {
params: {
'txId': '0x7f17aaba51d1f24204cd8b02251001d3704add46d84840a5826b95ef49b8b74f',
'apiKey': 'c6381a79-2817-4602-83bf-6a641a409e32'
}
});
if (response.isApproved) {
// user has enough approve amount now
// we could proceed to the next step
} else {
if (response.txStatus === 'failed') {
// approve transaction with given hash fails on blockchain
// it could happen for different reasons, e.g. low gas price
// action => ask user to signs the approve transaction again.
} else {
// scenario: response.txStatus === 'success'
// approve transaction succeeds but user doesn't have still enough approval
// it could happen in rare cases for example when user changes dapp
// suggested approve amount in Metamask and override it with a lower one
}
}
9. The dApp calls the Create Transaction API again to fetch the main swap transaction and asks user to sign it. (similar to the 6th and 6th steps)
Sample code for EVM transactions:
// sample type guard
export const isEvmTransaction = (tx: {
type: TransactionType
}): transaction is EvmTransaction => tx.type === TransactionType.EVM
// how to build and sign EVM main transaction
const tx = createTransactionResponse.transaction
if (isEvmTransacation(tx)) {
let swapTx = {
from: tx.from,
to: tx.to,
data: tx.data,
value: tx.value,
gasLimit: tx.gasLimit
}
if (tx.gasPrice) {
swapTx = { gasPrice: tx.gasPrice, ...swapTx }
} else if (tx.maxPriorityFeePerGas && tx.maxFeePerGas) {
swapTx = {
maxFeePerGas: tx.maxFeePerGas,
maxPriorityFeePerGas: tx.maxPriorityFeePerGas,
...swapTx
}
}
const swpTxHash = (await signer.sendTransaction(swapTx)).hash
}
10. The dApp calls Check Status API periodically to see if it was successful or failed.
By calling this method, dApp could get the outbound transaction hash and make sure if the outbound transaction on the destination blockchain succeeds or transaction failed and user was refunded.
const response = await axios.post(
'https://api.rango.exchange/tx/check-status',
{
'requestId': 'b3a12c6d-86b8-4c21-97e4-809151dd4036',
'txId': '0xfa88b705a5b4049adac7caff50c887d9600ef023ef1a937f8f8b6f44e90042b5',
'step': 1
},
{
params: {
'apiKey': 'c6381a79-2817-4602-83bf-6a641a409e32'
},
headers: {
'content-type': 'application/json'
}
}
);
if (response.status) {
// show latest status of the swap to the user
if (response.status === TransactionStatus.SUCCESS) {
// swap suceeded
} else if (response.status === TransactionStatus.FAILED) {
// swap failed
} else {
// swap is still running
// we need to call check-status method again after a timeout (10s)
}
}
11. If the step succeeds, the dApp repeats all instructions from steps 6 to 10 for the next step of the route.
12. If the swap fails because of a client side error like RPC errors in signing the transaction, dApp optionally calls Report Failure API to report the failure to Rango API.
Sample code:
await axios.post(
'https://api.rango.exchange/tx/report-tx',
{
'requestId': '688b308e-a06b-4a4e-a837-220d458b8642',
'step': 1,
'eventType': 'SEND_TX_FAILED',
'reason': 'RPC Error'
},
{
params: {
'apiKey': 'c6381a79-2817-4602-83bf-6a641a409e32'
},
headers: {
'content-type': 'application/json'
}
}
);
Flow Chart
Last updated