Presets

Userop.js ships with common presets that can help you get started even quicker with certain use cases.

The builder interface is flexible enough to support any implementation of an ERC-4337 Smart Account. However, there are already a few common implementations used within the ecosystem already. Rather then create the same builder and middleware functions over and over again, we've shipped a few useful presets for commonly used implementations.

View the source code for Presets on GitHub.

πŸ“˜

Preset for [insert favorite contract account] is not included?? :(

No worries! Userop.js is open for PRs. Alternatively, let us know what type of presets you'd like to see and we'll work together to get it shipped. 🀝

Builder

Builder presets are pre-configured builders over a known contract account implementation. Presets can be used as-is or modified with the get and set functions.

πŸ“˜

Looking for a concrete example?

All builder presets are also used in the ERC-4337 examples repo. For each preset, you can find working code samples in the scripts directory.

SimpleAccount

The SimpleAccount preset is an abstraction to build User Operations for an ERC-4337 account based on SimpleAccount.sol.

import { Client, Presets } from "userop";

const simpleAccount = await Presets.Builder.SimpleAccount.init(
  signer, // Any object compatible with ethers.Signer
  config.rpcUrl
);
const client = await Client.init(config.rpcUrl);

const res = await client.sendUserOperation(
  simpleAccount.execute(target, value, "0x"),
  { onBuild: (op) => console.log("Signed UserOperation:", op) }
);
console.log(`UserOpHash: ${res.userOpHash}`);

console.log("Waiting for transaction...");
const ev = await res.wait();
console.log(`Transaction hash: ${ev?.transactionHash ?? null}`);

Kernel

The Kernel preset is an abstraction to build User Operations for an ERC-4337 account based on ZeroDev Kernel V2 - a modular contract account framework. It deploys with the ECDSA validator by default.

🚧

Only available on Polygon Mumbai

Kernel V2 factories and validators are currently only deployed on Polygon Mumbai.

import { Client, Presets } from "userop";

const kernel = await Presets.Builder.Kernel.init(
  signer, // Any object compatible with ethers.Signer
  config.rpcUrl,
);
const client = await Client.init(config.rpcUrl);

const res = await client.sendUserOperation(
  kernel.execute({to, value, data: "0x"}),
  { onBuild: (op) => console.log("Signed UserOperation:", op) }
);
console.log(`UserOpHash: ${res.userOpHash}`);

console.log("Waiting for transaction...");
const ev = await res.wait();
console.log(`Transaction hash: ${ev?.transactionHash ?? null}`);

Middleware

Middleware presets are common implementations of middleware functions that can be re-used for different builder instances.

View middleware functions on GitHub.

estimateUserOperationGas

A middleware function for sending UserOperations to the eth_estimateUserOperationGas endpoint in order to estimate reasonable gas limits for preVerificationGas, verificationGasLimit, and callGasLimit.

import { Presets } from "userop";

// provider is an ethers.js JSON-RPC provider.
builder = builder.useMiddleware(Presets.Middleware.estimateUserOperationGas(provider))

getGasPrice

A middleware function for getting the latest values for maxFeePerGas and maxPriorityFeePerGas.

import { Presets } from "userop";

// provider is an ethers.js JSON-RPC provider.
builder = builder.useMiddleware(Presets.Middleware.getGasPrice(provider))

verifyingPaymaster

A middleware function for requesting gas sponsorship from a Paymaster service. The middleware assumes that the service implements this proposed JSON-RPC API for verifying paymasters.

import { Presets } from "userop";

builder = builder.useMiddleware(
  Presets.Middleware.verifyingPaymaster(paymasterRpc, paymasterCtx)
)

EOASignature

A middleware function for signing the User Operation with an EOA private key.

import { ethers } from "ethers";
import { Presets } from "userop";

// signer is an ethers.js Wallet instance.
const signer = new ethers.Wallet(signingKey);
builder = builder.useMiddleware(Presets.Middleware.EOASignature(signer))