Transfer from EVM
In this example, we will demonstrate how to transfer USDC
from Ethereum
to Polygon
using the
Stargate API GET ERC20 Quotes endpoint.
Execution Flow
Get Quotes
To initiate the transfer process, you’ll need to request the Stargate API with your operation parameters.
curl -X GET "https://stargate.finance/api/v1/quotes?srcToken=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48&dstToken=0x3c499c542cef5e3811e1192ce70d8cc03d5c3359&srcAddress=0x0C0d18aa99B02946C70EAC6d47b8009b993c9BfF&dstAddress=0x0C0d18aa99B02946C70EAC6d47b8009b993c9BfF&srcChainKey=ethereum&dstChainKey=polygon&srcAmount=10000000&dstAmountMin=9000000"
Transaction Construction
The API returns a comprehensive set of available routes
, each containing sequentially ordered
transaction steps
that must be executed in the specified sequence to successfully complete the
token transfer operation.
For this example, we will utilize the stargate/v2/taxi
route as it offers faster transaction
finality.
const response = {
"quotes":[
{
"route":"stargate/v2/taxi",
"srcAddress":"0x0C0d18aa99B02946C70EAC6d47b8009b993c9BfF",
"dstAddress":"0x0C0d18aa99B02946C70EAC6d47b8009b993c9BfF",
"srcChainKey":"ethereum",
"dstChainKey":"polygon",
"error":null,
"srcToken":"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"dstToken":"0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
"srcAmount":"10000000",
"srcAmountMax":"110838431564",
"dstAmount":"9999749",
"dstAmountMin":"9000000",
"duration":{
"estimated":180.828
},
"allowance":"0",
"dstNativeAmount":"0",
"fees":[
{
"token":"0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
"amount":"24887844265667",
"type":"message",
"chainKey":"ethereum"
}
],
"steps":[
{
"type":"approve",
"sender":"0x0C0d18aa99B02946C70EAC6d47b8009b993c9BfF",
"chainKey":"ethereum",
"transaction":{
"data":"0x095ea7b3000000000000000000000000c026395860db2d07ee33e05fe50ed7bd583189c70000000000000000000000000000000000000000000000000000000000989680",
"to":"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"from":"0x0C0d18aa99B02946C70EAC6d47b8009b993c9BfF"
}
},
{
"type":"bridge",
"chainKey":"ethereum",
"sender":"0x0C0d18aa99B02946C70EAC6d47b8009b993c9BfF",
"transaction":{
"data":"0xc7c7f5b30000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000016a2a71ddec300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0d18aa99b02946c70eac6d47b8009b993c9bff000000000000000000000000000000000000000000000000000000000000759d0000000000000000000000000c0d18aa99b02946c70eac6d47b8009b993c9bff0000000000000000000000000000000000000000000000000000000000989680000000000000000000000000000000000000000000000000000000000089544000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"to":"0xc026395860Db2d07ee33e05fE50ed7bD583189C7",
"value":"24887844265667",
"from":"0x0C0d18aa99B02946C70EAC6d47b8009b993c9BfF"
}
}
]
},
{
"route":"stargate/v2/bus",
...
}
]
}
// Access route data from API response
const route = response.quotes[0]; // First route (stargate/v2/taxi)
// Access transaction steps
const approveStep = route.steps[0]; // First step (approve)
const bridgeStep = route.steps[1]; // Second step (bridge)
// Access transaction data
const approveTransaction = approveStep.transaction;
const bridgeTransaction = bridgeStep.transaction;
// Access fee information
const fees = route.fees[0];
const approveTransaction = {
to: approveStep.transaction.to,
value: route.srcAmount
data: approveStep.transaction.data,
nonce: // user nonce
gasLimit: // user gas limit
gasPrice: // user gas price
from: approveStep.sender
};
const bridgeTransaction = {
to: bridgeStep.transaction.to,
value: route.srcAmount
data: bridgeStep.transaction.data,
nonce: // user nonce
gasLimit: // user gas limit
gasPrice: // user gas price
from: bridgeStep.sender
};
Client-side Signing
Now you have to sign the raw transaction
using your preferred wallet or key management system.
// Create and sign the transaction
const tx = Transaction.fromTxData(
{
to: approveTransaction.to,
value: approveTransaction.value,
data: approveTransaction.data,
nonce: approveTransaction.nonce,
gasLimit: approveTransaction.gasLimit,
gasPrice: approveTransaction.gasPrice,
},
...
);
// Sign the transaction
const signedTx = tx.sign(privateKeyBuffer);
// Do the same for the bridge transaction
...
Network Submission
Signed transaction is broadcast to the source
blockchain network.
// Get the serialized signed transaction
const serializedTx = '0x' + signedTx.serialize().toString('hex');
// Send the signed transaction
try {
const receipt = await web3.eth.sendSignedTransaction(serializedTx);
console.log('Transaction successful with hash:', receipt.transactionHash);
return receipt;
} catch (error) {
console.error('Error sending transaction:', error);
throw error;
}
// Do the same for the bridge transaction
...
For production implementations, we recommend implementing proper error handling and transaction monitoring to ensure a seamless cross-chain experience.
After successfully executing all transactions from the steps
array, the cross-chain ERC-20 token
transfer process is complete.