UNPKG

@alchemy/aa-core

Version:

viem based SDK that enables interactions with ERC-4337 Smart Accounts. ABIs are based off the definitions generated in @account-abstraction/contracts

154 lines (140 loc) 3.67 kB
import { concat, encodeAbiParameters, hexToBigInt, isAddress, keccak256, pad, type Address, type Chain, type Hash, type Hex, } from "viem"; import { EntryPointAbi_v7 } from "../abis/EntryPointAbi_v7.js"; import type { UserOperationRequest, UserOperationRequest_v7, } from "../types.js"; import type { SupportedEntryPoint } from "./types.js"; const packUserOperation = (request: UserOperationRequest<"0.7.0">): Hex => { const initCode = request.factory && request.factoryData ? concat([request.factory, request.factoryData]) : "0x"; const accountGasLimits = packAccountGasLimits( (({ verificationGasLimit, callGasLimit }) => ({ verificationGasLimit, callGasLimit, }))(request) ); const gasFees = packAccountGasLimits( (({ maxPriorityFeePerGas, maxFeePerGas }) => ({ maxPriorityFeePerGas, maxFeePerGas, }))(request) ); const paymasterAndData = request.paymaster && isAddress(request.paymaster) ? packPaymasterData( (({ paymaster, paymasterVerificationGasLimit, paymasterPostOpGasLimit, paymasterData, }) => ({ paymaster, paymasterVerificationGasLimit, paymasterPostOpGasLimit, paymasterData, }))(request) ) : "0x"; return encodeAbiParameters( [ { type: "address" }, { type: "uint256" }, { type: "bytes32" }, { type: "bytes32" }, { type: "bytes32" }, { type: "uint256" }, { type: "bytes32" }, { type: "bytes32" }, ], [ request.sender as Address, hexToBigInt(request.nonce), keccak256(initCode), keccak256(request.callData), accountGasLimits, hexToBigInt(request.preVerificationGas), gasFees, keccak256(paymasterAndData), ] ); }; export default { version: "0.7.0", address: { default: "0x0000000071727De22E5E9d8BAf0edAc6f37da032", }, abi: EntryPointAbi_v7, getUserOperationHash: ( request: UserOperationRequest<"0.7.0">, entryPointAddress: Address, chainId: number ): Hash => { const encoded = encodeAbiParameters( [{ type: "bytes32" }, { type: "address" }, { type: "uint256" }], [ keccak256(packUserOperation(request)), entryPointAddress, BigInt(chainId), ] ); return keccak256(encoded); }, packUserOperation, } satisfies SupportedEntryPoint<"0.7.0", Chain, typeof EntryPointAbi_v7>; export function packAccountGasLimits( data: | Pick<UserOperationRequest_v7, "verificationGasLimit" | "callGasLimit"> | Pick<UserOperationRequest_v7, "maxPriorityFeePerGas" | "maxFeePerGas"> ): Hex { return concat(Object.values(data).map((v) => pad(v, { size: 16 }))); } export function packPaymasterData({ paymaster, paymasterVerificationGasLimit, paymasterPostOpGasLimit, paymasterData, }: Pick< UserOperationRequest_v7, | "paymaster" | "paymasterVerificationGasLimit" | "paymasterPostOpGasLimit" | "paymasterData" >): Hex { if ( !paymaster || !paymasterVerificationGasLimit || !paymasterPostOpGasLimit || !paymasterData ) { return "0x"; } return concat([ paymaster, pad(paymasterVerificationGasLimit, { size: 16 }), pad(paymasterPostOpGasLimit, { size: 16 }), paymasterData, ]); } export function unpackAccountGasLimits(accountGasLimits: string): { verificationGasLimit: number; callGasLimit: number; } { return { verificationGasLimit: parseInt(accountGasLimits.slice(2, 34), 16), callGasLimit: parseInt(accountGasLimits.slice(34), 16), }; }