Skip to content

Commit

Permalink
Merge branch 'main' of github.com:pimlicolabs/permissionless.js into …
Browse files Browse the repository at this point in the history
…node-to-nodenext
  • Loading branch information
plusminushalf committed Nov 8, 2024
2 parents 04c0329 + f89713b commit 1d22236
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 187 deletions.
5 changes: 5 additions & 0 deletions .changeset/rotten-goats-draw.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"permissionless": patch
---

Improved `getSenderAddress` to avoid relying on EntryPoint reverts with RPC.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
228 changes: 42 additions & 186 deletions packages/permissionless/actions/public/getSenderAddress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,40 @@ 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 { 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
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
Expand Down Expand Up @@ -88,186 +106,24 @@ export const getSenderAddress = async (
)
}

try {
await getAction(
client,
simulateContract,
"simulateContract"
)({
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])]
const formattedInitCode =
initCode || concat([factory as Hex, factoryData as Hex])

const { data } = await getAction(
client,
call,
"call"
)({
data: encodeDeployData({
abi: GetSenderAddressHelperAbi,
bytecode: GetSenderAddressHelperByteCode,
args: [entryPointAddress, formattedInitCode]
})
} 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
})

return error.args[0] as Address
}
})

throw e
if (!data) {
throw new Error("Failed to get sender address")
}

throw new InvalidEntryPointError({ entryPointAddress })
return getAddress(data)
}

0 comments on commit 1d22236

Please sign in to comment.