Transferring Tokens
Transferring from one token to another, across one or more chains, is simple.
The following section will explain step by step how to transfer tokens across one or more chains.

Step 1: Requesting a Quote

The request for a transfer from 1 USDC on Gnosis to USDC on Polygon looks the following:
1
const getQuote = async (fromChain, toChain, fromToken, toToken, fromAmount, fromAddress) => {
2
const result = await axios.get('https://li.quest/v1/quote', {
3
params: {
4
fromChain,
5
toChain,
6
fromToken,
7
toToken,
8
fromAmount,
9
fromAddress,
10
}
11
});
12
return result.data;
13
}
14
​
15
const fromChain = 'DAI';
16
const fromToken = 'USDC';
17
const toChain = 'POL';
18
const toToken = 'USDC';
19
const fromAmount = '1000000';
20
const fromAddress = YOUR_WALLET_ADDRESS;
21
​
22
const quote = await getQuote(fromChain, toChain, fromToken, toToken, fromAmount, fromAddress);
Copied!
The quote response contains a transactionRequest object which can be directly passed on to your wallet/signer.
To learn more about quotes, head over to our Requesting a Quote guide.

Step 2: Sending the Transaction

After having received a quote, the transaction has to be sent to trigger the transfer.
Firstly, the wallet has to be configured. The following example connects your wallet to the Gnosis Chain.
1
const provider = new ethers.providers.JsonRpcProvider('https://rpc.xdaichain.com/', 100);
2
const wallet = ethers.Wallet.fromMnemonic(YOUR_PERSONAL_MNEMONIC).connect(
3
provider
4
);
Copied!
Afterwards, the transaction can be sent using the transactionRequest inside the previously retrieved quote:
1
const tx = await wallet.sendTransaction(quote.transactionRequest);
2
await tx.wait();
Copied!
For simple swaps on a single chain, this is enough. For cross chain transfers, the processing takes a bit longer. To handle this the API provides an endpoint to check for the transfers status.

Step 3: Waiting for the transfer to complete

Checking the status of the transfer is only necessary for cross chain transfers
To check if the token was successfully sent to the receiving chain, the /status endpoint can be called:
1
const getStatus = async (bridge, fromChain, toChain, txHash) => {
2
const result = await axios.get('https://li.quest/v1/status', {
3
params: {
4
bridge,
5
fromChain,
6
toChain,
7
txHash,
8
}
9
});
10
return result.data;
11
}
12
​
13
result = await getStatus(quote.tool, fromChain, toChain, tx.hash);
Copied!
If you want to learn more about the status endpoint and how to deal with the potential results check our Status Guide.

All things plugged together

The whole process then looks like this:
1
const ethers = require('ethers');
2
const axios = require('axios');
3
​
4
const API_URL = 'https://li.quest/v1';
5
​
6
// Get a quote for your desired transfer
7
const getQuote = async (fromChain, toChain, fromToken, toToken, fromAmount, fromAddress) => {
8
const result = await axios.get(`${API_URL}/quote`, {
9
params: {
10
fromChain,
11
toChain,
12
fromToken,
13
toToken,
14
fromAmount,
15
fromAddress,
16
}
17
});
18
return result.data;
19
}
20
​
21
// Check the status of your transfer
22
const getStatus = async (bridge, fromChain, toChain, txHash) => {
23
const result = await axios.get(`${API_URL}/status`, {
24
params: {
25
bridge,
26
fromChain,
27
toChain,
28
txHash,
29
}
30
});
31
return result.data;
32
}
33
​
34
const fromChain = 'DAI';
35
const fromToken = 'USDC';
36
const toChain = 'POL';
37
const toToken = 'USDC';
38
const fromAmount = '1000000';
39
const fromAddress = YOUR_WALLET_ADDRESS;
40
​
41
// Set up your wallet
42
const provider = new ethers.providers.JsonRpcProvider('https://rpc.xdaichain.com/', 100);
43
const wallet = ethers.Wallet.fromMnemonic(YOUR_PERSONAL_MNEMONIC).connect(
44
provider
45
);
46
​
47
const run = async () => {
48
const quote = await getQuote(fromChain, toChain, fromToken, toToken, fromAmount, fromAddress);
49
const tx = await wallet.sendTransaction(quote.transactionRequest);
50
​
51
await tx.wait();
52
​
53
// Only needed for cross chain transfers
54
if (fromChain !== toChain) {
55
let result;
56
do {
57
result = await getStatus(quote.tool, fromChain, toChain, tx.hash);
58
} while (result.status !== 'DONE' && result.status !== 'FAILED')
59
}
60
}
61
​
62
run().then(() => {
63
console.log('DONE!')
64
});
Copied!

Checking and setting the Allowance

Before any transaction can be sent, it must be made sure that the user allowed to send the requested amount from his wallet.
This can be achieve like this:
1
const { Contract } = require('ethers');
2
​
3
const ERC20_ABI = [
4
{
5
"name": "approve",
6
"inputs": [
7
{
8
"internalType": "address",
9
"name": "spender",
10
"type": "address"
11
},
12
{
13
"internalType": "uint256",
14
"name": "amount",
15
"type": "uint256"
16
}
17
],
18
"outputs": [
19
{
20
"internalType": "bool",
21
"name": "",
22
"type": "bool"
23
}
24
],
25
"stateMutability": "nonpayable",
26
"type": "function"
27
},
28
{
29
"name": "allowance",
30
"inputs": [
31
{
32
"internalType": "address",
33
"name": "owner",
34
"type": "address"
35
},
36
{
37
"internalType": "address",
38
"name": "spender",
39
"type": "address"
40
}
41
],
42
"outputs": [
43
{
44
"internalType": "uint256",
45
"name": "",
46
"type": "uint256"
47
}
48
],
49
"stateMutability": "view",
50
"type": "function"
51
}
52
];
53
​
54
// Get the current the allowance and update if needed
55
const checkAndSetAllowance = async (wallet, tokenAddress, approvalAddress, amount) => {
56
// Transactions with the native token don't need approval
57
if (tokenAddress === ethers.constants.AddressZero) {
58
return
59
}
60
​
61
const erc20 = new Contract(tokenAddress, ERC20_ABI, wallet);
62
const allowance = await erc20.allowance(await wallet.getAddress(), approvalAddress);
63
​
64
if (allowance.lt(amount)) {
65
const approveTx = await erc20.approve(approvalAddress, amount);
66
await approveTx.wait();
67
}
68
}
69
​
70
await checkAndSetAllowance(wallet, quote.action.fromToken.address, quote.estimate.approvalAddress, fromAmount);
Copied!