See full example here which uses Pimlico services for bundling, paymaster, gas estimation, etc.
Basic Implementation
1
Create Dynamic app with Viem & Wagmi
Copy
Ask AI
npx create-dynamic-app my-mm-smart-account-app --framework react --library viem --wagmi true --chains ethereum --pm npm
2
Install Delegation Toolkit
After the app is created, install the Delegation Toolkit:
Copy
Ask AI
npm install @metamask/delegation-toolkit
3
Create Smart Account Hook
src/hooks/useSmartAccount.ts
Copy
Ask AI
import {
Implementation,
MetaMaskSmartAccount,
toMetaMaskSmartAccount,
} from "@metamask/delegation-toolkit";
import { useEffect, useState } from "react";
import { useAccount, usePublicClient, useWalletClient } from "wagmi";
export default function useSmartAccount(): {
smartAccount: MetaMaskSmartAccount | null;
} {
const { address } = useAccount();
const publicClient = usePublicClient();
const { data: walletClient } = useWalletClient();
const [smartAccount, setSmartAccount] = useState<MetaMaskSmartAccount | null>(
null
);
useEffect(() => {
if (!address || !walletClient || !publicClient) return;
console.log("Creating smart account");
toMetaMaskSmartAccount({
client: publicClient,
implementation: Implementation.Hybrid,
deployParams: [address, [], [], []],
deploySalt: "0x",
signatory: { walletClient },
}).then((smartAccount) => {
setSmartAccount(smartAccount);
});
}, [address, walletClient, publicClient]);
return { smartAccount };
}
4
Create Bundler Client Hook
src/hooks/useBundlerClient.ts
Copy
Ask AI
import { createBundlerClient } from "viem/account-abstraction";
import { useState, useEffect } from "react";
import { usePublicClient } from "wagmi";
import { http } from "viem";
export function useBundlerClient() {
const [bundlerClient, setBundlerClient] = useState();
const publicClient = usePublicClient();
useEffect(() => {
if (!publicClient) return;
setBundlerClient(createBundlerClient({
client: publicClient,
transport: http("https://your-bundler-rpc.com"),
}));
}, [publicClient]);
return { bundlerClient };
}
5
Send User Operation
src/components/SendUserOperation.tsx
Copy
Ask AI
import { parseEther } from "viem";
import useBundlerClient from "/hooks/useBundlerClient";
import useSmartAccount from "../hooks/useSmartAccount";
const SendUserOperation = () => {
const { bundlerClient } = useBundlerClient();
const { smartAccount } = useSmartAccount();
// Appropriate fee per gas must be determined for the specific bundler being used.
const maxFeePerGas = 1n;
const maxPriorityFeePerGas = 1n;
const handleSendUserOperation = async () => {
const userOperationHash = await bundlerClient.sendUserOperation({
account: smartAccount,
calls: [
{
to: "0x1234567890123456789012345678901234567890",
value: parseEther("1"),
},
],
maxFeePerGas,
maxPriorityFeePerGas,
});
// You may want to handle the result here, e.g., show a notification
console.log("User Operation Hash:", userOperationHash);
};
return (
<button onClick={handleSendUserOperation}>
Send User Operation
</button>
);
}