Skip to main content

Destination Zaps

Introduction

  • Destination Actions enable developers to perform arbitrary transactions on the destination chain in addition to bridging tokens.
  • Developers can pass the calldata on the source chain that will be executed post-bridging on the destination chain. You’ll also need to estimate and pass the gasLimit of this destination transaction.
  • Accordingly, users would pay additional gas fees on the source chain which will cover the destination fees of the relayer.
  • This calldata will be executed on the destination chain in the same transaction in which the bridged funds are transferred.
  • Destination Actions has limited bridge support to begin with and will support more bridges/tokens in upcoming updates

Chain Support

info

The destination action integration flow mostly follows Single Transaction Bridging & Multi Transaction Bridging flows. The only changes are in the Quote Step and Build-Tx Step. In case you haven’t checked out either guides, please check it first.

Passing calldata to API

1. Generating calldata

  • You need to build the bytes calldata to be executed on the destination chain & estimate the gasLimit of executing this transaction before-hand

  • Considerations for the targetContract

    • Currently, destination actions only supports ERC20 tokens as the receiving token. Support for native assets will be added in upcoming releases.
    • The receiver contract increases the token allowance of bridged ERC20 by amountLD (bridged output amount) for targetContract
    • The function being executed on targetContract must have a transferFrom function which transfers the bridged ERC20 token from the receiverContract to targetContract
Click to see an example

Depositing sUSD into Lyra on Optimism

  • calldata for calling initiateDeposit() function on Lyra contracts post-bridging
import { ethers } from "ethers";

// Calldata for depositing 1000 sUSD with benificiary 0x58Daefe2A4224966535dfbBca1f3c90D09919c2D

const lyraContractAddress = "0x5Db73886c4730dBF3C562ebf8044E19E8C93843e";

async function generateLyraData() {
const provider = new ethers.providers.JsonRpcProvider(
"https://mainnet.optimism.io"
);
const contract = new ethers.Contract(lyraContractAddress, lyraAbi, provider);

const beneficiary = "0x58Daefe2A4224966535dfbBca1f3c90D09919c2D";
const amount = "1000000000000000000000";
const txData = await contract.populateTransaction.initiateDeposit(
beneficiary,
amount
);
return txData;
}

// Output
// 0xec55234600000000000000000000000058daefe2a4224966535dfbbca1f3c90d09919c2d00000000000000000000000000000000000000000000003635c9adc5dea00000

// Estimated gasLimit
// ~ 285K

2. Fetching Bridging Quote with destination calldata

  • You can request a bridging quote as usual with selected fromChainId, toChainId, fromTokenAddress, toTokenAddress. More on fetching quotes here.

  • When calling the Quote endpoint, you need to pass 4 additional params for executing destination transactions

    ParamDescription
    recipientAddress of targetContract on destination chain where calldata will be executed
    destinationPayloadcalldata to be executed on destination chain
    destinationGasLimitgasLimit required to post-bridging tx + 30k extra gas
    singleTxOnlyMust be set to true
  • IMPORTANT

    Please add 30,000 gas units to the estimated destinationGasLimit. This covers the cost of the receiver contract on the destination chain. For e.g if the estimated gasLimit to execute your destination tx is 570K__, add destinationGasLimit as 600K__.

Example Request

Example Quote Request for bridging 1000 sUSD from Ethereum to Optimism & depositing into Lyra

https://api.socket.tech/v2/quote?fromChainId=1&fromTokenAddress=0x57Ab1ec28D129707052df4dF418D58a2D46d5f51&toChainId=10&toTokenAddress=0x8c6f28f2F1A3C87F0f938b96d27520d9751ec8d9&fromAmount=1000000000000000000000&userAddress=0x58Daefe2A4224966535dfbBca1f3c90D09919c2D&recipient=0x5Db73886c4730dBF3C562ebf8044E19E8C93843e&uniqueRoutesPerBridge=true&includeBridges=&sort=output&singleTxOnly=true&destinationPayload=0xec55234600000000000000000000000058daefe2a4224966535dfbbca1f3c90d09919c2d00000000000000000000000000000000000000000000003635c9adc5dea00000&destinationGasLimit=310000

Example Response
    {
"success": true,
"result": {
"routes": [
{
// Route Object to be used
}
],
"destinationCallData": {
"destinationPayload": "0xec55234600000000000000000000000058daefe2a4224966535dfbbca1f3c90d09919c2d00000000000000000000000000000000000000000000003635c9adc5dea00000",
"destinationGasLimit": "310000"
}, // DestinationCallData to be used
...
}
}

3. Building transaction for source chain

(This guide uses the POST /build-tx endpoint)

  • The selected route’s object and destinationCallData returned in the quote response can be used to build the transaction to be executed on the source chain
  • More details on the POST /build-tx endpoint

REQUEST BODY

{
"route": {
// Insert selected route object here
},
"destinationCallData": {
// Insert selected destinationCallData from the Quote response here
}
}
Example Request
  • Using the route returned in the Quote Example above

REQUEST BODY

{
"route": {
"routeId": "49de2227-346f-4234-96c8-f892e4f9a46f",
"isOnlySwapRoute": false,
"fromAmount": "1000000000000000000000",
"toAmount": "999780563000000000000",
"usedBridgeNames": ["stargate"],
"minimumGasBalances": {
"1": "30000000000000000",
"10": "1800000000000000"
},
"chainGasBalances": {
"1": {
"minGasBalance": "30000000000000000",
"hasGasBalance": false
},
"10": {
"minGasBalance": "1800000000000000",
"hasGasBalance": false
}
},
"totalUserTx": 1,
"sender": "0x58Daefe2A4224966535dfbBca1f3c90D09919c2D",
"recipient": "0x5Db73886c4730dBF3C562ebf8044E19E8C93843e",
"totalGasFeesInUsd": 21.0896694041751,
"receivedValueInUsd": 979.680670595825,
"userTxs": [
{
"userTxType": "fund-movr",
"txType": "eth_sendTransaction",
"chainId": 1,
"toAmount": "999780563000000000000",
"toAsset": {
"chainId": 10,
"address": "0x8c6f28f2f1a3c87f0f938b96d27520d9751ec8d9",
"symbol": "SUSD",
"name": "Synthetic sUSD",
"decimals": 18,
"icon": "https://assets.coingecko.com/coins/images/5013/small/sUSD.png?1616150765",
"logoURI": "https://assets.coingecko.com/coins/images/5013/small/sUSD.png?1616150765",
"chainAgnosticId": null
},
"stepCount": 1,
"routePath": "0-27",
"sender": "0x58Daefe2A4224966535dfbBca1f3c90D09919c2D",
"approvalData": {
"minimumApprovalAmount": "1000000000000000000000",
"approvalTokenAddress": "0x57ab1ec28d129707052df4df418d58a2d46d5f51",
"allowanceTarget": "0x6cf8d2bf45fe99e369db145faf6fb606a50b27f3",
"owner": "0x58Daefe2A4224966535dfbBca1f3c90D09919c2D"
},
"steps": [
{
"type": "bridge",
"protocol": {
"name": "stargate",
"displayName": "Stargate",
"icon": "https://s2.coinmarketcap.com/static/img/coins/128x128/18934.png",
"securityScore": 3,
"robustnessScore": 3
},
"bridgeSlippage": 0.5,
"fromChainId": 1,
"fromAsset": {
"chainId": 1,
"address": "0x57ab1ec28d129707052df4df418d58a2d46d5f51",
"symbol": "SUSD",
"name": "Synth sUSD",
"decimals": 18,
"icon": "https://assets.coingecko.com/coins/images/5013/small/sUSD.png?1616150765",
"logoURI": "https://assets.coingecko.com/coins/images/5013/small/sUSD.png?1616150765",
"chainAgnosticId": null
},
"fromAmount": "1000000000000000000000",
"toChainId": 10,
"toAsset": {
"chainId": 10,
"address": "0x8c6f28f2f1a3c87f0f938b96d27520d9751ec8d9",
"symbol": "SUSD",
"name": "Synthetic sUSD",
"decimals": 18,
"icon": "https://assets.coingecko.com/coins/images/5013/small/sUSD.png?1616150765",
"logoURI": "https://assets.coingecko.com/coins/images/5013/small/sUSD.png?1616150765",
"chainAgnosticId": null
},
"minAmountOut": "994781660000000000000",
"toAmount": "999780563000000000000",
"protocolFees": {
"asset": {
"chainId": 1,
"address": "0x57ab1ec28d129707052df4df418d58a2d46d5f51",
"symbol": "SUSD",
"name": "Synth sUSD",
"decimals": 18,
"icon": "https://assets.coingecko.com/coins/images/5013/small/sUSD.png?1616150765",
"logoURI": "https://assets.coingecko.com/coins/images/5013/small/sUSD.png?1616150765",
"chainAgnosticId": null
},
"feesInUsd": 0,
"amount": "219437000000000000"
},
"gasFees": {
"gasAmount": "12607331020364000",
"asset": {
"chainId": 1,
"address": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"symbol": "ETH",
"name": "Ethereum",
"decimals": 18,
"icon": "https://maticnetwork.github.io/polygon-token-assets/assets/eth.svg",
"logoURI": "https://maticnetwork.github.io/polygon-token-assets/assets/eth.svg",
"chainAgnosticId": null
},
"gasLimit": 420000,
"feesInUsd": 21.0896694041751
},
"serviceTime": 60,
"maxServiceTime": 7200
}
],
"gasFees": {
"gasAmount": "12607331020364000",
"feesInUsd": 21.0896694041751,
"asset": {
"chainId": 1,
"address": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"symbol": "ETH",
"name": "Ethereum",
"decimals": 18,
"icon": "https://maticnetwork.github.io/polygon-token-assets/assets/eth.svg",
"logoURI": "https://maticnetwork.github.io/polygon-token-assets/assets/eth.svg",
"chainAgnosticId": null
},
"gasLimit": 420000
},
"serviceTime": 60,
"recipient": "0x5Db73886c4730dBF3C562ebf8044E19E8C93843e",
"maxServiceTime": 7200,
"bridgeSlippage": 0.5,
"userTxIndex": 0
}
],
"serviceTime": 60,
"maxServiceTime": 7200,
"integratorFee": {
"amount": "0",
"asset": {
"chainId": 1,
"address": "0x57ab1ec28d129707052df4df418d58a2d46d5f51",
"symbol": "SUSD",
"name": "Synth sUSD",
"decimals": 18,
"icon": "https://assets.coingecko.com/coins/images/5013/small/sUSD.png?1616150765",
"logoURI": "https://assets.coingecko.com/coins/images/5013/small/sUSD.png?1616150765",
"chainAgnosticId": null
}
}
},
"destinationCallData": {
"destinationPayload": "0xec55234600000000000000000000000058daefe2a4224966535dfbbca1f3c90d09919c2d00000000000000000000000000000000000000000000003635c9adc5dea00000",
"destinationGasLimit": "310000"
}
}
Example Response
{
"success": true,
"result": {
"userTxType": "fund-movr",
"txType": "eth_sendTransaction",
"txData": "0xa44bbb150000000000000000000000000000000000000000000000000000000000000020000000000000000000000000ddc3a2bc1d6252d09a82814269d602d84ca3e7ae000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000003635c9adc5dea0000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000057ab1ec28d129707052df4df418d58a2d46d5f5100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b00000000000000000000000000000000000000000000000000025381a1c4f9c100000000000000000000000057ab1ec28d129707052df4df418d58a2d46d5f51000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000003b4b29dc000000000000000000000000000000000000000000000000000000000000006f00000000000000000000000058daefe2a4224966535dfbbca1f3c90d09919c2d000000000000000000000000000000000000000000000000000000000004baf000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000005db73886c4730dbf3c562ebf8044e19e8c93843e00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000044ec55234600000000000000000000000058daefe2a4224966535dfbbca1f3c90d09919c2d00000000000000000000000000000000000000000000003635c9adc5dea0000000000000000000000000000000000000000000000000000000000000",
"txTarget": "0xc30141B657f4216252dc59Af2e7CdB9D8792e1B0",
"chainId": 1,
"userTxIndex": 0,
"value": "0x025381a1c4f9c1",
"approvalData": {
"minimumApprovalAmount": "1000000000000000000000",
"approvalTokenAddress": "0x57ab1ec28d129707052df4df418d58a2d46d5f51",
"allowanceTarget": "0x6cf8d2bf45fe99e369db145faf6fb606a50b27f3",
"owner": "0x58Daefe2A4224966535dfbBca1f3c90D09919c2D"
}
}
}

If you’re using the GET /build-tx instead.

If you’re following the Single Transaction Bridging guide & using the GET Build-Tx endpoint

  • Check out the GET build-tx for more details

  • In addition to passing all the request params, you’ll also need to pass the recipient,destinationPayload and destinationGasLimit returned in the Quote Response in the destinationCallData object.

  • Example Request

    https://api.socket.tech/v2/build-tx?sender=0x58Daefe2A4224966535dfbBca1f3c90D09919c2D&recipient=0x5Db73886c4730dBF3C562ebf8044E19E8C93843e&routePath=0-27&fromChainId=1&toChainId=10&fromTokenAddress=0x57ab1ec28d129707052df4df418d58a2d46d5f51&toTokenAddress=0x8c6f28f2f1a3c87f0f938b96d27520d9751ec8d9&fromAmount=1000000000000000000000&toAmount=999893238000000000000&bridgeInputTokenAddress=0x57ab1ec28d129707052df4df418d58a2d46d5f51&destinationPayload=0xec55234600000000000000000000000058daefe2a4224966535dfbbca1f3c90d09919c2d00000000000000000000000000000000000000000000003635c9adc5dea00000&destinationGasLimit=310000

If you’re using the POST /route/start instead.

If you’re following the Multi Transaction Bridging guide & using the /Route endpoints

  • When starting the route, you need to add the desintinationCallData object, same as the POST /build-tx endpoint
  • More on the /route/start endpoint
{
"route": {
// Insert selected route object here
},
"destinationCallData": {
// Insert selected destinationCallData from the Quote response here
}
}

4. In-flight & Post Bridging

Glossary

TermDescription
PayloadCalldata to be executed on the destination chain.
Receiver ContractBungee's contract on the destination chain that receives tokens and calls the target contract.
Target ContractThe contract on the destination chain which is being called in the calldata.

Debugging failed transactions

In case the tokens are bridged and sent to the Receiver Contract but the destination calldata isn’t executed, check if there’s a CachedSwapSaved event emitted. This generally means the calldata was faulty and couldn’t be executed or the gasLimit was insufficient to cover the cost of the transaction. Please reach out to us if your transaction fails and we can help debug.