External wallets like MetaMask, Rabby, and Trust Wallet don’t allow apps to install smart account logic directly on your address. Biconomy solves this with Fusion Mode —a passthrough mechanism that enables the same powerful orchestration features through a temporary Companion Account.
What We’re Building
By the end of this tutorial, your users will be able to:
Connect their existing MetaMask, Rabby, or Trust wallet
Execute orchestrated transactions (swaps, bridges, multicalls)
Pay gas with ERC-20 tokens instead of ETH
Receive all resulting tokens back to their original wallet
How it works : When a user signs a “trigger” transaction, Biconomy’s MEE temporarily moves funds to a Companion Account, executes all operations, and returns the results to the user’s wallet—all in one seamless flow.
Understanding Fusion Mode
Before diving into code, let’s understand how Fusion Mode differs from the EIP-7702 approach used with embedded wallets.
Why Fusion Mode?
External wallets are browser extensions that maintain their own security model. They don’t permit apps to “upgrade” the wallet to a smart account using EIP-7702. Fusion Mode works around this limitation by:
Using a trigger transaction to authorize the orchestration
Routing execution through a Companion Account (fully owned by the user)
Returning all assets to the user’s original wallet
The Fusion Flow
User Signs Trigger
The user signs a transaction (often a permit or approve) that contains the hash of all orchestration instructions. This single signature authorizes the entire flow.
Funds Move to Companion Account
Funds are pulled into a Companion Account that the user fully owns. This account is non-custodial and stateless—nothing remains after execution.
Instructions Execute
All operations (swaps, bridges, multicalls) execute using the Companion Account. MEE nodes handle the complexity.
Assets Return to EOA
Final assets are sent back to the user’s original wallet address. The Companion Account is left clean.
Automatic Cleanup (if needed)
If any step fails, cleanup logic can revert intermediate steps and return funds safely.
Invisible to Users : Your users never need to know about the Companion Account. From their perspective, they sign once and receive tokens in their wallet.
Trigger Types
Fusion Mode supports two trigger types, automatically selected based on your input token:
Trigger Type How it Works Gas Required Token Support ERC20Permit Uses ERC-2612 signature to permit spending. Orchestration hash is packed into the deadline field. ❌ No ERC-2612 tokens only Onchain Tx User sends an approve() transaction that includes orchestration data. ✅ Yes All ERC-20 tokens
The SDK automatically detects whether your token supports ERC-2612 and chooses the appropriate trigger type.
Fusion Constraints
Before implementing, understand these limitations:
One token per signature : Fusion can only consume one input token per user action
Same token for gas : The trigger token must also pay for gas fees
Same-chain gas only : Unlike EIP-7702, you can’t pay gas on Chain A for execution on Chain B
Sponsorship available : You can sponsor gas to bypass the gas requirement entirely
Step 1: Install Dependencies
npm install @biconomy/abstractjs viem wagmi @tanstack/react-query
What these packages do:
@biconomy/abstractjs — Biconomy’s SDK for MEE and Fusion Mode
viem — Ethereum library for building transactions
wagmi — React hooks for wallet connections
@tanstack/react-query — Required peer dependency for wagmi
Set up wagmi to support popular external wallets:
import { WagmiProvider , createConfig , http } from "wagmi" ;
import { optimism , base , arbitrum } from "wagmi/chains" ;
import { QueryClient , QueryClientProvider } from "@tanstack/react-query" ;
import { injected , walletConnect } from "wagmi/connectors" ;
const config = createConfig ({
chains: [ optimism , base , arbitrum ],
connectors: [
injected (), // MetaMask, Rabby, etc.
walletConnect ({ projectId: "YOUR_WC_PROJECT_ID" }),
],
transports: {
[optimism.id]: http (),
[base.id]: http (),
[arbitrum.id]: http (),
},
});
const queryClient = new QueryClient ();
function App ({ children }) {
return (
< WagmiProvider config = { config } >
< QueryClientProvider client = { queryClient } >
{ children }
</ QueryClientProvider >
</ WagmiProvider >
);
}
Step 3: Connect the Wallet
Use wagmi hooks to connect and access the user’s wallet:
import { useAccount , useConnect , useWalletClient } from "wagmi" ;
function WalletConnection () {
const { address , isConnected } = useAccount ();
const { connect , connectors } = useConnect ();
const { data : walletClient } = useWalletClient ();
if ( ! isConnected ) {
return (
< div >
{ connectors . map (( connector ) => (
< button key = { connector . id } onClick = { () => connect ({ connector }) } >
Connect { connector . name }
</ button >
)) }
</ div >
);
}
return < p > Connected: { address } </ p > ;
}
Step 4: Create the Fusion Account
For Fusion Mode, create a toFusionAccount instead of the standard Nexus account:
import {
mcUSDC ,
toFusionAccount ,
createMeeClient
} from "@biconomy/abstractjs" ;
import { optimism , base } from "viem/chains" ;
import { http } from "viem" ;
async function setupFusion ( walletClient ) {
// Create a Fusion account for the connected wallet
const fusionAccount = await toFusionAccount ({
// The user's EOA address from their external wallet
address: walletClient . account . address ,
// The client for signing (from wagmi)
client: walletClient ,
// Chains where Fusion will operate
chains: [ optimism , base ],
});
// Create the MEE client
const meeClient = await createMeeClient ({
account: fusionAccount ,
});
return { fusionAccount , meeClient };
}
Step 5: Build the Trigger
The trigger defines which token the user will “spend” to initiate the orchestration:
import { parseUnits } from "viem" ;
import { mcUSDC } from "@biconomy/abstractjs" ;
// Define the trigger: user will spend USDC on Optimism
const trigger = {
chainId: optimism . id ,
tokenAddress: mcUSDC . addressOn ( optimism . id ),
amount: parseUnits ( "10" , 6 ), // 10 USDC
};
The trigger token must be the same token used for gas payment in Fusion Mode. This is a key constraint.
Step 6: Define Instructions
Instructions describe what operations to execute. Here’s an example that transfers USDC:
import { encodeFunctionData , erc20Abi , parseUnits } from "viem" ;
// Example: Transfer some USDC to another address
const instructions = [
{
chainId: optimism . id ,
calls: [
{
to: mcUSDC . addressOn ( optimism . id ),
data: encodeFunctionData ({
abi: erc20Abi ,
functionName: "transfer" ,
args: [ "0xRecipientAddress" , parseUnits ( "5" , 6 )],
}),
},
],
},
];
Step 7: Get a Fusion Quote
Request a quote that includes the trigger and instructions:
const { quote , trigger : signableTrigger } = await meeClient . getFusionQuote ({
trigger ,
instructions ,
feeToken: {
address: trigger . tokenAddress ,
chainId: trigger . chainId ,
},
});
console . log ( "Estimated gas cost:" , quote . paymentInfo . tokenWei );
Step 8: Execute the Fusion Transaction
Execute the quote—the SDK handles trigger signing automatically:
const { hash } = await meeClient . executeFusionQuote ({
fusionQuote: quote
});
console . log ( "Supertransaction submitted:" , hash );
// Wait for confirmation
const receipt = await meeClient . waitForSupertransactionReceipt ({ hash });
console . log ( "Completed:" , receipt );
Complete Example
Here’s a full React component for Fusion Mode with MetaMask:
import { useState } from "react" ;
import { useAccount , useWalletClient } from "wagmi" ;
import { parseUnits , encodeFunctionData , erc20Abi } from "viem" ;
import { optimism } from "viem/chains" ;
import {
createMeeClient ,
toFusionAccount ,
mcUSDC
} from "@biconomy/abstractjs" ;
const USDC_OPTIMISM = "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85" ;
export function FusionTransfer () {
const { address } = useAccount ();
const { data : walletClient } = useWalletClient ();
const [ status , setStatus ] = useState ( "" );
const [ recipient , setRecipient ] = useState ( "" );
const [ amount , setAmount ] = useState ( "" );
async function executeFusionTransaction () {
if ( ! walletClient || ! address ) {
setStatus ( "Please connect your wallet first" );
return ;
}
try {
setStatus ( "Setting up Fusion account..." );
// Create Fusion account for external wallet
const fusionAccount = await toFusionAccount ({
address ,
client: walletClient ,
chains: [ optimism ],
});
// Create MEE client
const meeClient = await createMeeClient ({
account: fusionAccount ,
});
setStatus ( "Getting quote..." );
// The amount to trigger with (includes buffer for gas)
const triggerAmount = parseUnits ( amount , 6 );
const transferAmount = parseUnits (
( parseFloat ( amount ) * 0.95 ). toFixed ( 6 ), // 95% goes to recipient
6
);
// Define trigger
const trigger = {
chainId: optimism . id ,
tokenAddress: USDC_OPTIMISM ,
amount: triggerAmount ,
};
// Define what we want to do
const instructions = [
{
chainId: optimism . id ,
calls: [
{
to: USDC_OPTIMISM ,
data: encodeFunctionData ({
abi: erc20Abi ,
functionName: "transfer" ,
args: [ recipient , transferAmount ],
}),
},
],
},
];
// Get quote
const { quote } = await meeClient . getFusionQuote ({
trigger ,
instructions ,
feeToken: {
address: USDC_OPTIMISM ,
chainId: optimism . id ,
},
});
setStatus ( "Please sign the transaction in your wallet..." );
// Execute (user will be prompted to sign)
const { hash } = await meeClient . executeFusionQuote ({
fusionQuote: quote ,
});
setStatus ( `Transaction submitted! Hash: ${ hash } ` );
// Wait for confirmation
const receipt = await meeClient . waitForSupertransactionReceipt ({ hash });
setStatus ( `✅ Success! Transferred to ${ recipient } ` );
} catch ( error ) {
setStatus ( `Error: ${ error . message } ` );
}
}
return (
< div className = "fusion-transfer" >
< h2 > Send USDC (Gasless with Fusion) </ h2 >
< input
type = "text"
placeholder = "Recipient address"
value = { recipient }
onChange = { ( e ) => setRecipient ( e . target . value ) }
/>
< input
type = "text"
placeholder = "Amount (USDC)"
value = { amount }
onChange = { ( e ) => setAmount ( e . target . value ) }
/>
< button onClick = { executeFusionTransaction } >
Send USDC
</ button >
< p > { status } </ p >
< small >
Gas will be paid from your USDC. If your token supports ERC-2612,
this will be completely gasless.
</ small >
</ div >
);
}
Comparison: Fusion vs EIP-7702
Feature Fusion Mode EIP-7702 Wallet Support All wallets (MetaMask, Rabby, Trust, etc.) Embedded wallets only (Privy, Turnkey, etc.) Gas Payment Same chain only Cross-chain supported Input Tokens One token per signature Multiple tokens possible User Experience Sign once (permit) or send approve tx Sign authorization once Companion Account Required (transparent) Not needed
When to Use Fusion Mode
Use Fusion When
Users have MetaMask, Rabby, Trust, or similar
You need maximum wallet compatibility
Single-token input flows (swaps, deposits)
Same-chain gas payment is acceptable
Consider EIP-7702 When
You control the wallet (embedded wallets)
Cross-chain gas payment is needed
Multiple input tokens per operation
Direct smart account features required
Key Takeaways
Fusion enables any wallet — MetaMask, Rabby, Trust, and all browser extensions work
One signature, full orchestration — Users sign once to authorize complex operations
Transparent Companion Account — Users never see it; assets always return to their wallet
Automatic trigger detection — SDK chooses gasless permit or onchain tx based on token
Next Steps