This is a simple frontend application that enables users to send ERC-4337 user operations using wagmi, viem, and permissionless.js.
- Create & Fund an ERC-4337 smart contract account.
- Send ERC-4337 user operations.
-
Pimlico API Key:
- Obtain an API key by visiting the Pimlico Documentation.
-
Environment File:
-
After acquiring the API key, create a
.env.local
file in the root directory based on the provided.env.example
file.Example:
VITE_PIMLICO_API_KEY=your_api_key_here
-
-
Install Dependencies:
- This project uses pnpm as the package manager. Make sure you have pnpm installed.
-
Clone the repository:
git clone https://github.com/zt-9/wagmi-erc4337.git cd wagmi-erc4337
-
Install the dependencies:
pnpm install
-
Set up the environment variables:
- Create a
.env.local
file and include your Pimlico API key as described above.
cp .env.example .env.local
- Create a
-
Start the development server:
pnpm dev
Before sending user operations, ensure your smart contract account is funded. Send ETH to your smart contract account address to cover transaction costs.
Send your first ERC-4337 user operation by just signing the User Operation.
Use wagmi to get the viem publicClient and walletClient, which will be used for creating the ERC-4337 bundler and account.
import { usePublicClient, useWalletClient } from "wagmi";
const publicClient = usePublicClient();
const { data: walletClient } = useWalletClient();
We use the toSimpleSmartAccount
to load a simple erc4337 account.
This will not deploy a smart contract account if it does not exist. It simply loads the deterministic address where the smart account will be deployed.
import { toSimpleSmartAccount } from "permissionless/accounts";
// ERC 4337 smart contract account
const [smartAccount, setSmartAccount] = useState<any>(null);
// Use an effect to load the smart account once walletClient is ready
useEffect(() => {
// If there's no wallet client yet, skip
if (!walletClient) return;
loadSmartAccount();
}, [walletClient, publicClient]);
async function loadSmartAccount() {
try {
const account = await toSimpleSmartAccount({
client: publicClient,
owner: walletClient!,
});
setSmartAccount(account);
} catch (err) {
console.error("Failed to get ERC4337 account:", err);
}
}
Create the bundler client with pimlico RPC
import { createBundlerClient } from "viem/account-abstraction";
const bundlerClient = createBundlerClient({
account: smartAccount,
client: publicClient,
transport: http(`https://api.pimlico.io/v2/sepolia/rpc?apikey=APIKEY`),
});
Send a user operation to transfer ETH:
const hash = await bundlerClient.sendUserOperation({
account: smartAccount,
calls: [
{
to: to,
value: parseEther(value),
},
],
});
This will send ETH to the specified to address to
.