How to create a Smart Contract Account with AccountKit and ZAN
Overview
This guide will show you how to create a smart contract account and send a User Operation with Account Kit and ZAN Bundler API.
Account Kit consists of a number of SDK packages that you can leverage to interact with ERC-4337 infrastructure. ZAN provides ERC-4337 compliant APIs that integrate effortlessly with widely-used Account Abstraction SDKs.
Prerequisites
Before creating a SCA with this guide, you should possess skills and knowledge about the topics we are going over. We assume that you already have an understanding/experience with the following:
- The development of smart contracts and their role in Ethereum
- Metamask or similar crypto wallet usage
- We are creating the SCA on the Sepolia testnet, so you wonβt need to use real ETH for this guide. However, you will need SepoliaETH to transact on the testnet. You can get test ETH from Alchemy's Sepolia faucet.
- TypeScript
- Account Abstraction (ERC-4337) and how it works, conceptually.
Quickstart
1. Setup a project
add the following dependencies:
yarn add viem
yarn add @alchemy/aa-accounts @alchemy/aa-core
yarn add @zannodeservice/aa-zan
yarn add dotenv
viem
is a lightweight interface for Ethereum.
Two Alchemy packages @alchemy/aa-accounts
and @alchemy/aa-core
come from the Alchemy Account Kit, and will provide the key building blocks.
The aa-zan SDK @zannodeservice/aa-zan
enables better interaction with the ZAN AA infrastructure APIs, including the ERC-4337 standard interface, ZAN paymaster service, and ZAN's unique data query interfaces.
dotenv
is an npm package that automatically loads environment variables from a .env file into process.env, making it easier to manage configuration options for your applications.
2. Loading Modules and Environment Parameters
import {
LocalAccountSigner,
type SmartAccountSigner,
} from "@alchemy/aa-core";
import {
createLightAccount,
} from "@alchemy/aa-accounts";
import { createZanSmartAccountClient } from "@zannodeservice/aa-zan";
import * as dotenv from "dotenv";
import {http} from "viem";
import { sepolia } from "viem/chains";
Get Constants from environment parameters.
dotenv.config()
const rpcUrl = process.env.RPC_URL;
const private_key = process.env.PRIVATE_KEY;
The .env
file must look like follows:
RPC_URL = https://api.zan.top/node/v1/eth/sepolia/{apiKey}
PRIVATE_KEY = 0x123abc...
3. Create a Signer
Our smart contract account needs to have an "owner". An "owner" refers to the entity that has control over a smart contract, including the capability to execute specific privileged actions, such as updating the contract or invoking certain functions that are restricted to the owner. In our case, the owner of the smart contract account is designated by a private key.
PRIVATE_KEY environment variable is read and stored in the private_key constant.
Creating an Account Signer instance based on the private key.
const eoaSigner: SmartAccountSigner = LocalAccountSigner.privateKeyToAccountSigner(private_key);
4. Create a client
const chain = sepolia;
export const zanSmartAccountClient = createZanSmartAccountClient({
rpcUrl,
chain,
account: await createLightAccount({
transport: http(rpcUrl),
chain,
signer: eoaSigner,
})
});
5. Send a UserOperation
Build an Eth transfer.
const targetAddress = "0x136aF0A9155d89CD428E8f292F79D74a69B38E0f"; // Replace with the desired target address
const userOpData = {
target: targetAddress,
data: "0x0",
value: 0n,
};
Build and then send the UserOperation by calling sendUserOperation
method.
then waitForUserOperationTransaction
method of smartAccountClient is called, which waits and polls for the user operation to be mined and included into a block, identified by txHash (the transaction hash).
const { hash: batchedUoHash } = await zanSmartAccountClient.sendUserOperation({
uo: [userOpData]
});
// Send a user operation from your smart contract account
console.log("Resulting UserOperation: ", batchedUoHash); // Log the user operation hash
console.log(`Checkout https://jiffyscan.xyz/userOpHash/${batchedUoHash}?network=${chain.name}`)
const txHash = await zanSmartAccountClient.waitForUserOperationTransaction({
hash: batchedUoHash
});
console.log(`Transaction Hash: ${txHash}`);
you can also use a website called "jiffyscan.xyz for tracking its processing.
Updated 5 months ago