Skip to content

Commit

Permalink
Reduce boilerplate for base SimpleAccount config (#124)
Browse files Browse the repository at this point in the history
  • Loading branch information
hazim-j authored Apr 6, 2024
1 parent 9c1335e commit 35d66c0
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 44 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "userop",
"version": "0.4.0-beta.1",
"version": "0.4.0-beta.2",
"description": "A simple JS library for building ERC-4337 UserOperations.",
"types": "./dist/index.d.ts",
"main": "./dist/index.js",
Expand Down
36 changes: 8 additions & 28 deletions src/test/v06/account.constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import { V06 } from "../..";

const EOA_PK = generatePrivateKey();
const VIEM_ACC = privateKeyToAccount(EOA_PK);
const OWNER_ADDR = VIEM_ACC.address;
const VIEM_WALLET_CLIENT = createWalletClient({
account: VIEM_ACC,
chain: localhost,
Expand All @@ -33,58 +32,45 @@ export const ACCOUNTS = [
type: "SimpleAccount, withViemWalletClient (account hoisted)",
instance: new V06.Account.Instance({
...V06.Account.CommonConfigs.SimpleAccount.base(
OWNER_ADDR,
V06.Account.Hooks.RequestSignature.withViemWalletClient(
VIEM_WALLET_CLIENT,
),
VIEM_PUBLIC_CLIENT,
VIEM_WALLET_CLIENT,
),
}),
},
{
type: "SimpleAccount, withViemWalletClient (account not hoisted)",
instance: new V06.Account.Instance({
...V06.Account.CommonConfigs.SimpleAccount.base(
OWNER_ADDR,
V06.Account.Hooks.RequestSignature.withViemWalletClient(
VIEM_WALLET_CLIENT_NO_HOIST,
VIEM_ACC,
),
VIEM_PUBLIC_CLIENT,
VIEM_WALLET_CLIENT_NO_HOIST,
VIEM_ACC,
),
}),
},
{
type: "SimpleAccount, with JsonRpcProvider",
instance: new V06.Account.Instance({
...V06.Account.CommonConfigs.SimpleAccount.base(
OWNER_ADDR,
V06.Account.Hooks.RequestSignature.withViemWalletClient(
VIEM_WALLET_CLIENT,
),
ETHERS_JSON_RPC_PROVIDER,
VIEM_WALLET_CLIENT,
),
}),
},
{
type: "SimpleAccount, withEthersSigner",
instance: new V06.Account.Instance({
...V06.Account.CommonConfigs.SimpleAccount.base(
OWNER_ADDR,
V06.Account.Hooks.RequestSignature.withEthersSigner(ETHERS_WALLET),
VIEM_PUBLIC_CLIENT,
ETHERS_WALLET,
),
}),
},
{
type: "SimpleAccount, with separate viem node and bundler PublicClients",
instance: new V06.Account.Instance({
...V06.Account.CommonConfigs.SimpleAccount.base(
OWNER_ADDR,
V06.Account.Hooks.RequestSignature.withViemWalletClient(
VIEM_WALLET_CLIENT,
),
VIEM_NODE_PUBLIC_CLIENT,
VIEM_WALLET_CLIENT,
),

bundlerClient: VIEM_BUNDLER_PUBLIC_CLIENT,
Expand All @@ -94,11 +80,8 @@ export const ACCOUNTS = [
type: "SimpleAccount, with separate ethers node and bundler JsonRpcProviders",
instance: new V06.Account.Instance({
...V06.Account.CommonConfigs.SimpleAccount.base(
OWNER_ADDR,
V06.Account.Hooks.RequestSignature.withViemWalletClient(
VIEM_WALLET_CLIENT,
),
ETHERS_NODE_JSON_RPC_PROVIDER,
VIEM_WALLET_CLIENT,
),

bundlerClient: ETHERS_BUNDLER_JSON_RPC_PROVIDER,
Expand All @@ -108,11 +91,8 @@ export const ACCOUNTS = [
type: "SimpleAccount, with Stackup V1 PAYG paymaster",
instance: new V06.Account.Instance({
...V06.Account.CommonConfigs.SimpleAccount.base(
OWNER_ADDR,
V06.Account.Hooks.RequestSignature.withViemWalletClient(
VIEM_WALLET_CLIENT,
),
VIEM_PUBLIC_CLIENT,
VIEM_WALLET_CLIENT,
),

requestPaymaster: V06.Account.Hooks.RequestPaymaster.withCommon({
Expand Down
65 changes: 55 additions & 10 deletions src/v06/account/commonConfigs/simpleAccount.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,67 @@
import { Address, PublicClient } from "viem";
import { JsonRpcProvider } from "ethers";
import {
Account,
Address,
Chain,
PublicClient,
Transport,
WalletClient,
} from "viem";
import { JsonRpcProvider, Signer } from "ethers";
import { AccountAbi, FactoryAbi } from "./abi/simpleAccount";
import { RequiredAccountOpts } from "../types";
import { RequestSignatureFunc } from "../hooks";
import { RequestSignature } from "../hooks";

export const base = (
owner: Address,
requestSignature: RequestSignatureFunc,
const FACTORY_ADDRESS = "0x9406Cc6185a346906296840746125a0E44976454";

type SimpleAccountArgsWithViemEOA<E extends WalletClient> = [
ethClient: PublicClient | JsonRpcProvider,
eoa: E,
];
type SimpleAccountArgsWithViemEOANoHoist<E extends WalletClient> = [
ethClient: PublicClient | JsonRpcProvider,
eoa: E,
account: Account,
];
type SimpleAccountArgsWithEthersSigner<E extends Signer> = [
ethClient: PublicClient | JsonRpcProvider,
eoa: E,
];

export const base = <E extends WalletClient | Signer>(
...args: E extends WalletClient
? E["account"] extends Account
? SimpleAccountArgsWithViemEOA<E>
: SimpleAccountArgsWithViemEOANoHoist<E>
: E extends Signer
? SimpleAccountArgsWithEthersSigner<E>
: never
): RequiredAccountOpts<typeof AccountAbi, typeof FactoryAbi> => {
const [ethClient, eoa, account] = args;

return {
accountAbi: AccountAbi,
factoryAbi: FactoryAbi,
factoryAddress: "0x9406Cc6185a346906296840746125a0E44976454",
factoryAddress: FACTORY_ADDRESS,
ethClient,
setFactoryData(salt, encoder) {
return encoder("createAccount", [owner, salt]);
async setFactoryData(salt, encoder) {
if (account !== undefined) {
return encoder("createAccount", [account.address, salt]);
} else if ("getAddresses" in eoa) {
return encoder("createAccount", [(await eoa.getAddresses())[0], salt]);
} else {
return encoder("createAccount", [
(await eoa.getAddress()) as Address,
salt,
]);
}
},
requestSignature,
requestSignature:
"getAddresses" in eoa
? account !== undefined
? RequestSignature.withViemWalletClient(eoa, account)
: RequestSignature.withViemWalletClient(
eoa as WalletClient<Transport, Chain | undefined, Account>,
)
: RequestSignature.withEthersSigner(eoa),
};
};
2 changes: 1 addition & 1 deletion src/v06/account/hooks/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export type SetFactoryDataFunc<F extends Abi> = (
method: M,
inputs: AbiParametersToPrimitiveTypes<ExtractAbiFunction<F, M>["inputs"]>,
) => Hex,
) => Hex;
) => Promise<Hex>;

export type RequestSignatureFunc = (
type: "dummy" | "final",
Expand Down
8 changes: 4 additions & 4 deletions src/v06/account/instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,11 @@ export class Instance<A extends Abi, F extends Abi> {
this.onBuild = opts.onBuild;
}

private getInitCode(): Hex {
private async getInitCode(): Promise<Hex> {
if (this.initCode === "0x") {
this.initCode = concat([
this.factoryAddress,
this.setFactoryData(this.salt, (method, inputs) => {
await this.setFactoryData(this.salt, (method, inputs) => {
return encodeFunctionData({
abi: this.factoryAbi as Abi,
functionName: method as string,
Expand Down Expand Up @@ -117,7 +117,7 @@ export class Instance<A extends Abi, F extends Abi> {

return {
nonce,
initCode: code === undefined ? this.getInitCode() : "0x",
initCode: code === undefined ? await this.getInitCode() : "0x",
};
}

Expand Down Expand Up @@ -211,7 +211,7 @@ export class Instance<A extends Abi, F extends Abi> {
address: this.entryPointAddress,
abi: EntryPoint.CONTRACT_ABI,
functionName: "getSenderAddress",
args: [this.getInitCode()],
args: [await this.getInitCode()],
});
} catch (error) {
if (error instanceof BaseError) {
Expand Down

0 comments on commit 35d66c0

Please sign in to comment.