Skip to content

Commit

Permalink
chore: improved debugging tools
Browse files Browse the repository at this point in the history
  • Loading branch information
joepegler committed Dec 20, 2024
1 parent fa5f293 commit cc59f52
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 82 deletions.
4 changes: 3 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ BUNDLER_URL=
BICONOMY_SDK_DEBUG=false
PAYMASTER_URL=
PIMLICO_API_KEY=
TENDERLY_API_KEY=
TENDERLY_API_KEY=
TENDERLY_ACCOUNT_SLUG=
TENDERLY_PROJECT_SLUG=
25 changes: 25 additions & 0 deletions src/sdk/account/utils/Utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,31 @@ export const isTesting = () => {
}
}

type TenderlyDetails = {
accountSlug: string
projectSlug: string
apiKey: string
}
export const getTenderlyDetails = (): TenderlyDetails | null => {
try {
const accountSlug = process?.env?.TENDERLY_ACCOUNT_SLUG
const projectSlug = process?.env?.TENDERLY_PROJECT_SLUG
const apiKey = process?.env?.TENDERLY_API_KEY

if (!accountSlug || !projectSlug || !apiKey) {
return null
}

return {
accountSlug,
projectSlug,
apiKey
}
} catch (e) {
return null
}
}

/**
* Safely multiplies a bigint by a number, rounding appropriately.
*
Expand Down
36 changes: 19 additions & 17 deletions src/sdk/account/utils/getAAError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,23 @@ const matchError = (message: string): null | KnownError =>
message.toLowerCase().indexOf(knownError.regex.toLowerCase()) > -1
) ?? null

const buildErrorStrings = (error: KnownError, status: string): string[] =>
[
`${status}: ${error.description}\n`,
error.causes?.length
? ["Potential cause(s): \n", ...error.causes, ""].join("\n")
: "",
error.solutions?.length
? ["Potential solution(s): \n", ...error.solutions].join("\n")
: ""
].filter(Boolean)
const buildErrorStrings = (error: KnownError, status: string): string[] => {
const strings: string[] = []

strings.push(`${status}: ${error.description}`)

if (error.causes?.length) {
strings.push("Potential cause(s):")
strings.push(...error.causes)
}

if (error.solutions?.length) {
strings.push("Potential solution(s):")
strings.push(...error.solutions)
}

return strings
}

type AccountAbstractionErrorParams = {
docsSlug?: string
Expand All @@ -53,8 +60,7 @@ export const getAAError = async (message: string, httpStatus?: number) => {
knownErrors.push(...errors)
}

const details: string = JSON.stringify(message)
const matchedError = matchError(details)
const matchedError = matchError(message)
const status =
matchedError?.regex ?? (httpStatus ?? UNKOWN_ERROR_CODE).toString()

Expand All @@ -64,9 +70,5 @@ export const getAAError = async (message: string, httpStatus?: number) => {
const title = matchedError ? matchedError.name : "Unknown Error"
const docsSlug = matchedError?.docsUrl ?? DOCS_URL

return new AccountAbstractionError(title, {
docsSlug,
metaMessages,
details
})
return { title, docsSlug, metaMessages, message }
}
158 changes: 106 additions & 52 deletions src/sdk/clients/decorators/smartAccount/sendDebugUserOperation.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,3 @@
import type {
Address,
Assign,
BaseError,
Chain,
Client,
Hex,
MaybeRequired,
Narrow,
OneOf,
Transport
} from "viem"
import {
type DeriveEntryPointVersion,
type DeriveSmartAccount,
Expand All @@ -25,13 +13,33 @@ import {
type UserOperationRequest,
formatUserOperationRequest,
getUserOperationError,
prepareUserOperation
prepareUserOperation,
toPackedUserOperation
} from "viem/account-abstraction"
import { parseAccount } from "viem/accounts"

import {
http,
type Assign,
type BaseError,
type Chain,
type Client,
type Hex,
type MaybeRequired,
type Narrow,
type OneOf,
type Transport,
createPublicClient,
parseEther,
zeroAddress

Check failure on line 33 in src/sdk/clients/decorators/smartAccount/sendDebugUserOperation.ts

View workflow job for this annotation

GitHub Actions / size report

'zeroAddress' is declared but its value is never read.
} from "viem"
import { type Address, parseAccount } from "viem/accounts"
import { type RequestErrorType, getAction } from "viem/utils"
import { AccountNotFoundError } from "../../../account/utils/AccountNotFound"
import { generateRandomHex } from "../../../modules/utils/Uid"

import { getTenderlyDetails } from "../../../account/utils/Utils"
import { deepHexlify } from "../../../account/utils/deepHexlify"
import { getAAError } from "../../../account/utils/getAAError"
import { getChain } from "../../../account/utils/getChain"
import { ENTRY_POINT_ADDRESS, EntrypointAbi } from "../../../constants"
export type SendDebugUserOperationParameters<
account extends SmartAccount | undefined = SmartAccount | undefined,
accountOverride extends SmartAccount | undefined = SmartAccount | undefined,
Expand Down Expand Up @@ -118,6 +126,8 @@ export async function sendDebugUserOperation<
client: Client<Transport, Chain | undefined, account>,
parameters: SendDebugUserOperationParameters<account, accountOverride, calls>
) {
const tenderlyDetails = getTenderlyDetails()

const { account: account_ = client.account, entryPointAddress } = parameters

if (!account_ && !parameters.sender) throw new AccountNotFoundError()
Expand All @@ -140,46 +150,84 @@ export async function sendDebugUserOperation<
signature
} as UserOperation)

console.log("Sending User Operation:", rpcParameters)

// Create Tenderly debug URL
const tenderlyUrl = new URL(
"https://dashboard.tenderly.co/JoeBico/biconomy/simulator/new"
console.log("Sending UserOperation to bundler:", rpcParameters)
const packed = toPackedUserOperation(request as UserOperation)
console.log(
"Packed user operation: ",
JSON.stringify(deepHexlify(packed), null, 2)
)
const formattedRpcParams = {
callData: rpcParameters.callData,
callGasLimit: rpcParameters.callGasLimit,
maxFeePerGas: rpcParameters.maxFeePerGas,
maxPriorityFeePerGas: rpcParameters.maxPriorityFeePerGas,
nonce: rpcParameters.nonce,
paymasterPostOpGasLimit: rpcParameters.paymasterPostOpGasLimit,
paymasterVerificationGasLimit: rpcParameters.paymasterVerificationGasLimit,
preVerificationGas: rpcParameters.preVerificationGas,
sender: rpcParameters.sender,
signature: rpcParameters.signature,
verificationGasLimit: rpcParameters.verificationGasLimit

const chainId = client.account?.client?.chain?.id?.toString()

if (tenderlyDetails) {
const tenderlyUrl = new URL(
`https://dashboard.tenderly.co/${tenderlyDetails.accountSlug}/${tenderlyDetails.projectSlug}/simulator/new`
)

const formattedRpcParams = {
callData: rpcParameters.callData,
callGasLimit: rpcParameters.callGasLimit,
maxFeePerGas: rpcParameters.maxFeePerGas,
maxPriorityFeePerGas: rpcParameters.maxPriorityFeePerGas,
nonce: rpcParameters.nonce,
paymasterPostOpGasLimit: rpcParameters.paymasterPostOpGasLimit,
paymasterVerificationGasLimit:
rpcParameters.paymasterVerificationGasLimit,
preVerificationGas: rpcParameters.preVerificationGas,
sender: rpcParameters.sender,
signature: rpcParameters.signature,
verificationGasLimit: rpcParameters.verificationGasLimit
}

const params = new URLSearchParams({
contractAddress: "0x0000000071727de22e5e9d8baf0edac6f37da032",
value: "0",
network: chainId ?? "84532",
// simulationId: generateRandomHex(),
contractFunction: "0x765e827f",
rawFunctionInput: rpcParameters.callData,
functionInputs: JSON.stringify([formattedRpcParams]),
headerBlockNumber: "19463586",
headerTimestamp: "1734695460",
stateOverrides: JSON.stringify([
{
contractAddress: rpcParameters.sender,
balance: "100000000000000000000"
}
])
})
tenderlyUrl.search = params.toString()
console.log("Tenderly Simulation URL:", tenderlyUrl.toString())

// Also do a simulation using the publicClient
} else {
console.log(
"Tenderly details not found in environment variables. Please set TENDERLY_API_KEY, TENDERLY_ACCOUNT_SLUG, and TENDERLY_PROJECT_SLUG."
)
}

const params = new URLSearchParams({
contractAddress: "0x0000000071727de22e5e9d8baf0edac6f37da032",
value: "0",
network: "84532",
// simulationId: generateRandomHex(),
contractFunction: "0x765e827f",
rawFunctionInput: rpcParameters.callData,
functionInputs: JSON.stringify([formattedRpcParams]),
headerBlockNumber: "19463586",
headerTimestamp: "1734695460",
stateOverrides: JSON.stringify([
{
contractAddress: rpcParameters.sender,
balance: "100000000000000000000"
}
])
})
tenderlyUrl.search = params.toString()
try {
const simulation = await createPublicClient({
chain: client.account?.client?.chain ?? getChain(Number(chainId)),
transport: http()
}).simulateContract({
account: rpcParameters.sender,
address: ENTRY_POINT_ADDRESS,
abi: EntrypointAbi,
functionName: "handleOps",
args: [[packed], rpcParameters.sender],
stateOverride: [
{
address: rpcParameters.sender,
balance: parseEther("1000")
}
]
})

console.log("Tenderly Simulation URL:", tenderlyUrl.toString())
console.log("Simulation:", { simulation })
} catch (error) {
console.error("Simulation failed")
}

try {
const hash = await client.request(
Expand All @@ -197,6 +245,12 @@ export async function sendDebugUserOperation<
return hash
} catch (error) {
// console.error("User Operation Failed:", error)

if (error?.details) {

Check failure on line 249 in src/sdk/clients/decorators/smartAccount/sendDebugUserOperation.ts

View workflow job for this annotation

GitHub Actions / size report

Property 'details' does not exist on type '{}'.
const aaError = await getAAError(error.details)

Check failure on line 250 in src/sdk/clients/decorators/smartAccount/sendDebugUserOperation.ts

View workflow job for this annotation

GitHub Actions / size report

Property 'details' does not exist on type '{}'.
console.log({ aaError })
}

const calls = (parameters as any).calls
throw getUserOperationError(error as BaseError, {

Check failure on line 255 in src/sdk/clients/decorators/smartAccount/sendDebugUserOperation.ts

View workflow job for this annotation

GitHub Actions / unit-tests

src/sdk/modules/smartSessionsValidator/toSmartSessionValidator.enable.mode.test.ts > modules.smartSessions.enable.mode.dx > should support smart sessions enable mode

UserOperationExecutionError: Signature provided for the User Operation is invalid. This could arise when: - the `signature` for the User Operation is incorrectly computed, and unable to be verified by the Smart Account Request Arguments: callData: 0xe9ae5c5300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000003814e4829e655f0b3a1793838ddd47273d5341d4160000000000000000000000000000000000000000000000000000000000000000273ea3e30000000000000000 callGasLimit: 10000000 maxFeePerGas: 0.001500581 gwei maxPriorityFeePerGas: 0.0015 gwei nonce: 26040081937429419522611726281644983206698692175197151913405192147658329817088 paymasterPostOpGasLimit: 10000000 paymasterVerificationGasLimit: 10000000 preVerificationGas: 10000000 sender: 0xdC66A533f27aC804B40c991F6016ceAAb8d7Defc signature: 0x02010000e014010040e0141d020004802004e03300e0173f00e0e0155c0103c0e0151f0100012003e011001f014a349968f2f08f79edc4e5341b7326cbac9e1da496eab7b5c3ef39715368220339323900e0020013e7a6f1a02151e50b600bc3d06feed70c6c4b19bde0021ee00b001fc0d0d1d70cebf31c48a20a14a3cc5aefacf5125c96ae6f259eba6363c045ef59000de00b34e00100e015be201f00202004e012000101a0e0121c400014143b61b91d3c72da4a0b033f930006e99884b3cbf44018e03e00e2163f0100602003e05300e117400420273ea3e3e01f801314e4829e655f0b3a1793838ddd47273d5341d416e0163be017dfe0189fe0035f13529ad04f4d83aab25144a90267d4a1443b84f5a6e0031fe00a00e1177fe01700005520201f2d6db27c52e3c11c1cf24072004ac75cba186928468c063f2c023feab125ae321fd58a2afdcc74cd3948b4a955fc50abe7e0733a435a3b8bbc91834664987fe9e6119a194aadc19b8ed13aa6721aab6ddf878a1b2054e01e001f418619b0815549f114012f5a94fd637faf6d473d4614132904ed41342e41b1001f6a36e422cacbfacb4261937f19bc6ebdc4885625a9325b133ddf5efb87076a2800cbe0126b040000000000 verificationGasLimit: 10000000 Details: {"code":-32500,"message":"AA24 signature error"} Version: 2.21.6 ❯ Module.getUserOperationError node_modules/viem/account-abstraction/utils/errors/getUserOperationError.ts:68:10 ❯ Module.sendDebugUserOperation src/sdk/clients/decorators/smartAccount/sendDebugUserOperation.ts:255:11 ❯ src/sdk/modules/smartSessionsValidator/toSmartSessionValidator.enable.mode.test.ts:348:24 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { details: '{"code":-32500,"message":"AA24 signature error"}', docsPath: undefined, metaMessages: [ 'This could arise when:', '- the `signature` for the User Operation is incorrectly computed, and unable to be verified by the Smart Account', ' ', 'Request Arguments:', ' callData: 0xe9ae5c5300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000003814e4829e655f0b3a1793838ddd47273d5341d4160000000000000000000000000000000000000000000000000000000000000000273ea3e30000000000000000\n callGasLimit: 10000000\n maxFeePerGas: 0.001500581 gwei\n maxPriorityFeePerGas: 0.0015 gwei\n nonce: 26040081937429419522611726281644983206698692175197151913405192147658329817088\n paymasterPostOpGasLimit: 10000000\n paymasterVerificationGasLimit: 10000000\n preVerificationGas: 10000000\n sender: 0xdC66A533f27aC804B40c991F6016ceAAb8d7Defc\n signature: 0x02010000e014010040e0141d020004802004e03300e0173f00e0e0155c0103c0e0151f0100012003e011001f014a349968f2f08f79edc4e5341b7326cbac9e1da496eab7b5c3ef39715368220339323900e0020013e7a6f1a02151e50b600bc3d06feed70c6c4b19bde0021ee00b001fc0d0d1d70cebf31c48a20a14a3cc5aefacf5125c96ae6f259eba6363c045ef59000de00b34e00100e015be201f00202004e012000101a0e0121c400014143b61b91d3c72da4a0b033f930006e99884b3cbf44018e03e00e2163f0100602003e05300e117400420273ea3e3e01f801314e4829e655f
...(request as UserOperation),
Expand Down
2 changes: 1 addition & 1 deletion src/sdk/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { ParamCondition } from "../modules/smartSessionsValidator/Types"
export * from "./abi"

export const SIMPLE_SESSION_VALIDATOR_ADDRESS: Hex =
"0x41f143f4B5f19AfCd2602F6ADE18E75e9b5E37d3"
"0xE7A6F1a02151E50b600BC3d06FeEd70C6c4B19Bd"
export const ENTRY_POINT_ADDRESS: Hex =
"0x0000000071727De22E5E9d8BAf0edAc6f37da032"
export const ENTRYPOINT_SIMULATIONS_ADDRESS: Hex =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,27 +126,27 @@ describe("modules.smartSessions.enable.mode.dx", async () => {

test("should pack user operation", async () => {
const packed = toPackedUserOperation({
verificationGasLimit: 10000000n,
paymasterVerificationGasLimit: 10000000n,
callGasLimit: 10000000n,
paymasterPostOpGasLimit: 10000000n,
preVerificationGas: 10000000n,
signature:
"0x02010000e014010040e0141d020004802004e03300e0173f00e0e0155c0103c0e0151f0100012003e011001f014a34ae11a739a10c39be924306d512bff8c480de193a42f1209c99d1b2950c02e20f42e0033c1341f143f4b5f19afcd2602f6ade18e75e9b5e37d3e0031fe00a001fc06d47491264728e9233d06d2b0efbc5689de47b89e9fe3d419365676ef3d77d001de00a33e00200e015be201f00202004e012000101a0e0121c400014147a478affccf9ba4722b4fd42fb68e460d16fbc1e4018e03e00e2163f0100602003e05300e117400420273ea3e3e01f801314e4829e655f0b3a1793838ddd47273d5341d416e0163be017dfe0189fe0035f13529ad04f4d83aab25144a90267d4a1443b84f5a6e0031fe00a00e1177fe01700005520201f2d6db27c52e3c11c1cf24072004ac75cba04086e15e6bd4485230c7655d5d1e01f1bef115c8098335703bda6e3f8f565bd2c00485124334422c5798da167e63a5d1179826812046dd500cf2a1a7439b0c83d6d1c2054e01e001f414c83cd664b8fcb40e8e06152028f452d11e9ed58e80de3825645d3f53b16c31f4b7e84ab430dc42200d802a42e85b98eb1d5e319e32ceb4ee3b349e285025bdc01661be01168040000000000",
"0x02010000e014010040e0141d020004802004e03300e0173f00e0e0155c0103c0e0151f0100012003e011001f014a34ce499bbaebbe7d4959cfff7288cb93ef4092e01394aaa8d8be9a83965002ce564ee0033c13e7a6f1a02151e50b600bc3d06feed70c6c4b19bde0031fe00a001fc0cd2cb6e55eee9b4a40c46ffbacd016ba4a24478af6824c4f4a1c54fd408dde00a5e00a33e00200e015be201f00202004e012000101a0e0121c4000141485db11bee65cc7b724f84a59f6f28e12c908a34c4018e03e00e2163f0100602003e05300e117400420273ea3e3e01f801314e4829e655f0b3a1793838ddd47273d5341d416e0163be017dfe0189fe0035f13529ad04f4d83aab25144a90267d4a1443b84f5a6e0031fe00a00e1177fe01700005520201f2d6db27c52e3c11c1cf24072004ac75cba46b3ec7a493343de755d89cbadf12f1f7313bd4d71e406b0de146f86c859af98f73b62677b7ae474375b13ca50d09dc81104e7327697b7e823c1be631f6b851ed2f21b2054e01e001f415ed3370e1bb7f72b82d7080f02785f6e9765999f5bb76e043164e93af57fa31f4d2d513aaa6b04c14d3b64f98844b77815f9f2a72d3dad3a7f6c017fd90263cc01341ce01168040000000000",
sender: "0xdC66A533f27aC804B40c991F6016ceAAb8d7Defc",
maxFeePerGas: 1500582n,
maxPriorityFeePerGas: 1500000n,
callData:
"0xe9ae5c5300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000003814e4829e655f0b3a1793838ddd47273d5341d4160000000000000000000000000000000000000000000000000000000000000000273ea3e30000000000000000",
sender: "0xdC66A533f27aC804B40c991F6016ceAAb8d7Defc",
maxFeePerGas: 3500855n,
maxPriorityFeePerGas: 3500000n,
factory: undefined,
factoryData: undefined,
nonce:
84423803952951738471617358635217431751803879867990993447121768113268552892416n,
callGasLimit: 1562217n,
verificationGasLimit: 1567305n,
paymasterPostOpGasLimit: 1567305n,
paymasterVerificationGasLimit: 1567305n,
preVerificationGas: 10000000000n
24082891610152898234334765648976326605918059143978045864478758690797549256704n
})

// console.log(JSON.stringify(deepHexlify(packed), null, 2))
expect(packed.nonce).toBe(
84423803952951738471617358635217431751803879867990993447121768113268552892416n
24082891610152898234334765648976326605918059143978045864478758690797549256704n
)

console.log(JSON.stringify(deepHexlify(packed), null, 2))
Expand Down

0 comments on commit cc59f52

Please sign in to comment.