Transform Externally Owned Accounts into smart accounts using EIP-7702 with Alchemy or ZeroDev
npm install @account-kit/infra @account-kit/smart-contracts @aa-sdk/core @getpara/viem-v2-integration@alpha viem @getpara/web-sdk@alpha --save-exact
import { alchemy } from "@account-kit/infra";
import { createModularAccountV2Client } from "@account-kit/smart-contracts";
import { WalletClientSigner } from "@aa-sdk/core";
import { createParaAccount, createParaViemClient } from "@getpara/viem-v2-integration";
import { arbitrumSepolia } from "@account-kit/infra";
import { http, type LocalAccount, type WalletClient } from "viem";
import Para from "@getpara/web-sdk";
const para = new Para(YOUR_API_KEY);
const viemParaAccount: LocalAccount = createParaAccount(para);
viemParaAccount.signMessage = async ({ message }) => {
const signature = await para.signMessage(message);
const cleanSig = signature.startsWith("0x") ? signature.slice(2) : signature;
const v = parseInt(cleanSig.slice(128, 130), 16);
if (v < 27) {
const adjustedV = (v + 27).toString(16).padStart(2, "0");
return signature.slice(0, -2) + adjustedV;
}
return signature;
};
viemParaAccount.signAuthorization = async (authorization) => {
const signature = await para.signMessage(authorization);
const cleanSig = signature.startsWith("0x") ? signature.slice(2) : signature;
const v = parseInt(cleanSig.slice(128, 130), 16);
if (v !== 0 && v !== 1) {
throw new Error(`Invalid v value for EIP-7702: ${v}. Expected 0 or 1`);
}
return signature;
};
const viemClient: WalletClient = createParaViemClient(para, {
account: viemParaAccount,
chain: arbitrumSepolia,
transport: http(rpcUrl)
});
const walletClientSigner = new WalletClientSigner(viemClient, "para");
const alchemyClient = await createModularAccountV2Client({
mode: "7702",
transport: alchemy({
rpcUrl: rpcUrl
}),
chain: arbitrumSepolia,
signer: walletClientSigner,
policyId: alchemyGasPolicyId
});
const userOpResult = await alchemyClient.sendUserOperation({
uo: {
target: "0x1234567890123456789012345678901234567890",
data: "0x",
value: parseEther("0.01"),
}
});