> ## Documentation Index
> Fetch the complete documentation index at: https://docs.enso.build/llms.txt
> Use this file to discover all available pages before exploring further.

# CCIP Bridge with Callback

> Bridge ERC20 tokens across chains using Chainlink CCIP with post-bridge swap execution

export const date_0 = "2025-02-03"

This workflow demonstrates bridging tokens using Chainlink's CCIP protocol with automatic post-bridge execution. CCIP supports larger callback payloads (up to 30KB), making it ideal for complex post-bridge operations.

```mermaid theme={null}
flowchart LR
    subgraph bnb ["🟡 BNB Chain"]
        SOLVBTC_BNB((SolvBTC)) --> A1(( ))
    end

    A1 -.->|ccip<br/>bridge| B1

    subgraph base ["🔵 Base"]
        B1(( )) -->|balance<br/>check| SOLVBTC_BASE((SolvBTC))
        SOLVBTC_BASE -->|enso<br/>route| ETH((ETH))
    end
```

**Route Mechanics:**

This bundle bridges SolvBTC from BNB Chain to Base using CCIP, then automatically swaps it to native ETH:

* Bridge SolvBTC from BNB Chain to Base using Chainlink CCIP
* Check SolvBTC balance on Base after successful bridge completion
* Swap bridged SolvBTC to native ETH using Enso's routing

<Note>
  Use the [GET `/ccip/router`](/api-reference/integration/ccip-router) API to get the CCIP Router address for the `primaryAddress` parameter.
</Note>

```typescript ccipBridgeWithCallback.ts theme={null}
import { EnsoClient } from "@ensofinance/sdk";
import { parseUnits } from "viem";

// Chain IDs
const BNB_CHAIN_ID = 56;
const BASE_CHAIN_ID = 8453;

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

// Token addresses
const SOLVBTC_BNB = "0x4aae823a6a0b376De6A78e74eCC5b079d38cBCf7";
const SOLVBTC_BASE = "0x3B86Ad95859b6AB773f55f8d94B4b9d443EE931f";
const NATIVE_TOKEN = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";

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

// Get CCIP Router address for BNB Chain
const ccipRouter = await client.getCcipRouter({
  chainId: BNB_CHAIN_ID,
});

const bundle = await client.getBundleData(
  {
    chainId: BNB_CHAIN_ID,
    fromAddress: WALLET_ADDRESS,
    routingStrategy: "router",
    receiver: WALLET_ADDRESS,
  },
  [
    {
      protocol: "ccip",
      action: "bridge",
      args: {
        primaryAddress: ccipRouter.router,
        destinationChainId: BASE_CHAIN_ID,
        tokenIn: SOLVBTC_BNB,
        amountIn: "100000000000000", // 0.0001 SolvBTC
        receiver: WALLET_ADDRESS,
        callback: [
          // Step 1: Check SolvBTC balance on Base after bridge
          {
            protocol: "enso",
            action: "balance",
            args: {
              token: SOLVBTC_BASE,
            },
          },
          // Step 2: Swap SolvBTC to native ETH on Base
          {
            protocol: "enso",
            action: "route",
            args: {
              slippage: "100", // 1%
              tokenIn: SOLVBTC_BASE,
              tokenOut: NATIVE_TOKEN,
              amountIn: { useOutputOfCallAt: 0 },
            },
          },
        ],
      },
    },
  ]
);

return bundle;
```

**Important Considerations:**

* CCIP only supports ERC20 tokens - native token bridging is not available
* Callback data limit is approximately 30KB, allowing for complex post-bridge operations
* The callback gas limit ranges from 200k (default) to 3M (max)
* CCIP fees are paid in native token (wrapped)
* If callback execution fails, tokens are sent to `refundReceiver` (defaults to `receiver`)

<Warning>
  **Finalization timing**: CCIP waits for source chain finalization before executing callbacks. This ensures transaction irreversibility but timing varies significantly by chain (sub-second to hours).

  See [Chainlink's Finality By Blockchain](https://docs.chain.link/ccip/ccip-execution-latency#finality-by-blockchain) for current finalization times per chain.

  For time-sensitive swaps with tight slippage protection on slower chains, consider using Relay or Stargate instead.
</Warning>

## Without Callback (Simple Transfer)

For simple cross-chain transfers without post-bridge execution:

```typescript ccipSimpleTransfer.ts theme={null}
const bundle = await client.getBundleData(
  {
    chainId: BNB_CHAIN_ID,
    fromAddress: WALLET_ADDRESS,
    routingStrategy: "router",
    receiver: WALLET_ADDRESS,
  },
  [
    {
      protocol: "ccip",
      action: "bridge",
      args: {
        primaryAddress: ccipRouter.router,
        destinationChainId: BASE_CHAIN_ID,
        tokenIn: SOLVBTC_BNB,
        amountIn: "100000000000000",
        receiver: WALLET_ADDRESS,
        // No callback - tokens sent directly to receiver on Base
      },
    },
  ]
);
```

## Resources

* [Crosschain Routing Guide](/pages/build/get-started/crosschain-routing) - Complete guide to crosschain operations
* [Bridge Action Reference](/pages/build/reference/actions#bridge) - Technical details on bridge parameters
* [Bundle Actions Guide](/pages/build/get-started/bundling-actions) - Creating complex multi-step transactions

<div className="text-right text-xs gray-200 font-semibold w-full" style={{marginTop: '0'}}>
  <p style={{
        color: "#b2b2b2"  
    }}>Updated {date_0}</p>
</div>
