@owlprotocol/contracts-account-abstraction
Version:
ERC4337 Account Abstraction support for deploying relevant smart contracts and interacting with UserOps.
82 lines (73 loc) • 2.86 kB
text/typescript
import { Client, Transport, Hash } from "viem";
import {
entryPoint07Address,
GetUserOperationReceiptReturnType,
UserOperationReceiptNotFoundError,
} from "viem/account-abstraction";
import { getBlockNumber, getLogs, getTransactionReceipt } from "viem/actions";
import { getAction } from "viem/utils";
import { UserOperationEvent } from "../../artifacts/EntryPoint.js";
export async function getUserOperationReceipt(
client: Client<Transport>,
parameters: { hash: Hash },
): Promise<GetUserOperationReceiptReturnType> {
const { hash } = parameters;
const blockNumber = await getBlockNumber(client);
//TODO: Parametrize rpc max range
// Certain RPCs enforce a max block range
const rpcMaxRange = 90_000n;
// If rpcMaxRange is less blockNumber, set fromBlock to rpcMaxRange away from blockNumber
const fromBlock = rpcMaxRange < blockNumber ? blockNumber - rpcMaxRange : 0n;
const filterResult = await getAction(
client,
getLogs,
"getLogs",
)({
address: entryPoint07Address,
event: UserOperationEvent,
args: {
userOpHash: hash,
},
fromBlock,
toBlock: "latest",
strict: true,
});
const userOperationEvent = filterResult[0];
if (!userOperationEvent) throw new UserOperationReceiptNotFoundError({ hash });
// Get UserOp transaction receipt
const transactionHash = userOperationEvent.transactionHash;
const receipt = await getAction(client, getTransactionReceipt, "getTransactionReceipt")({ hash: transactionHash });
// Filter receipt logs
const logs = receipt.logs;
// Filters logs emitted for this UserOp
let startIndex = -1;
let endIndex = -1;
logs.forEach((log, index) => {
if (log.topics[0] === userOperationEvent.topics[0]) {
// Process UserOperationEvent
if (log.topics[1] === userOperationEvent.topics[1]) {
// It's our userOpHash. save as end of logs array
endIndex = index;
} else if (endIndex === -1) {
// Different hash. remember it as beginning index, but only if we didn't find our end index yet.
startIndex = index;
}
}
});
if (endIndex === -1) {
// Should not happen
throw new Error("fatal: no UserOperationEvent in logs");
}
const filteredLogs = logs.slice(startIndex + 1, endIndex);
return {
entryPoint: entryPoint07Address,
userOpHash: hash,
sender: userOperationEvent.args.sender,
nonce: userOperationEvent.args.nonce,
actualGasUsed: userOperationEvent.args.actualGasUsed,
actualGasCost: userOperationEvent.args.actualGasCost,
success: userOperationEvent.args.success,
receipt,
logs: filteredLogs,
};
}