From 5dceecaa9254c9d02f568100c01c9b0330dbc8fa Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Fri, 8 Nov 2024 16:25:49 +0000 Subject: [PATCH 1/7] Use custom contract that doesn't revert to get sender address --- .../actions/public/getSenderAddress.ts | 219 ++++-------------- 1 file changed, 43 insertions(+), 176 deletions(-) diff --git a/packages/permissionless/actions/public/getSenderAddress.ts b/packages/permissionless/actions/public/getSenderAddress.ts index d5d1c881..694e4e47 100644 --- a/packages/permissionless/actions/public/getSenderAddress.ts +++ b/packages/permissionless/actions/public/getSenderAddress.ts @@ -12,12 +12,37 @@ import { RpcRequestError, UnknownRpcError, concat, - decodeErrorResult + decodeErrorResult, + encodeDeployData, + getAddress } from "viem" -import { simulateContract } from "viem/actions" +import { call, simulateContract } from "viem/actions" import { getAction } from "viem/utils" +// https://github.com/pimlicolabs/entrypoint-estimations/blob/main/src/GetSenderAddressHelper.sol +const GetSenderAddressHelperByteCode = + "0x608060405260405161058a38038061058a83398181016040528101906100259190610341565b5f808373ffffffffffffffffffffffffffffffffffffffff16639b249f6960e01b8460405160240161005791906103ed565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516100c19190610447565b5f604051808303815f865af19150503d805f81146100fa576040519150601f19603f3d011682016040523d82523d5f602084013e6100ff565b606091505b50915091505f8261015f576004825111156101245760248201519050805f526014600cf35b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610156906104dd565b60405180910390fd5b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101919061056b565b60405180910390fd5b5f604051905090565b5f80fd5b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6101d4826101ab565b9050919050565b6101e4816101ca565b81146101ee575f80fd5b50565b5f815190506101ff816101db565b92915050565b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6102538261020d565b810181811067ffffffffffffffff821117156102725761027161021d565b5b80604052505050565b5f61028461019a565b9050610290828261024a565b919050565b5f67ffffffffffffffff8211156102af576102ae61021d565b5b6102b88261020d565b9050602081019050919050565b8281835e5f83830152505050565b5f6102e56102e084610295565b61027b565b90508281526020810184848401111561030157610300610209565b5b61030c8482856102c5565b509392505050565b5f82601f83011261032857610327610205565b5b81516103388482602086016102d3565b91505092915050565b5f8060408385031215610357576103566101a3565b5b5f610364858286016101f1565b925050602083015167ffffffffffffffff811115610385576103846101a7565b5b61039185828601610314565b9150509250929050565b5f81519050919050565b5f82825260208201905092915050565b5f6103bf8261039b565b6103c981856103a5565b93506103d98185602086016102c5565b6103e28161020d565b840191505092915050565b5f6020820190508181035f83015261040581846103b5565b905092915050565b5f81905092915050565b5f6104218261039b565b61042b818561040d565b935061043b8185602086016102c5565b80840191505092915050565b5f6104528284610417565b915081905092915050565b5f82825260208201905092915050565b7f67657453656e64657241646472657373206661696c656420776974686f7574205f8201527f6461746100000000000000000000000000000000000000000000000000000000602082015250565b5f6104c760248361045d565b91506104d28261046d565b604082019050919050565b5f6020820190508181035f8301526104f4816104bb565b9050919050565b7f67657453656e6465724164647265737320646964206e6f7420726576657274205f8201527f6173206578706563746564000000000000000000000000000000000000000000602082015250565b5f610555602b8361045d565b9150610560826104fb565b604082019050919050565b5f6020820190508181035f83015261058281610549565b905091905056fe" + +const GetSenderAddressHelperAbi = [ + { + inputs: [ + { + internalType: "address", + name: "_entryPoint", + type: "address" + }, + { + internalType: "bytes", + name: "initCode", + type: "bytes" + } + ], + stateMutability: "payable", + type: "constructor" + } +] + export type GetSenderAddressParams = OneOf< | { initCode: Hex @@ -88,186 +113,28 @@ export const getSenderAddress = async ( ) } + const formattedInitCode = + initCode || concat([factory as Hex, factoryData as Hex]) + try { - await getAction( + const { data } = await getAction( client, - simulateContract, - "simulateContract" + call, + "call" )({ - address: entryPointAddress, - abi: [ - { - inputs: [ - { - internalType: "address", - name: "sender", - type: "address" - } - ], - name: "SenderAddressResult", - type: "error" - }, - { - inputs: [ - { - internalType: "bytes", - name: "initCode", - type: "bytes" - } - ], - name: "getSenderAddress", - outputs: [], - stateMutability: "nonpayable", - type: "function" - } - ], - functionName: "getSenderAddress", - args: [initCode || concat([factory as Hex, factoryData as Hex])] - }) - } catch (e) { - const revertError = (e as ContractFunctionExecutionErrorType).walk( - (err) => - err instanceof ContractFunctionRevertedError || - err instanceof RpcRequestError || - err instanceof InvalidInputRpcError || - err instanceof UnknownRpcError - ) - - if (!revertError) { - const cause = (e as ContractFunctionExecutionErrorType).cause as any - const errorName = cause?.data?.errorName ?? "" - if ( - errorName === "SenderAddressResult" && - cause?.data?.args && - cause?.data?.args[0] - ) { - return cause.data?.args[0] as Address - } - } - - if (revertError instanceof ContractFunctionRevertedError) { - const errorName = revertError.data?.errorName ?? "" - if ( - errorName === "SenderAddressResult" && - revertError.data?.args && - revertError.data?.args[0] - ) { - return revertError.data?.args[0] as Address - } - } - - if (revertError instanceof RpcRequestError) { - const hexStringRegex = /0x[a-fA-F0-9]+/ - // biome-ignore lint/suspicious/noExplicitAny: - const match = (revertError as unknown as any).cause.data.match( - hexStringRegex - ) - - if (!match) { - throw new Error( - "Failed to parse revert bytes from RPC response" - ) - } - - const data: Hex = match[0] - - const error = decodeErrorResult({ - abi: [ - { - inputs: [ - { - internalType: "address", - name: "sender", - type: "address" - } - ], - name: "SenderAddressResult", - type: "error" - } - ], - data - }) - - return error.args[0] as Address - } - - if (revertError instanceof InvalidInputRpcError) { - const { data: data_ } = ( - e instanceof RawContractError - ? e - : e instanceof BaseError - ? e.walk((err) => "data" in (err as Error)) || e.walk() - : {} - ) as RawContractError - - const data = typeof data_ === "string" ? data_ : data_?.data - - if (data === undefined) { - throw new Error( - "Failed to parse revert bytes from RPC response" - ) - } - - const error = decodeErrorResult({ - abi: [ - { - inputs: [ - { - internalType: "address", - name: "sender", - type: "address" - } - ], - name: "SenderAddressResult", - type: "error" - } - ], - data - }) - - return error.args[0] as Address - } - - if (revertError instanceof UnknownRpcError) { - const parsedBody = JSON.parse( - // biome-ignore lint/suspicious/noExplicitAny: - (revertError as unknown as any).cause.body - ) - const revertData = parsedBody.error.data - - const hexStringRegex = /0x[a-fA-F0-9]+/ - const match = revertData.match(hexStringRegex) - - if (!match) { - throw new Error( - "Failed to parse revert bytes from RPC response" - ) - } - - const data: Hex = match[0] - - const error = decodeErrorResult({ - abi: [ - { - inputs: [ - { - internalType: "address", - name: "sender", - type: "address" - } - ], - name: "SenderAddressResult", - type: "error" - } - ], - data + data: encodeDeployData({ + abi: GetSenderAddressHelperAbi, + bytecode: GetSenderAddressHelperByteCode, + args: [args.entryPointAddress, formattedInitCode] }) + }) - return error.args[0] as Address + if (!data) { + throw new Error("Failed to get sender address") } - throw e + return getAddress(data) + } catch (e) { + throw new InvalidEntryPointError({ entryPointAddress }) } - - throw new InvalidEntryPointError({ entryPointAddress }) } From a582a3e5857fc011ed6891bb8f7d23a90247c67c Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Fri, 8 Nov 2024 16:37:54 +0000 Subject: [PATCH 2/7] fix build --- .../permissionless/actions/public/getSenderAddress.ts | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/packages/permissionless/actions/public/getSenderAddress.ts b/packages/permissionless/actions/public/getSenderAddress.ts index 694e4e47..3dc2bb8a 100644 --- a/packages/permissionless/actions/public/getSenderAddress.ts +++ b/packages/permissionless/actions/public/getSenderAddress.ts @@ -2,22 +2,15 @@ import { type Address, BaseError, type Client, - type ContractFunctionExecutionErrorType, - ContractFunctionRevertedError, type Hex, - InvalidInputRpcError, type OneOf, type Prettify, - RawContractError, - RpcRequestError, - UnknownRpcError, concat, - decodeErrorResult, encodeDeployData, getAddress } from "viem" -import { call, simulateContract } from "viem/actions" +import { call } from "viem/actions" import { getAction } from "viem/utils" // https://github.com/pimlicolabs/entrypoint-estimations/blob/main/src/GetSenderAddressHelper.sol From 22de50df7305dd59301e7b4511b63abffc857daa Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Fri, 8 Nov 2024 16:47:43 +0000 Subject: [PATCH 3/7] Add changeset --- .changeset/rotten-goats-draw.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/rotten-goats-draw.md diff --git a/.changeset/rotten-goats-draw.md b/.changeset/rotten-goats-draw.md new file mode 100644 index 00000000..6b59db12 --- /dev/null +++ b/.changeset/rotten-goats-draw.md @@ -0,0 +1,5 @@ +--- +"permissionless": patch +--- + +Improved `getSenderAddress` to avoid relying on EntryPoint reverts with RPC. From ce9a9aee0bff99e2a27c69640164d8f9a0dc3d4f Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Fri, 8 Nov 2024 17:06:58 +0000 Subject: [PATCH 4/7] remove unused variable --- packages/permissionless/actions/public/getSenderAddress.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/permissionless/actions/public/getSenderAddress.ts b/packages/permissionless/actions/public/getSenderAddress.ts index 3dc2bb8a..b152d92e 100644 --- a/packages/permissionless/actions/public/getSenderAddress.ts +++ b/packages/permissionless/actions/public/getSenderAddress.ts @@ -127,7 +127,7 @@ export const getSenderAddress = async ( } return getAddress(data) - } catch (e) { + } catch { throw new InvalidEntryPointError({ entryPointAddress }) } } From 64eaa8881f35dbcebbb0553eaacfde6dd7155745 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Fri, 8 Nov 2024 17:10:01 +0000 Subject: [PATCH 5/7] bubble up the error --- .../actions/public/getSenderAddress.ts | 32 ++++++++----------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/packages/permissionless/actions/public/getSenderAddress.ts b/packages/permissionless/actions/public/getSenderAddress.ts index b152d92e..228fbe3a 100644 --- a/packages/permissionless/actions/public/getSenderAddress.ts +++ b/packages/permissionless/actions/public/getSenderAddress.ts @@ -109,25 +109,21 @@ export const getSenderAddress = async ( const formattedInitCode = initCode || concat([factory as Hex, factoryData as Hex]) - try { - const { data } = await getAction( - client, - call, - "call" - )({ - data: encodeDeployData({ - abi: GetSenderAddressHelperAbi, - bytecode: GetSenderAddressHelperByteCode, - args: [args.entryPointAddress, formattedInitCode] - }) + const { data } = await getAction( + client, + call, + "call" + )({ + data: encodeDeployData({ + abi: GetSenderAddressHelperAbi, + bytecode: GetSenderAddressHelperByteCode, + args: [args.entryPointAddress, formattedInitCode] }) + }) - if (!data) { - throw new Error("Failed to get sender address") - } - - return getAddress(data) - } catch { - throw new InvalidEntryPointError({ entryPointAddress }) + if (!data) { + throw new Error("Failed to get sender address") } + + return getAddress(data) } From 27fc5b5ac4314696311075b226a2049835305f16 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Fri, 8 Nov 2024 17:11:59 +0000 Subject: [PATCH 6/7] fix build --- packages/permissionless/actions/public/getSenderAddress.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/permissionless/actions/public/getSenderAddress.ts b/packages/permissionless/actions/public/getSenderAddress.ts index 228fbe3a..1bdb9ee3 100644 --- a/packages/permissionless/actions/public/getSenderAddress.ts +++ b/packages/permissionless/actions/public/getSenderAddress.ts @@ -117,7 +117,7 @@ export const getSenderAddress = async ( data: encodeDeployData({ abi: GetSenderAddressHelperAbi, bytecode: GetSenderAddressHelperByteCode, - args: [args.entryPointAddress, formattedInitCode] + args: [entryPointAddress, formattedInitCode] }) }) From 822466d894e099216d34acb0c1e0dda4ea444d4d Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Fri, 8 Nov 2024 17:22:15 +0000 Subject: [PATCH 7/7] fix test --- packages/permissionless/actions/public/getSenderAddress.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/permissionless/actions/public/getSenderAddress.test.ts b/packages/permissionless/actions/public/getSenderAddress.test.ts index 762aa082..956b9671 100644 --- a/packages/permissionless/actions/public/getSenderAddress.test.ts +++ b/packages/permissionless/actions/public/getSenderAddress.test.ts @@ -78,7 +78,7 @@ describe("getSenderAddress", () => { entryPointAddress: "0x0000000000000000000000000000000000000000", initCode: concatHex([factory, factoryData]) }) - ).rejects.toThrowError(/not a valid entry point/) + ).rejects.toThrowError() }) testWithRpc("getSenderAddress_V07", async ({ rpc }) => { const { anvilRpc, altoRpc } = rpc