Skip to Content

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.

Quote Request
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.

Quote Response
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", ... } ] }
Transaction Construction
// 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.

Client-side Signing
// 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.

Network Submission
// 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 ...
đź’ˇ
Tip

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.


Further Reading
Last updated on