***
title: Biconomy MEE — Simplified Onboarding via Smart Accounts
slug: guides/biconomy
subtitle: >-
Use Biconomy's Modular Execution Environment (MEE) to enable cross-chain
onboarding with a single user signature
---------------------------------------
Biconomy's **Modular Execution Environment (MEE)** lets you build seamless cross-chain experiences on top of Transak's fiat on-ramp — with no smart wallet setup required for users.
## EVM Account Types
Before diving into MEE, it helps to understand the two foundational account types on Ethereum:
Externally Owned Accounts (EOAs)
Controlled by a private key (e.g. MetaMask). Can send transactions and interact with contracts, but cannot execute complex logic or batch operations.
Contract Accounts (CAs)
Smart contract code deployed on-chain. Can execute complex logic and interact with other contracts, but require deployment and cannot initiate transactions on their own.
EIP-4337 Smart Accounts
Combine the best of both worlds — smart contract functionality within a single wallet. Enable account abstraction across DeFi, GameFi, DAOs, and more.
## MEE: Beyond ERC-4337
Biconomy's MEE extends standard ERC-4337 to enable **true cross-chain composability** — with no extra setup for users.
True Composability
Dynamic execution where each step can reference outputs from previous steps.
Cross-Chain Orchestration
A single signature authorizes complex flows spanning multiple chains simultaneously.
Universal Gas Abstraction
Pay for gas on any chain using tokens from any other supported chain.
EOA Wallet Support
Works with standard wallets like MetaMask — no smart wallet deployment required.
## How MEE Works: Fusion Execution
MEE uses a **Fusion** execution model with four core components:
Orchestrator
A Companion Smart Account that represents the user's wallet. Invisible to users — handles batching, permissions, and fee payments.
MEE Client
Collects instructions, bundles them, and coordinates execution across chains.
Instructions
Transaction objects created by dApps. Built using composable patterns that allow dynamic, multi-step execution.
Fee Token
Specifies which token to use for gas, allowing users to pay fees with any supported token on any chain.
The user signs a single quote authorizing their Companion account to pull tokens and execute instructions.
The Companion executes the batched instructions, using the pulled tokens to pay for gas and perform the requested actions.
## Why Integrate MEE with Transak?
Easy User Onboarding
Works with existing EOA wallets — no smart wallet setup required for your users.
Fiat On-Ramp
Let users buy crypto directly within your dApp via Transak's on-ramp.
Single Signature UX
One signature covers complex multi-step and multi-chain operations.
Gasless Transactions
Users pay transaction fees with any supported token — no native gas token required.
Chain Agnostic
Natively orchestrates operations across chains with a single authorization.
Custom Transaction Bundling
Batch multiple actions across chains in one transaction (e.g. Approve + Deposit).
## Getting Started
You can start testing MEE without any API key. Add your Biconomy API key only when you
### Biconomy API Key (Production only)
Visit [dashboard.biconomy.io](https://dashboard.biconomy.io/) and create an account or log in.
Set up a new project and copy your API key for production use.
## Project Setup
```shell
bun create vite my-mee-app --template react-ts
cd my-mee-app
```
```shell
bun add viem wagmi @biconomy/abstractjs @tanstack/react-query
```
Create `src/wagmi.ts`:
```typescript
import { baseSepolia } from 'wagmi/chains';
import { createConfig, http } from 'wagmi';
export const config = createConfig({
chains: [baseSepolia],
transports: {
[baseSepolia.id]: http()
}
});
```
Edit `src/main.tsx`:
```typescript
import ReactDOM from 'react-dom/client';
import { WagmiProvider } from 'wagmi';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { config } from './wagmi';
import App from './App';
const queryClient = new QueryClient();
ReactDOM.createRoot(document.getElementById('root')!).render(
);
```
```shell
bun dev
```
You should see the Vite starter page — setup is complete.
## Implementing MEE in `App.tsx`
Open `src/App.tsx` and add the following imports:
```typescript
import { useState } from 'react';
import {
createWalletClient,
custom,
erc20Abi,
http,
type Hex,
formatUnits
} from 'viem';
import { baseSepolia } from 'viem/chains';
import {
createMeeClient,
toMultichainNexusAccount,
getMeeScanLink,
getMEEVersion,
MEEVersion,
type MeeClient,
type MultichainSmartAccount
} from '@biconomy/abstractjs';
import { useReadContract } from 'wagmi';
```
Create a `connectAndInit` function that sets up the Orchestrator and MEE client:
```typescript
const usdcAddress = '0x036CbD53842c5426634e7929541eC2318f3dCF7e';
const [account, setAccount] = useState(null);
const [walletClient, setWalletClient] = useState(null);
const [meeClient, setMeeClient] = useState(null);
const [orchestrator, setOrchestrator] = useState(null);
const connectAndInit = async () => {
if (typeof window.ethereum === 'undefined') {
alert('MetaMask not detected');
return;
}
const wallet = createWalletClient({
chain: baseSepolia,
transport: custom(window.ethereum)
});
setWalletClient(wallet);
const [address] = await wallet.requestAddresses();
setAccount(address);
const multiAccount = await toMultichainNexusAccount({
chainConfigurations: [
{
chain: baseSepolia,
transport: http(),
version: getMEEVersion(MEEVersion.V2_1_0)
}
],
signer: createWalletClient({
account: address,
transport: custom(window.ethereum)
})
});
setOrchestrator(multiAccount);
const mee = await createMeeClient({ account: multiAccount });
setMeeClient(mee);
};
```
| Function | Purpose |
| -------------------------- | --------------------------------------------------------- |
| `toMultichainNexusAccount` | Creates the Orchestrator (Companion Smart Account) |
| `chainConfigurations` | Array of chains to support — add more for cross-chain ops |
| `getMEEVersion` | Retrieves the correct MEE version for compatibility |
| `createMeeClient` | Creates the MEE client that coordinates execution |
Create an `executeTransfers` function that builds composable instructions and executes them with a single signature:
```typescript
const executeTransfers = async () => {
if (!orchestrator || !meeClient || !account) {
alert('Account not initialized');
return;
}
try {
await walletClient?.switchChain({ id: baseSepolia.id });
const recipients = [
'0x322Af0da66D00be980C7aa006377FCaaEee3BDFD',
'0x1234567890123456789012345678901234567890'
];
// Build composable instructions for each recipient
const transfers = await Promise.all(
recipients.map((recipient) =>
orchestrator.buildComposable({
type: 'default',
data: {
abi: erc20Abi,
chainId: baseSepolia.id,
to: usdcAddress,
functionName: 'transfer',
args: [recipient as Hex, 1_000_000n] // 1 USDC (6 decimals)
}
})
)
);
const totalAmount = BigInt(transfers.length) * 1_000_000n;
// Get a Fusion quote with fee token specification
const fusionQuote = await meeClient.getFusionQuote({
instructions: transfers,
trigger: {
chainId: baseSepolia.id,
tokenAddress: usdcAddress,
amount: totalAmount
},
feeToken: {
address: usdcAddress,
chainId: baseSepolia.id
}
});
// Execute with a single user signature
const { hash } = await meeClient.executeFusionQuote({ fusionQuote });
// Wait for on-chain confirmation
const transactionDetail = await meeClient.waitForSupertransactionReceipt({ hash });
console.log('Transaction completed!');
console.log(getMeeScanLink(hash));
} catch (error) {
console.log(error);
}
};
```
## Complete Code Sample
The full `App.tsx` below includes wallet connection, balance display, dynamic recipient management, live status updates, and a MEE Scan link.