Bridge

The Across /swap/approval API is the entry point for both crosschain swaps and pure bridging. This allows developers to use the same Swap API concepts and build instant bridging flows.

When using /swap/approval, the depositor must first grant allowance to the Across protocol’s contract for the input token. The endpoint handles the setup required for both bridging and swapping, returning all the information needed to proceed safely.

The response includes:

  • Allowance state: current and required allowance values.

  • Balance state: current and expected balance after transfer.

  • Executable approval transaction(s): calldata to set the required allowance if insufficient.

  • Executable bridging transaction: ready-to-submit transaction for a bridge (same token across chains) flow.

  • Quote details: including input/output tokens, expected amount, and fee breakdown.

By abstracting both swap logic and bridge-only flows into the same endpoint, the Swap API allows developers to cover the full spectrum of crosschain token transfers without needing to stitch together separate services.


Bridge Flow

1

Fetch Chains and Token

Fetch all the available chains and tokens using GET /swap/chains and GET /swap/tokens and select your tradeType , originChain , destinationChain , inputToken and outputToken

2

Execute Crosschan Swap

Now that we have crosschain intent filled out, make sure you define the amount of inputToken you want to use here. Call the GET /swap/approval endpoint. This endpoint will return a ready transaction and you just need to sign and execute the transaction using your wallet.

Now let's dive deeper and code the whole flow out!


Basic Execution

Let us now focus on building a bridge transaction with the following parameters:

  1. tradeType : Defines the type of trade for eg - exactInput.

  2. amount : Specifies amount of inputToken in the smallest unit (wei for ETH or 6 decimals for USDC).

  3. inputToken : Address of the token being bridged.

  4. originChainId : Chain ID of the source/origin chain.

  5. outputToken : Address of the token to be received after the bridge transaction is complete.

  6. destinationChainId : Chain ID of the destination chain where the output token will be delivered.

  7. depositor : The address of the sender (usually the wallet initiating the swap).

In this specific example, we will be bridging 10 USDC on Optimism to USDC on Arbitrum.

Read the Complete Swap API Reference Here

Run the following script to conduct the crosschain swap:

import { createWalletClient, http, parseUnits } from 'viem'
import { privateKeyToAccount } from 'viem/accounts';
import { optimism, arbitrum } from 'viem/chains'
import axios from 'axios'
import dotenv from 'dotenv'

dotenv.config()

async function acrossSwapApproval() {
  const PRIVATE_KEY = process.env.PRIVATE_KEY


  const account = privateKeyToAccount(PRIVATE_KEY)
  const client = createWalletClient({
    account,
    chain: optimism,
    transport: http()
  })

  const { data } = await axios.get('https://app.across.to/api/swap/approval', {
    params: {
      tradeType: 'exactInput',
      amount: parseUnits('10',6).toString(),
      inputToken: '0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85', // USDC on Optimism
      originChainId: 10,
      outputToken: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831', // USDC on Arbitrum
      destinationChainId: 42161,
      depositor: account.address,
    }
  })

  // Handle token approvals if required
  if (data.approvalTxns) {
    for (const approvalTxn of data.approvalTxns) {
      const tx = await client.sendTransaction({
        to: approvalTxn.to,
        data: approvalTxn.data,
      })
      console.log('Approval tx hash:', tx)
    }
  }

  // Execute swap transaction
  const tx = await client.sendTransaction({
    to: data.swapTx.to,
    data: data.swapTx.data,
    value: data.swapTx.value ? BigInt(data.swapTx.value) : undefined,
  })

  console.log('Crosschain swap tx hash:', tx)
}

acrossSwapApproval()

Upon successful execution of the /swap/approval endpoint, the return data should be something like this:

{
    "crossSwapType": "bridgeableToBridgeable",
    "amountType": "exactInput",
    "checks": {
        "allowance": {
            "token": "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
            "spender": "0x6f26Bf09B1C792e3228e5467807a900A503c0281",
            "actual": "115792089237316195423570985008687907853269984665640564039457584007913092639935",
            "expected": "10000000"
        },
        "balance": {
            "token": "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
            "actual": "169942",
            "expected": "10000000"
        }
    },
    "steps": {
        "bridge": {
            "inputAmount": "10000000",
            "outputAmount": "9989218",
            "tokenIn": {
                "decimals": 6,
                "symbol": "USDC",
                "address": "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
                "name": "USD Coin",
                "chainId": 10
            },
            "tokenOut": {
                "decimals": 6,
                "symbol": "USDC",
                "address": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
                "name": "USD Coin",
                "chainId": 42161
            },
            "fees": {
                "totalRelay": {
                    "pct": "1078297594970015",
                    "total": "10782"
                },
                "relayerCapital": {
                    "pct": "100000000000000",
                    "total": "1000"
                },
                "relayerGas": {
                    "pct": "939500000000000",
                    "total": "9395"
                },
                "lp": {
                    "pct": "38797594970015",
                    "total": "387"
                }
            }
        }
    },
    "inputToken": {
        "decimals": 6,
        "symbol": "USDC",
        "address": "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
        "name": "USD Coin",
        "chainId": 10
    },
    "outputToken": {
        "decimals": 6,
        "symbol": "USDC",
        "address": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
        "name": "USD Coin",
        "chainId": 42161
    },
    "refundToken": {
        "decimals": 6,
        "symbol": "USDC",
        "address": "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
        "name": "USD Coin",
        "chainId": 10
    },
    "fees": {
        "total": {
            "amount": "10782",
            "amountUsd": "0.010779994548000715",
            "pct": "1078200000000072",
            "token": {
                "decimals": 6,
                "symbol": "USDC",
                "address": "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
                "name": "USD Coin",
                "chainId": 10
            }
        },
        "originGas": {
            "amount": "0",
            "amountUsd": "0.0",
            "token": {
                "chainId": 10,
                "address": "0x0000000000000000000000000000000000000000",
                "decimals": 18,
                "symbol": "ETH"
            }
        },
        "destinationGas": {
            "amount": "2051474962763",
            "amountUsd": "0.00939325253",
            "pct": "939500000000000",
            "token": {
                "chainId": 42161,
                "address": "0x0000000000000000000000000000000000000000",
                "decimals": 18,
                "symbol": "ETH"
            }
        },
        "relayerCapital": {
            "amount": "1000",
            "amountUsd": "0.000999814",
            "pct": "100000000000000",
            "token": {
                "decimals": 6,
                "symbol": "USDC",
                "address": "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
                "name": "USD Coin",
                "chainId": 10
            }
        },
        "lpFee": {
            "amount": "387",
            "amountUsd": "0.000386928018",
            "pct": "38700000000000",
            "token": {
                "decimals": 6,
                "symbol": "USDC",
                "address": "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
                "name": "USD Coin",
                "chainId": 10
            }
        },
        "relayerTotal": {
            "amount": "10782",
            "amountUsd": "0.010779994547999999",
            "pct": "1078200000000000",
            "token": {
                "decimals": 6,
                "symbol": "USDC",
                "address": "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
                "name": "USD Coin",
                "chainId": 10
            }
        },
        "app": {
            "amount": "0",
            "amountUsd": "0.0",
            "pct": "0",
            "token": {
                "decimals": 6,
                "symbol": "USDC",
                "address": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
                "name": "USD Coin",
                "chainId": 42161
            }
        }
    },
    "inputAmount": "10000000",
    "expectedOutputAmount": "9989218",
    "minOutputAmount": "9989218",
    "expectedFillTime": 3,
    "swapTx": {
        "simulationSuccess": false,
        "chainId": 10,
        "to": "0x6f26Bf09B1C792e3228e5467807a900A503c0281",
        "data": "0xad5425c6000000000000000000000000a4d353bbc130cbef1811...",
        "maxFeePerGas": "1003403",
        "maxPriorityFeePerGas": "1000000"
    },
    "id": "6mrxp-1756393011703-916d396aae3d"
}

With the above response from the /swap/approval endpoint, you can proceed to sign transaction on the wallet client.

For same-asset bridging, the Swap API will simply return a 400 error stating that the relayers donot have sufficient liquidity. This behavior is similar to /suggested-fees API but the Swap API will not return the maximum deposit limit here


Sample Routes using /swap/approval Endpoint

This section is aimed at displaying how some routes can be formed to help developers build bridge interfaces quickly.

1. Bridge USDC on Ethereum Mainnet to USDC on Arbitrum

import axios from 'axios'
import { parseUnits } from 'viem'

async function fetchSwapDetails() {
  const { data } = await axios.get('https://app.across.to/api/swap/approval', {
    params: {
      tradeType: 'minOutput',
      amount: parseUnits("10",6).toString(),
      inputToken: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 
      originChainId: 1,
      outputToken: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',
      destinationChainId: 42161,
      depositor: '<address-of-the-sender>'
    }
  })
 // console.log(data) [if needed]
  return data
}

Key Parameters:

  1. tradeType : Defines the type of trade for eg - minOutput.

  2. amount : Specifies amount of inputToken in the smalled unit (wei for ETH or 6 decimals for USDC).

  3. inputToken : Address of the token being bridged.

  4. originChainId : Chain ID of the origin chain.

  5. outputToken : Address of the token to be received after the bridge transaction completes.

  6. destinationChainId : Chain ID of the destination chain where the output token will be delivered.

  7. depositor : The address of the sender (usually the wallet initiating the swap).

Same parameters will be followed in all other examples in this section.

2. Bridge ETH from Ethereum Mainnet to ETH on Lens Chain

import axios from 'axios'
import { parseUnits } from 'viem'

async function fetchSwapDetails() {
  const { data } = await axios.get('https://app.across.to/api/swap/approval', {
    params: {
      tradeType: 'minOutput',
      amount: parseUnits("0.001",18).toString(),
      inputToken: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
      originChainId: 1,
      outputToken: '0xE5ecd226b3032910CEaa43ba92EE8232f8237553',
      destinationChainId: 232,
      depositor: '<address-of-the-sender>'
    }
  })
 // console.log(data) [if needed]
  return data
}

3. Bridge USDC on Optimism to USDC on Base

In case you face any errors or need support, please feel free to reach out to us.

import axios from 'axios'
import { parseUnits } from 'viem'

async function fetchSwapDetails() {
  const { data } = await axios.get('https://app.across.to/api/swap/approval', {
    params: {
      tradeType: 'minOutput',
      amount: parseUnits("1",6).toString(),
      inputToken: '0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85', 
      originChainId: 10,
      outputToken: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', 
      destinationChainId: 8453,
      depositor: '<address-of-the-depositor>'
    }
  })
 // console.log(data) [if needed]
  return data
}

Tracking Deposits

To track the lifecycle of a deposit you can use the GET /deposit/status endpoint with the following parameters:

  • originChainId: chainId where the deposit originated from. Use this in conjunction with the depositId parameter.

  • depositId: The deposit id that is emitted from the DepositV3 function call as a V3FundsDeposited event. Use this in conjunction with the originChainId parameter.

  • depositTxHash : The deposit transaction hash that is emitted from the DepositV3 function call as a V3FundsDeposited event. If you are using this, you do not need the above parameters.

The recommended solution for tracking all Across deposits originating from your integration, for a single user, is to store the user's depositId and originChainId or the depositTxHash from each transaction originating from your app, and then get the status of each via the above endpoint.

In case you face any errors or need support, please feel free to reach out to us.

Last updated