Common Hooks

A reference to preset hook functions for an Account to call into when building UserOperations.

As briefly mentioned in the Quickstart guide, every User Operation typically follows the same high level steps during its build lifecycle. When configuring Account Options, we can implement these hook functions to return the relevant value for each area of a User Operation that is suited for a particular Smart Account implementation.

For V06, these hooks include:

HookDescription
setFactoryDataValue used to generate initCode and derive sender address.
requestSignatureDirectly used to set the signature field.
requestGasPriceDirectly used to set the maxFeePerGas and maxPriorityFeePerGas.
requestGasValuesDirectly used to set preVerificationGas, verificationGasLimit, and callGasLimit.
requestPaymasterDirectly used to set paymasterAndData and other other optional field required by the paymaster.
onBuildCalled once the final User Operation has been built.

There are certain use cases where a single hook can be reused in many different implementations. For these cases we package them up in the presets detailed below.

RequestSignature

These preset hooks are available for common signature use cases.

withViemWalletClient

Uses the signMessage function on a given viem WalletClient to create a User Operation signature.

import { V06 } from "userop";

const account = new V06.Account.Instance({
  // Account opts...
  
  requestSignature: V06.Account.Hooks.RequestSignature.withViemWalletClient(
    viemWalletClient,
    // Pass viem Account if not yet hoisted in the WalletClient
  ),
})

withEthersSigner

Uses the signMessage function on a given ethers.js Signer to create a User Operation signature.

import { V06 } from "userop";

const account = new V06.Account.Instance({
  // Account opts...
  
  requestSignature: V06.Account.Hooks.RequestSignature.withEthersSigner(ethersSigner),
})

RequestGasPrice

These preset hooks are available for common gas fee logic.

withEthClient

Uses an instance of a viem PublicClient or ethers.js JsonRpcProvider to fetch the latest gas prices. This hook will attempt to set EIP-1559 gas prices using the given heuristics:

const maxFeePerGas = currentBlockBaseFee * 2 + maxPriorityFeePerGas

The currentBlockBaseFee is derived from eth_getBlockByNumber and maxPriorityFeePerGas from eth_maxPriorityFeePerGas. The priority fee allows for timely inclusion while the max fee allows for the User Operation to be marketable longer in case of spikes in network activity. If the network does not support EIP-1559, it will fallback to legacy gas prices with eth_gasPrice.

This is the default gas price hook used by an Account instance.

import { V06 } from "userop";

const account = new V06.Account.Instance({
  // Account opts...
  
  requestGasPrice: V06.Account.Hooks.RequestGasPrice.withEthClient(
    viemPublicClient, // will also accept an ethers.js JsonRpcProvider
  ),
})

RequestGasValues

These preset hooks are available for common gas value logic.

withEthClient

Uses an instance of viem PublicClient or ethers.js JsonRpcProvider to estimate User Operation gas using the Bundler's eth_estimateUserOperationGas RPC method.

This is the default gas value hook used by an Account instance.

import { V06 } from "userop";

const account = new V06.Account.Instance({
  // Account opts...
  
  requestGasValues: V06.Account.Hooks.RequestGasValues.withEthClient(
    viemPublicClient, // will also accept an ethers.js JsonRpcProvider
  ),
})

RequestPaymaster

These preset hooks are available for common paymaster implementations.

withCommon

Given a PaymasterOpts, it will generate a User Operation with a Paymaster for gas abstraction.

Configuring this hook will depend on the underlying Paymaster used.

import { V06 } from "userop";

const account = new V06.Account.Instance({
  // Account opts...
  
  requestPaymaster: V06.Account.Hooks.RequestPaymaster.withCommon({
    variant: "stackupV1",
    parameters: {
      rpcUrl: STACKUP_V1_PM_RPC,
      type: "payg",
      },
  }),
})
import { V06 } from "userop";

const account = new V06.Account.Instance({
  // Account opts...
  
  requestPaymaster: V06.Account.Hooks.RequestPaymaster.withCommon({
    variant: "stackupV1",
    parameters: {
      rpcUrl: STACKUP_V1_PM_RPC,
      type: "erc20token",
      token: TOKEN_ADDRESS,
      },
  }),
})