Perform an Asset Swap
Swapping assets locally or across different chains.
Warning
This is an advanced guide. Make sure you've gone through the previous guides to understand the basics of the API.
The /routes
endpoint (callable via the getRoutes
method from our SDK) lists different routes for a proposed swap (local or cross-chain).
Code Example
Prerequisites
- Use the following link as an example of how to programmatically use the
/routes
endpoint: Example Code.- Before running the script, ensure your development environment is set up correctly by following this guide: Set Up the Development Environment.
This script sets up a configuration for a route (routeParameters
object) that specifies the swap details, including the source and destination chains, source and destination tokens, maximum slippage, and recipients.
To run the script, use the command:
npx ts-node src/main/scripts/do-swap.ts
This script will create, sign, and broadcast transactions. You can inspect this functionality in the sign-and-broadcast-transaction.ts
script.
Steps for a Cross-Chain Transfer
Step 1. Get Routes
First, get possible routes for your transfer using the getRoutes
method. This defines token information and route parameters. For example, for stablecoin token transfers between L2s to swap DAI on Optimism for DAI on Polygon. To swap USDC, simply use tokens["USDC"]
in the fromToken
, fromAmount
, and toToken
fields of the routeParameters
constant. The following snippet illustrates this process:
const tokenUSDC = {
// USDC on OP
fromToken: "0x0b2c639c533813f4aa9d7837caf62653d097ff85",
// USDC on Polygon
toToken: "0x3c499c542cef5e3811e1192ce70d8cc03d5c3359",
// 1 USDC, 6 decimals
fromAmount: "1000000",
};
const tokenDAI = {
fromToken: "0xda10009cbd5d07dd0cecc66161fc93d7c9000da1",
toToken: "0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063",
// 1 DAI, 18 decimals
fromAmount: "1000000000000000000",
};
const tokens = {
USDC: tokenUSDC,
DAI: tokenDAI,
};
const routeParameters: GetRoutesRequest = {
fromChain: "eip155:10", // Optimism
fromToken: tokens["DAI"].fromToken,
fromAmount: tokens["DAI"].fromAmount,
toChain: "eip155:137", // Polygon
toToken: tokens["DAI"].toToken,
fromAddress: optimismWallet.address,
toAddress: polygonWallet.address,
slippage: 0.1,
};
Alternatively, you can obtain routes via cURL:
curl -X GET 'https://svc.blockdaemon.com/defi/exchange/routes?fromChain=eip155:10&fromAmount=100000000000000000&fromToken=0xda10009cbd5d07dd0cecc66161fc93d7c9000da1&toChain=eip155:137&toToken=0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063&fromAddress=0xf271AAFC62634e6Dc9A276ac0f6145C4fDbE2Ced&toAddress=0xf271AAFC62634e6Dc9A276ac0f6145C4fDbE2Ced&slippage=0.1' \
-H 'x-api-key: YOUR_API_KEY'
The result is a routes object and should look similar to the following:
{
"routes": [
{
"fromAmount": "100000000000000000",
"fromAmountUSD": "0.1002621696",
"fromToken": {
"address": "0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1",
"chainID": "10",
"chainType": "evm",
"decimals": 18,
"name": "Dai Stablecoin",
"symbol": "DAI"
},
"gasCostUSD": "0.003103509152",
"slippage": 0.1,
"steps": [
{
"action": {
"fromAddress": "0xf271AAFC62634e6Dc9A276ac0f6145C4fDbE2Ced",
"fromAmount": "100000000000000000",
"fromToken": {
"address": "0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1",
"chainID": "10",
"chainType": "evm",
"decimals": 18,
"name": "Dai Stablecoin",
"symbol": "DAI"
},
"slippage": 0.1,
"toAddress": "0xf271AAFC62634e6Dc9A276ac0f6145C4fDbE2Ced",
"toToken": {
"address": "0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063",
"chainID": "137",
"chainType": "evm",
"decimals": 18,
"name": "Dai Stablecoin",
"symbol": "DAI"
}
},
"estimate": {
"approvalAddress": "0xB0D502E938ed5f4df2E681fE6E419ff29631d62b",
"executionDuration": 1548,
"gasCosts": [
{
"amount": "909198000000",
"amountUSD": "0.003103509152",
"estimate": "909198000000",
"limit": "450000",
"price": "2020440",
"token": {
"address": "0x0000000000000000000000000000000000000000",
"chainID": "10",
"chainType": "evm",
"decimals": 18,
"name": "Ether",
"symbol": "ETH"
},
"type": "SEND"
}
],
"integrationDetails": {
"key": "stargate",
"name": "Stargate",
"type": "bridge"
},
"toAmount": "99910000000000000000000000000"
},
"type": "cross"
}
],
"tags": ["stargate"],
"toAmount": "99910000000000000000000000000",
"toAmountMin": "999000000000000000",
"toAmountUSD": "0.1002621696",
"toToken": {
"address": "0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063",
"chainID": "137",
"chainType": "evm",
"decimals": 18,
"name": "Dai Stablecoin",
"symbol": "DAI"
},
"tool": "stargate"
}
]
}
Step 2. Select a Route
Now, choose a route. For example, let's choose the first route available.
Before signing and broadcasting the transaction, authorize the bridge to use your DAI tokens. You can send an approval transaction using the Blocdaemon’s Accounts API.
Step 3. Get Approvals
You must authorize the route provider to use your tokens to perform a cross-chain swap. We recommend that you authorize only the required funds for that specific transaction.
Ensure you have received the approvals to interact with the exchange/bridge. You can also check these approvals after choosing a specific route approval address, which can be found in the estimate field for the selected route.
This is done programmatically in the following excerpt:
const approvalTxHash = await handleApproval(
selectedRoute,
routeParameters,
accountAPI,
optimismWallet,
OPTIMISM_RPC,
logger,
);
await checkTransactionStatus(
statusAPI,
routeParameters.fromChain,
approvalTxHash.toString(),
);
4. Sign and Broadcast
Now, let's use the utility functions provided in the examples to sign and broadcast the transaction found in the routesTransactionRequest
field.
let txPayload = selectedRoute.transactionRequest.data;
[...]
const broadcastResult = await signTxObjectAndBroadcast(
txPayload,
optimismWallet.privateKey,
OPTIMISM_RPC,
);
Under the hood, we sign and broadcast a transaction object to the source chain network. The transaction is transmitted to the source blockchain and processed by the route providers. The script logs useful information about the transaction broadcast process:
if (broadcastResult) {
logger.info("Successfully broadcast signed data to Optimism");
logger.debug("Broadcast result:", broadcastResult);
logger.info("Transaction hash:", broadcastResult.transactionHash);
logger.info(
"Check transaction at: https://optimistic.etherscan.io/tx/" +
broadcastResult.transactionHash,
);
5. Get the Transaction Status
To check cross-chain transaction status, monitor both source chain transactions and activities on the target chain. For this, you can use the /status
endpoint
await checkTransactionStatus(
statusAPI,
routeParameters.fromChain,
broadcastResult.transactionHash.toString(),
);
Under the hood, this function makes an HTTP request against the DEFI status API and retries until the status of the transaction is erroneous or finalized:
let approvalStatus: StatusResponse = {
status: StatusEnum.Pending,
};
while (approvalStatus.status !== StatusEnum.Done) {
approvalStatus = await statusAPI.getStatus({
fromChain: fromChain,
toChain: fromChain,
transactionID: transactionHash,
});
if (
isBlockdaemonApiError(approvalStatus) ||
approvalStatus.status === StatusEnum.NotFound ||
approvalStatus.status === StatusEnum.NeedGas
) {
logger.error(JSON.stringify(approvalStatus, null, 2));
throw new Error(
`Failed to get approval status: ${approvalStatus.status}`,
);
}
logger.info(`Current approval status: ${approvalStatus.status}`);
// Sleep for 10 seconds before next check
await new Promise((resolve) => setTimeout(resolve, 10000));
}
This process ensures that the transaction moving funds across blockchains was finalized successfully or that the end-user is informed if an error occurred.
Info:
For more information, refer to Get Transaction Status endpoint.
👋 Need Help?
Contact us through email or our support page for any issues, bugs, or assistance you may need.
Updated about 1 month ago