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

# Cross-Chain Orchestration

> Execute multi-chain flows with a single signature

Bridge, swap, and interact across chains in one transaction. User signs once—MEE handles timing, confirmations, and execution.

## How It Works

1. User signs a single message
2. MEE executes operations on the source chain
3. MEE waits for bridge completion
4. MEE executes operations on the destination chain
5. User receives final tokens

## Basic Cross-Chain Flow

```typescript theme={null}
import { toMultichainNexusAccount, createMeeClient } from "@biconomy/abstractjs";
import { arbitrum, base } from "viem/chains";

// Account spans multiple chains
const account = await toMultichainNexusAccount({
  signer,
  chainConfigurations: [
    { chain: arbitrum, transport: http(), version: getMEEVersion(MEEVersion.V2_1_0) },
    { chain: base, transport: http(), version: getMEEVersion(MEEVersion.V2_1_0) }
  ]
});

const meeClient = await createMeeClient({ account });

// Instructions on different chains
const bridgeInstruction = /* bridge from Arbitrum */;
const swapInstruction = /* swap on Base */;
const depositInstruction = /* deposit on Base */;

const quote = await meeClient.getQuote({
  instructions: [bridgeInstruction, swapInstruction, depositInstruction],
  feeToken: { address: USDC_ARBITRUM, chainId: arbitrum.id }
});

const { hash } = await meeClient.executeQuote({ quote });
```

## Runtime Injection for Bridge Outputs

Since bridge outputs aren't known upfront, use `runtimeERC20BalanceOf`:

```typescript theme={null}
import { runtimeERC20BalanceOf, greaterThanOrEqualTo } from "@biconomy/abstractjs";

// Bridge USDC from Arbitrum to Base via Across SpokePool
// See the Across integration guide for full setup: /new/integration-guides/bridges-and-solvers/integrate-across
const bridge = await account.buildComposable({
  type: "default",
  data: {
    chainId: arbitrum.id,
    to: ACROSS_SPOKE_POOL,
    abi: acrossSpokePoolAbi,
    functionName: "depositV3",
    args: [
      account.addressOn(arbitrum.id, true),  // depositor
      account.addressOn(base.id, true),       // recipient
      USDC_ARBITRUM,                          // inputToken
      USDC_BASE,                              // outputToken
      parseUnits("100", 6),                   // inputAmount
      outputAmount,                           // outputAmount (from Across quote API)
      base.id,                                // destinationChainId
      zeroAddress,                            // exclusiveRelayer
      quoteTimestamp,                         // quoteTimestamp (from Across quote API)
      fillDeadline,                           // fillDeadline
      0,                                      // exclusivityDeadline
      "0x"                                    // message
    ]
  }
});

// Swap on Base—waits for bridge to complete
const swap = await account.buildComposable({
  type: "default",
  data: {
    chainId: base.id,
    to: UNISWAP_ROUTER,
    abi: UniswapAbi,
    functionName: "exactInputSingle",
    args: [{
      tokenIn: USDC_BASE,
      amountIn: runtimeERC20BalanceOf({
        tokenAddress: USDC_BASE,
        targetAddress: account.addressOn(base.id, true),
        constraints: [greaterThanOrEqualTo(parseUnits("80", 6))]  // 20% slippage tolerance
      }),
      tokenOut: WETH_BASE,
      // ...
    }]
  }
});
```

<Info>
  **Automatic Sequencing**: MEE retries the swap instruction until the constraint is satisfied (bridge tokens have arrived).
</Info>

## Fusion Mode for External Wallets

For MetaMask/Rabby users:

```typescript theme={null}
const trigger = {
  chainId: arbitrum.id,
  tokenAddress: USDC_ARBITRUM,
  amount: parseUnits("100", 6)
};

const quote = await meeClient.getFusionQuote({
  trigger,
  instructions: [
    approveAcross,
    bridge,
    swapOnBase,
    depositOnBase,
    returnTokensToEOA
  ],
  feeToken: { address: USDC_ARBITRUM, chainId: arbitrum.id }
});

const { hash } = await meeClient.executeFusionQuote({ fusionQuote: quote });
```

## Example: Bridge → Swap → Deposit

Complete flow: USDC on Arbitrum → WETH yield on Base

```typescript theme={null}
const inputAmount = parseUnits("100", 6);
const minAfterSlippage = inputAmount * 80n / 100n;

// 1. Approve Across to spend USDC
const approveAcross = await account.buildComposable({
  type: "approve",
  data: { spender: ACROSS_SPOKE_POOL, tokenAddress: USDC_ARBITRUM, chainId: arbitrum.id, amount: inputAmount }
});

// 2. Bridge USDC: Arbitrum → Base (via Across SpokePool)
const bridge = await account.buildComposable({
  type: "default",
  data: {
    chainId: arbitrum.id,
    to: ACROSS_SPOKE_POOL,
    abi: acrossSpokePoolAbi,
    functionName: "depositV3",
    args: [
      account.addressOn(arbitrum.id, true),  // depositor
      account.addressOn(base.id, true),       // recipient
      USDC_ARBITRUM,                          // inputToken
      USDC_BASE,                              // outputToken
      inputAmount,                            // inputAmount
      outputAmount,                           // outputAmount (from Across quote API)
      base.id,                                // destinationChainId
      zeroAddress,                            // exclusiveRelayer
      quoteTimestamp,                         // quoteTimestamp
      fillDeadline,                           // fillDeadline
      0,                                      // exclusivityDeadline
      "0x"                                    // message
    ]
  }
});

// 3. Swap USDC → WETH on Base (waits for bridge)
const swap = await account.buildComposable({
  type: "default",
  data: {
    chainId: base.id,
    to: UNISWAP_ROUTER,
    abi: UniswapAbi,
    functionName: "exactInputSingle",
    args: [{
      tokenIn: USDC_BASE,
      amountIn: runtimeERC20BalanceOf({
        tokenAddress: USDC_BASE,
        targetAddress: account.addressOn(base.id, true),
        constraints: [greaterThanOrEqualTo(minAfterSlippage)]
      }),
      tokenOut: WETH_BASE,
      amountOutMinimum: 0n,
      recipient: account.addressOn(base.id, true),
      fee: 500,
      sqrtPriceLimitX96: 0n
    }]
  }
});

// 4. Deposit WETH into Morpho
const deposit = await account.buildComposable({
  type: "default",
  data: {
    chainId: base.id,
    to: MORPHO_WETH_POOL,
    abi: MorphoAbi,
    functionName: "deposit",
    args: [
      runtimeERC20BalanceOf({ tokenAddress: WETH_BASE, targetAddress: account.addressOn(base.id, true) }),
      account.addressOn(base.id, true)
    ]
  }
});

// Execute entire flow
const quote = await meeClient.getQuote({
  instructions: [approveAcross, bridge, swap, deposit],
  feeToken: { address: USDC_ARBITRUM, chainId: arbitrum.id }
});

const { hash } = await meeClient.executeQuote({ quote });
```

## Key Benefits

| Traditional               | With MEE                                                                                 |
| ------------------------- | ---------------------------------------------------------------------------------------- |
| 4+ signatures             | 1 signature                                                                              |
| Manual bridge waiting     | Automatic                                                                                |
| ETH needed on both chains | Pay in one token                                                                         |
| Risk of stuck states      | No stuck states—programmatic fund retrieval via [cleanups](/overview/abstractjs/cleanup) |

<Info>
  **Important**: Cross-chain transactions are **not atomic**—only single-chain batches are fully atomic (all-or-nothing). For cross-chain flows, if a step fails after bridging, tokens won't be lost—use [cleanup transactions](/overview/abstractjs/cleanup) to programmatically return funds to the user's wallet.
</Info>

## Next Steps

<Card title="Composable Batching" icon="syringe" href="/overview/abstractjs/composable-batching">
  Deep dive into dynamic parameters
</Card>
