Skip to main content

Utilities

A set of utilities for ERC-4337 Account Abstraction to help you with your development.

UserOperation utils

createUserOperationHash

Computes the hash of a UserOperation, which is used as the unique identifier for the operation on-chain.

example.ts
import { createUserOperationHash } from "abstractionkit";

const userOpHash = createUserOperationHash(
userOperation,
"0x0000000071727De22E5E9d8BAf0edAc6f37da032",
11155111n
);

Source code

createUserOperationHash

createPackedUserOperationV6

Encodes a UserOperationV6 into its packed ABI representation, suitable for hashing or on-chain verification.

example.ts
import { createPackedUserOperationV6 } from "abstractionkit";

const packed = createPackedUserOperationV6(userOperationV6);

Source code

createPackedUserOperationV6

createPackedUserOperationV7

Encodes a UserOperationV7 into its packed ABI representation, suitable for hashing or on-chain verification.

example.ts
import { createPackedUserOperationV7 } from "abstractionkit";

const packed = createPackedUserOperationV7(userOperationV7);

Source code

createPackedUserOperationV7

fetchAccountNonce

Fetches the current nonce for a smart account from the EntryPoint. Accepts an optional key parameter (default 0) that enables parallel nonce channels, allowing multiple independent UserOperations to be submitted concurrently.

example.ts
import { fetchAccountNonce } from "abstractionkit";

const nonce = await fetchAccountNonce(
"https://ethereum-sepolia-rpc.publicnode.com",
"0x0000000071727De22E5E9d8BAf0edAc6f37da032",
"0xYourSmartAccountAddress"
);

Source code

fetchAccountNonce

calculateUserOperationMaxGasCost

Calculates the maximum possible gas cost (in wei) for a UserOperation based on its gas limits and fee parameters.

example.ts
import { calculateUserOperationMaxGasCost } from "abstractionkit";

const maxCost = calculateUserOperationMaxGasCost(userOperation);

Source code

calculateUserOperationMaxGasCost

JsonRpcNode

JsonRpcNode wraps common Ethereum node calls behind the same Transport abstraction used by Bundler and Paymaster services. Use it for node reads instead of the removed top-level URL helpers fetchGasPrice, getBalanceOf, getDepositInfo, and getDelegatedAddress.

example.ts
import { GasOption, JsonRpcNode } from "abstractionkit";

const node = new JsonRpcNode("https://ethereum-sepolia-rpc.publicnode.com");

const [maxFeePerGas, maxPriorityFeePerGas] = await node.getFeeData(GasOption.Medium);
const deposit = await node.getEntryPointDeposit(
"0xYourAccountAddress",
"0x0000000071727De22E5E9d8BAf0edAc6f37da032",
);
const depositInfo = await node.getEntryPointDepositInfo(
"0xYourAccountAddress",
"0x0000000071727De22E5E9d8BAf0edAc6f37da032",
);
const delegatee = await node.getDelegatedAddress("0xYourEOAAddress");

Methods

  • chainId()
  • blockNumber()
  • getCode(address)
  • call(transaction)
  • getTransactionCount(address)
  • getFeeData(gasOption?)
  • getDelegatedAddress(eoaAddress)
  • getEntryPointNonce(entryPoint, account, key?)
  • getEntryPointDeposit(address, entryPoint)
  • getEntryPointDepositInfo(address, entryPoint)
  • request(args, options?)

Source code

JsonRpcNode

getBalanceOf

Deprecated in v0.3.8. Use JsonRpcNode#getEntryPointDeposit instead.

migration.ts
import { JsonRpcNode } from "abstractionkit";

const node = new JsonRpcNode("https://ethereum-sepolia-rpc.publicnode.com");
const balance = await node.getEntryPointDeposit(
"0xYourAccountAddress",
"0x0000000071727De22E5E9d8BAf0edAc6f37da032",
);

getDepositInfo

Deprecated in v0.3.8. Use JsonRpcNode#getEntryPointDepositInfo instead.

migration.ts
import { JsonRpcNode } from "abstractionkit";

const node = new JsonRpcNode("https://ethereum-sepolia-rpc.publicnode.com");
const info = await node.getEntryPointDepositInfo(
"0xYourAccountAddress",
"0x0000000071727De22E5E9d8BAf0edAc6f37da032",
);

getStorageAt

Reads the 32-byte storage word at a given slot via eth_getStorageAt.

example.ts
import { JsonRpcNode, SAFE_FALLBACK_HANDLER_STORAGE_SLOT } from "abstractionkit";

const node = new JsonRpcNode("https://ethereum-sepolia-rpc.publicnode.com");
const word = await node.getStorageAt(
"0xYourAccountAddress",
SAFE_FALLBACK_HANDLER_STORAGE_SLOT,
);

Source code

getStorageAt

Simulation utils

Simulates a UserOperation via the EntryPoint's handleOps on Tenderly and returns a shareable dashboard link.

example.ts
import { simulateUserOperationWithTenderlyAndCreateShareLink } from "abstractionkit";

const { simulation, simulationShareLink } =
await simulateUserOperationWithTenderlyAndCreateShareLink(
"my-account",
"my-project",
"my-access-key",
11155111n,
"0x0000000071727De22E5E9d8BAf0edAc6f37da032",
userOperation
);

Source code

simulateUserOperationWithTenderlyAndCreateShareLink

Simulates UserOperation callData with Tenderly and returns shareable links. Unlike simulateUserOperationWithTenderlyAndCreateShareLink, this simulates the inner call data rather than the full EntryPoint handleOps flow.

example.ts
import { simulateUserOperationCallDataWithTenderlyAndCreateShareLink } from "abstractionkit";

const { simulation, callDataSimulationShareLink } =
await simulateUserOperationCallDataWithTenderlyAndCreateShareLink(
"my-account",
"my-project",
"my-access-key",
11155111n,
"0x0000000071727De22E5E9d8BAf0edAc6f37da032",
userOperation
);

Source code

simulateUserOperationCallDataWithTenderlyAndCreateShareLink

Simulates sender callData directly with Tenderly and returns shareable links. Useful for simulating the execution of callData from a specific sender address without wrapping it in a full UserOperation.

example.ts
import { simulateSenderCallDataWithTenderlyAndCreateShareLink } from "abstractionkit";

const { simulation, callDataSimulationShareLink } =
await simulateSenderCallDataWithTenderlyAndCreateShareLink(
"my-account",
"my-project",
"my-access-key",
11155111n,
"0x0000000071727De22E5E9d8BAf0edAc6f37da032",
"0xSenderAddress",
"0xCallData"
);

Source code

simulateSenderCallDataWithTenderlyAndCreateShareLink

Multicall utils

encodeMultiSendCallData

Encodes an array of MetaTransactions into a single callData payload for the MultiSend contract.

example.ts
import { encodeMultiSendCallData } from "abstractionkit";

const callData = encodeMultiSendCallData([
{
to: "0xTokenAddress",
value: 0n,
data: "0xTransferCallData",
operation: 0,
},
{
to: "0xAnotherContract",
value: 0n,
data: "0xAnotherCallData",
operation: 0,
},
]);

Source code

encodeMultiSendCallData

decodeMultiSendCallData

Decodes encoded MultiSend callData back into a readable representation.

example.ts
import { decodeMultiSendCallData } from "abstractionkit";

const decoded = decodeMultiSendCallData(encodedCallData);

Source code

decodeMultiSendCallData

Generic Ethereum utils

fetchGasPrice

Deprecated in v0.3.8. Use JsonRpcNode#getFeeData instead.

migration.ts
import { GasOption, JsonRpcNode } from "abstractionkit";

const node = new JsonRpcNode("https://ethereum-sepolia-rpc.publicnode.com");
const [maxFeePerGas, maxPriorityFeePerGas] = await node.getFeeData(GasOption.Medium);

createCallData

Encodes a function call into ABI-encoded call data by combining a function selector with its encoded parameters.

example.ts
import { createCallData } from "abstractionkit";

const callData = createCallData(
"0xa9059cbb", // transfer(address,uint256) selector
["address", "uint256"],
["0xRecipientAddress", 1000000n]
);

Source code

createCallData

getFunctionSelector

Computes the 4-byte function selector from a Solidity function signature string.

example.ts
import { getFunctionSelector } from "abstractionkit";

const selector = getFunctionSelector("transfer(address,uint256)");
// Returns "0xa9059cbb"

Source code

getFunctionSelector

sendJsonRpcRequest

Sends a JSON-RPC request to the given URL. Accepts optional headers (defaults to {"Content-Type": "application/json"}) and an optional paramsKeyName for non-standard JSON-RPC endpoints.

example.ts
import { sendJsonRpcRequest } from "abstractionkit";

const result = await sendJsonRpcRequest(
"https://ethereum-sepolia-rpc.publicnode.com",
"eth_blockNumber",
[]
);

Source code

sendJsonRpcRequest

sendEthCallRequest

Deprecated in v0.3.8. Use JsonRpcNode#call instead.

example.ts
import { JsonRpcNode } from "abstractionkit";

const node = new JsonRpcNode("https://ethereum-sepolia-rpc.publicnode.com");
const result = await node.call({
to: "0xContractAddress",
data: "0xCallData",
});

Source code

JsonRpcNode.call

sendEthGetCodeRequest

Deprecated in v0.3.8. Use JsonRpcNode#getCode instead.

example.ts
import { JsonRpcNode } from "abstractionkit";

const node = new JsonRpcNode("https://ethereum-sepolia-rpc.publicnode.com");
const code = await node.getCode("0xContractAddress");

Source code

JsonRpcNode.getCode

getDelegatedAddress

Deprecated in v0.3.8. Use JsonRpcNode#getDelegatedAddress instead.

migration.ts
import { JsonRpcNode } from "abstractionkit";

const node = new JsonRpcNode("https://ethereum-sepolia-rpc.publicnode.com");
const delegatee = await node.getDelegatedAddress("0xYourEOAAddress");

if (delegatee) {
console.log("Delegated to:", delegatee);
} else {
console.log("Not delegated");
}

Error and revert decoding

decodeUserOperationRevertReason

Reads the EntryPoint's UserOperationRevertReason log directly from a mined receipt and returns the decoded reason, with no extra RPC call. The result is matched to the receipt's userOpHash, so a multi-op bundle returns the right entry. The reason is an Error string, a Panic code, or empty when the inner call left no revert data (usually out-of-gas).

example.ts
import { decodeUserOperationRevertReason } from "abstractionkit";

const receipt = await response.included();
const revert = decodeUserOperationRevertReason(receipt);

if (revert.reverted) {
console.log(revert.errorMessage ?? revert.panicCode ?? "out of gas");
}

Source code

decodeUserOperationRevertReason

parseAaCode

Parses an EntryPoint AAxx revert code (e.g. AA21) out of an error message, so you can branch on a stable contract-defined code instead of matching message text. When a UserOperation fails, AbstractionKit also surfaces this code directly on AbstractionKitError.aaCode, so most callers can read error.aaCode without calling parseAaCode themselves.

example.ts
import { parseAaCode } from "abstractionkit";

try {
await smartAccount.sendUserOperation(userOperation, bundlerUrl);
} catch (error) {
// Read the code straight off the error...
if (error.aaCode === "AA21") {
// account did not pay the prefund
}
// ...or parse it from any message string
const code = parseAaCode(error.message);
}

Source code

parseAaCode

EIP-7702 Utilities

createAndSignEip7702DelegationAuthorization

Creates and signs an EIP-7702 delegation authorization, allowing an EOA to delegate its code to a specified contract address. Accepts either a hex-encoded private key string for synchronous signing, or an async signer callback (hash: string) => Promise<string> for use with viem, ethers Signers, hardware wallets, or MPC signers.

example.ts
import { createAndSignEip7702DelegationAuthorization } from "abstractionkit";

// With a private key (synchronous)
const authorization = createAndSignEip7702DelegationAuthorization(
11155111n,
"0xDelegateeContractAddress",
0n,
"0xYourPrivateKey"
);

// With an async signer callback
const authorization = await createAndSignEip7702DelegationAuthorization(
11155111n,
"0xDelegateeContractAddress",
0n,
async (hash) => {
// Sign the hash using your preferred method
return await wallet.signMessage(hash);
}
);

Source code

createAndSignEip7702DelegationAuthorization

createRevokeDelegationAuthorization

Creates a signed authorization that revokes an existing EIP-7702 delegation by setting the delegatee address to the zero address, restoring the EOA to a normal account.

example.ts
import { createRevokeDelegationAuthorization } from "abstractionkit";

const revokeAuth = createRevokeDelegationAuthorization(
11155111n,
0n,
"0xYourPrivateKey"
);

Source code

createRevokeDelegationAuthorization

createEip7702DelegationAuthorizationHash

Computes the keccak256 hash of an EIP-7702 delegation authorization using the MAGIC prefix (0x05) as defined in the EIP-7702 spec. Useful when signing the authorization externally.

example.ts
import { createEip7702DelegationAuthorizationHash } from "abstractionkit";

const hash = createEip7702DelegationAuthorizationHash(
11155111n,
"0xDelegateeContractAddress",
0n
);

Source code

createEip7702DelegationAuthorizationHash

createAndSignEip7702RawTransaction

Creates and signs a raw EIP-7702 (set-code, type 0x04) transaction with an authorization list. The transaction is RLP-encoded and includes the type prefix, ready for eth_sendRawTransaction.

example.ts
import { createAndSignEip7702RawTransaction } from "abstractionkit";

const rawTx = createAndSignEip7702RawTransaction(
11155111n, // chainId
0n, // nonce
2000000000n, // maxPriorityFeePerGas
20000000000n, // maxFeePerGas
21000n, // gasLimit
"0xDestination", // destination
0n, // value
"0x", // data
[], // accessList
[authorization], // authorizationList
"0xYourPrivateKey"
);

Source code

createAndSignEip7702RawTransaction

createEip7702TransactionHash

Computes the keccak256 hash of an EIP-7702 transaction for signing purposes, using the type 0x04 prefix and RLP encoding.

example.ts
import { createEip7702TransactionHash } from "abstractionkit";

const txHash = createEip7702TransactionHash(
11155111n, // chainId
0n, // nonce
2000000000n, // maxPriorityFeePerGas
20000000000n, // maxFeePerGas
21000n, // gasLimit
"0xDestination", // destination
0n, // value
"0x", // data
[], // accessList
[authorization] // authorizationList
);

Source code

createEip7702TransactionHash