From 6f9852773b093d7ff49dc5c26b7e36746daeb31d Mon Sep 17 00:00:00 2001 From: mouseless <97399882+mouseless-eth@users.noreply.github.com> Date: Wed, 29 May 2024 21:35:22 +0100 Subject: [PATCH] fix kinto e2e tests --- src/executor/utils.ts | 7 +++- test/kinto-e2e/src/index.ts | 70 +++++++++++++++++++-------------- test/kinto-e2e/src/setupAlto.ts | 13 ++++-- test/kinto-e2e/src/utils.ts | 21 +++++++++- 4 files changed, 75 insertions(+), 36 deletions(-) diff --git a/src/executor/utils.ts b/src/executor/utils.ts index 62dc5f7a..1504b776 100644 --- a/src/executor/utils.ts +++ b/src/executor/utils.ts @@ -39,7 +39,8 @@ import { hexToBytes, numberToHex, formatTransactionRequest, - RpcRequestError + RpcRequestError, + hexToBigInt } from "viem" export function simulatedOpsToResults( @@ -203,10 +204,12 @@ export async function filterOpsAndEstimateGas( ...gasOptions }) - gasLimit = await publicClient.request({ + const rpcResponse = await publicClient.request({ method: "eth_estimateGas", params: [tx, blockTag] }) + + gasLimit = hexToBigInt(rpcResponse) } return { simulatedOps, gasLimit, resubmitAllOps: false } diff --git a/test/kinto-e2e/src/index.ts b/test/kinto-e2e/src/index.ts index 3b06d7d7..a5a115ab 100644 --- a/test/kinto-e2e/src/index.ts +++ b/test/kinto-e2e/src/index.ts @@ -1,5 +1,4 @@ import { - type Address, type Hex, createPublicClient, decodeEventLog, @@ -7,9 +6,10 @@ import { http, parseAbi, parseAbiItem, - getAddress + slice, + hexToNumber } from "viem" -import { BundleBulkerAbi, handleOpsAbi } from "./abi" +import { handleOpsAbi } from "./abi" import { type Pool, createPool } from "@viem/anvil" import type { UserOperation } from "permissionless" import { createPimlicoBundlerClient } from "permissionless/clients/pimlico" @@ -18,22 +18,13 @@ import { KINTO_ENTRYPOINT, kintoMainnet, prettyPrintTxHash, - sleep + sleep, + type OpInfoType, + type CompressedOp, + isCompressed } from "./utils" import { startAlto } from "./setupAlto" -type CompressedOp = { - compressedBytes: Hex - inflator: Address -} - -type OpInfoType = { - opHash: Hex - txHash: Hex - blockNum: bigint - opParams: UserOperation | CompressedOp -} - const canReplayUserOperation = async ({ anvilPool, anvilId, @@ -57,7 +48,11 @@ const canReplayUserOperation = async ({ const anvilRpc = `http://${anvil.host}:${anvil.port}` // spin up new alto instance - const altoProcess = await startAlto(anvilRpc, altoPort.toString()) + const altoProcess = await startAlto( + anvilRpc, + altoPort.toString(), + "inflator" in opInfo.opParams + ) // resend userOperation and that it gets mined const bundlerClient = createPimlicoBundlerClient({ @@ -65,7 +60,8 @@ const canReplayUserOperation = async ({ }) let hash: Hex - if ("inflator" in opParams) { + if (isCompressed(opParams)) { + console.log("sending compressed UserOperation") hash = await bundlerClient.sendCompressedUserOperation({ compressedUserOperation: opParams.compressedBytes, inflatorAddress: opParams.inflator, @@ -122,7 +118,8 @@ const main = async () => { let userOperationEvents = await publicClient.getLogs({ address: KINTO_ENTRYPOINT, event: parseAbiItem(userOperationEventAbi), - fromBlock: latestBlock - 10_000n + fromBlock: latestBlock - 10_000n, + toBlock: latestBlock }) userOperationEvents = userOperationEvents.reverse() @@ -163,15 +160,24 @@ const main = async () => { data: rawTx.input }).args[0][0] } catch { - const compressedBytes = decodeFunctionData({ - abi: BundleBulkerAbi, - data: rawTx.input - }).args[0] + // Extract first compressedUserOperation (compressedBytes) + // slice of 9 bytes: + // - 4 Bytes BundleBulker Payload (PerOpInflator Id) + // - 1 Bytes PerOpInflator Payload (number of ops) + // - 4 Bytes PerOpInflator Payload (inflator id) + const bytes = slice(rawTx.input, 9, undefined) + + const compressedLength = hexToNumber(slice(bytes, 0, 2)) + + const compressedBytes = slice( + bytes, + 2, + 2 + compressedLength + ) + opParams = { compressedBytes, - inflator: getAddress( - "0x336a76a7A2a1e97CE20c420F39FC08c441234aa2" - ) + inflator: "0x336a76a7A2a1e97CE20c420F39FC08c441234aa2" } } @@ -229,7 +235,7 @@ const main = async () => { const endTime = performance.now() const elapsedTime = (endTime - startTime) / 1000 - // biome-ignore lint/suspicious/noConsoleLog: + // biome-ignore lint/suspicious/noConsoleLog: console.log( `Processed ${processed}/${totalOps} operations. (processed in ${elapsedTime.toFixed( 2 @@ -240,11 +246,15 @@ const main = async () => { // if any ops failed, print them and exit with 1 if (failedOps.length > 0) { for (const f of failedOps) { + let opType = "uncompressed" + if (isCompressed(f.opParams)) { + opType = "compressed" + } // biome-ignore lint/suspicious/noConsoleLog: console.log( - `FAILED OP: ${f.opHash} (txhash: ${prettyPrintTxHash( - f.txHash - )})` + `[${opType}] FAILED OP: ${ + f.opHash + } (txhash: ${prettyPrintTxHash(f.txHash)})` ) } process.exit(1) diff --git a/test/kinto-e2e/src/setupAlto.ts b/test/kinto-e2e/src/setupAlto.ts index ad231480..3e650c2b 100644 --- a/test/kinto-e2e/src/setupAlto.ts +++ b/test/kinto-e2e/src/setupAlto.ts @@ -5,7 +5,11 @@ import waitPort from "wait-port" import { sleep } from "./utils" // skip docker wait times, just start locally -export const startAlto = async (rpc: string, altoPort: string) => { +export const startAlto = async ( + rpc: string, + altoPort: string, + print?: boolean +) => { const anvil = createTestClient({ transport: http(rpc), mode: "anvil" @@ -46,9 +50,12 @@ export const startAlto = async (rpc: string, altoPort: string) => { const alto = spawn(command, args, options) + if (print) { + alto.stdout.on("data", (data) => console.log(data.toString())) + alto.stderr.on("data", (data) => console.log(data.toString())) + } + // [USE FOR DEBUGGING] - //alto.stdout.on("data", (data) => console.log(data.toString())) - //alto.stderr.on("data", (data) => console.log(data.toString())) await waitPort({ host: "127.0.0.1", diff --git a/test/kinto-e2e/src/utils.ts b/test/kinto-e2e/src/utils.ts index f75b052a..05b26adf 100644 --- a/test/kinto-e2e/src/utils.ts +++ b/test/kinto-e2e/src/utils.ts @@ -1,9 +1,28 @@ -import { defineChain, type Hash } from "viem" +import type { UserOperation } from "permissionless" +import { defineChain, type Hex, type Hash, type Address } from "viem" export const prettyPrintTxHash = (hash: Hash) => { return `https://kintoscan.io/tx/${hash}` } +export type CompressedOp = { + compressedBytes: Hex + inflator: Address +} + +export type OpInfoType = { + opHash: Hex + txHash: Hex + blockNum: bigint + opParams: UserOperation | CompressedOp +} + +export const isCompressed = ( + op: UserOperation | CompressedOp +): op is CompressedOp => { + return "inflator" in op +} + export const kintoMainnet = defineChain({ id: 7887, name: "Kinto Mainnet",