Lens Crosschain Swap Guide

This is a comprehensive walkthrough for developers looking to implement crosschain token swaps using the Across /swap/approval API on the Lens chain.

Across /swap/approval API provides a streamlined interface for developers to build crosschain swapping applications that easily fit in any development environment and tech stacks.

The ideal Across Crosschain Swap API approach involves setting an allowance and executing the transaction directly via the signer. This is a gasful flow.

Let's get started!


Understanding the /swap/approval Endpoint

In the /swap/approval endpoint crosschain swap flow, consumers of the API need to make sure that the depositor has granted sufficient allowance to the respective contract of the Across Protocol.

The API returns data that can be used to:

  • check current and expected allowance

  • check current and expected balance

  • executable approval transaction(s)

  • executable swap transaction

  • swap quote

API Endpoint

GET https://app.across.to/api/swap/approval

Basic Execution


Quickstart Code Snippets

import { createWalletClient, http, privateKeyToAccount, parseUnits } from 'viem'
import { optimism } from 'viem/chains'
import axios from 'axios'

async function acrossSwapApproval() {
  const PRIVATE_KEY = '0x...' as `0x${string}`
  const RPC_URL = 'https://rpc.lens.xyz'

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

  const { data } = await axios.get('https://app.across.to/api/swap/approval', {
    params: {
      tradeType: 'minOutput',
      amount: parseUnits('0.001',18).toString(),
      inputToken: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // ETH on Ethereum Mainnet
      originChainId: 1,
      outputToken: '0xE5ecd226b3032910CEaa43ba92EE8232f8237553', // WETH on Lens Chain
      destinationChainId: 232,
      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)
      await client.waitForTransactionReceipt({ 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('Cross-swap tx hash:', tx)
  await client.waitForTransactionReceipt({ hash: tx })
}

export default acrossSwapApproval

Important fields to note here are:

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

  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 swapped.

  4. originChainId : Chain ID of the source/origin chain (232 for Lens Chain mainnet).

  5. outputToken : Address of the token to be received after the swap.

  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).

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

{
  "checks": {
    "allowance": {
      "token": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
      "spender": "0x5c7BCd6E7De5423a257D81B442095A1a6ced35C5",
      "actual": "115792089237316195423570985008687907853269984665640564039457584007913129639935",
      "expected": "1065159719994"
    },
    "balance": {
      "token": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
      "actual": "0",
      "expected": "1065159719994"
    }
  },
  "steps": {
    "bridge": {
      "inputAmount": "1065159719994",
      "outputAmount": "940201830",
      "tokenIn": {
        "decimals": 18,
        "symbol": "ETH",
        "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
        "name": "Ether",
        "chainId": 1
      },
      "tokenOut": {
        "decimals": 18,
        "symbol": "ETH",
        "address": "0xE5ecd226b3032910CEaa43ba92EE8232f8237553",
        "name": "Ether",
        "chainId": 232
      },
      "fees": {
        "totalRelay": {
          "pct": "999117313760226216",
          "total": "1064219518164"
        },
        "relayerCapital": {
          "pct": "99999954936899",
          "total": "106515923"
        },
        "relayerGas": {
          "pct": "999017313805289317",
          "total": "1064113002241"
        },
        "lp": {
          "pct": "0",
          "total": "0"
        }
      }
    }
  },
  "refundToken": {
    "decimals": 18,
    "symbol": "WETH",
    "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
    "name": "Ether",
    "chainId": 1
  },
  "inputAmount": "1065159719994",
  "expectedOutputAmount": "940201830",
  "minOutputAmount": "940201830",
  "expectedFillTime": 8,
  "swapTx": {
    "simulationSuccess": false,
    "chainId": 1,
    "to": "0x5c7BCd6E7De5423a257D81B442095A1a6ced35C5",
    "data": "0x7b939232000000000000000000000000a4d353bbc130cbef1811f27ac70989f9d568ceab000000000000000000000000c5939f59b3c9662377dda53a08d5085b2d52b719000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000e5ecd226b3032910ceaa43ba92ee8232f8237553000000000000000000000000000000000000000000000000000000f800777c3a00000000000000000000000000000000000000000000000000000000380a576600000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000067f4f4530000000000000000000000000000000000000000000000000000000067f5494300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000c5939f59b3c9662377dda53a08d5085b2d52b719000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044ef8738d3000000000000000000000000e5ecd226b3032910ceaa43ba92ee8232f8237553000000000000000000000000a4d353bbc130cbef1811f27ac70989f9d568ceab00000000000000000000000000000000000000000000000000000000",
    "maxFeePerGas": "1213349849",
    "maxPriorityFeePerGas": "500000000"
  }
}

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


Lens Use Cases using /swap/approval Endpoint

1. Bridge ETH on 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', // ETH on Ethereum
      originChainId: 1,
      outputToken: '0xE5ecd226b3032910CEaa43ba92EE8232f8237553', // WETH on Lens Chain
      destinationChainId: 232,
      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 swapped.

  4. originChainId : Chain ID of the source/origin chain (232 for lens chain mainnet).

  5. outputToken : Address of the token to be received after the swap.

  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).

2. Bridge GHO from Ethereum Mainnet to GHO 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: '0x1ff1dC3cB9eeDbC6Eb2d99C03b30A05cA625fB5a', // ETH on Ethereum
      originChainId: 1,
      outputToken: '0x6bDc36E20D267Ff0dd6097799f82e78907105e2F', // WETH on Lens Chain
      destinationChainId: 232,
      depositor: '<address-of-the-sender>'
    }
  })
 // console.log(data) [if needed]
  return data
}

Key Parameters:

  • tradeType: Use "minOutput" to ensure a minimum amount after the swap.

  • inputToken: Address of ETH or USDC on the origin chain. (Note: USDC contains 6 decimal places)

  • originChainId: Chain ID of the origin chain.

  • outputToken: Corresponding token address on Lens.

  • destinationChainId: Chain ID of Lens.

3. Swap USDC on Ethereum Mainnet to GHO 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: '0x1ff1dC3cB9eeDbC6Eb2d99C03b30A05cA625fB5a', // USDC on Ethereum
      originChainId: 1,
      outputToken: '0x6bDc36E20D267Ff0dd6097799f82e78907105e2F', // GHO on Lens Chain
      destinationChainId: 232,
      depositor: '<address-of-the-depositor>'
    }
  })
 // console.log(data) [if needed]
  return data
}

Key Parameters:

  • inputToken: Address of USDC on Ethereum Mainnet.

  • outputToken: Address of GHO on Lens.


With this, you have now completely understood the core principles of using the /swap/approval endpoint and walked through certain examples that enable you to swap and bridge tokens to build custom use cases on Lens Chain.

If you have any doubts, please feel free to reach out to us here.

Last updated