Skip to main content
This workflow demonstrates bridging tokens using Relay protocol with automatic post-bridge execution. Relay uses a placeholder-based design for dynamic amount resolution, making it ideal for complex workflows where amounts are determined at execution time. Route Mechanics: This bundle swaps USDC to ETH, bridges to Arbitrum via Relay, then wraps to WETH:
  • Swap USDC to native ETH on Ethereum using Enso routing
  • Bridge ETH from Ethereum to Arbitrum using Relay (supports native tokens)
  • Check ETH balance on Arbitrum after successful bridge
  • Wrap ETH to WETH on Arbitrum
relayBridgeWithCallback.ts
import { EnsoClient } from "@ensofinance/sdk";

// Chain IDs
const ETHEREUM_ID = 1;
const ARBITRUM_ID = 42161;

// Common addresses
const WALLET_ADDRESS = "0xd8da6bf26964af9d7eed9e03e53415d37aa96045";

// Token addresses
const USDC_ETHEREUM = "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48";
const WETH_ARBITRUM = "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1";
const NATIVE_TOKEN = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";

const client = new EnsoClient({
  apiKey: process.env.ENSO_API_KEY!,
});

const bundle = await client.getBundleData(
  {
    chainId: ETHEREUM_ID,
    fromAddress: WALLET_ADDRESS,
    routingStrategy: "router",
  },
  [
    // Step 1: Swap USDC to ETH on Ethereum
    {
      protocol: "enso",
      action: "route",
      args: {
        tokenIn: USDC_ETHEREUM,
        tokenOut: NATIVE_TOKEN,
        amountIn: "10000000", // 10 USDC
      },
    },
    // Step 2: Bridge ETH to Arbitrum via Relay
    {
      protocol: "relay",
      action: "bridge",
      args: {
        primaryAddress: "0xa5f565650890fba1824ee0f21ebbbf660a179934",
        destinationChainId: ARBITRUM_ID,
        tokenIn: NATIVE_TOKEN, // Relay supports native tokens
        amountIn: { useOutputOfCallAt: 0 },
        receiver: WALLET_ADDRESS,
        callback: [
          // Step 3: Check ETH balance on Arbitrum
          {
            protocol: "enso",
            action: "balance",
            args: {
              token: NATIVE_TOKEN,
            },
          },
          // Step 4: Wrap ETH to WETH on Arbitrum
          {
            protocol: "wrapped-native",
            action: "deposit",
            args: {
              primaryAddress: WETH_ARBITRUM,
              tokenIn: NATIVE_TOKEN,
              tokenOut: WETH_ARBITRUM,
              amountIn: { useOutputOfCallAt: 0 },
            },
          },
        ],
      },
    },
  ]
);

return bundle;
Important Considerations:
  • Relay supports both ERC20 and native token bridging
  • No callback data limit - uses placeholder-based design for dynamic amounts
  • Fee is taken from the bridged token amount (no separate fee token)
  • API-based quote system determines optimal routing
  • For Relay, primaryAddress is the token address itself

Key Differences from Other Bridges

FeatureRelayCCIPStargate
Native TokenYesNoYes
Callback LimitUnlimited~30KB~9.5KB
Fee TokenToken itselfNativeNative
Amount ResolutionDynamic (placeholders)Pre-computedPre-computed

Resources

Updated