Skip to content

Commit

Permalink
chore: smart sessions migration
Browse files Browse the repository at this point in the history
  • Loading branch information
joepegler committed Dec 31, 2024
1 parent 3fe6115 commit 9c0759d
Show file tree
Hide file tree
Showing 7 changed files with 230 additions and 134 deletions.
22 changes: 20 additions & 2 deletions src/sdk/account/toNexusAccount.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
createWalletClient,
domainSeparator,
encodeAbiParameters,
encodeFunctionData,
encodePacked,
getContract,
hashMessage,
Expand All @@ -27,6 +28,7 @@ import {
} from "viem"
import type { UserOperation } from "viem/account-abstraction"
import { afterAll, beforeAll, describe, expect, test } from "vitest"
import { CounterAbi } from "../../test/__contracts/abi/CounterAbi"
import { MockSignatureValidatorAbi } from "../../test/__contracts/abi/MockSignatureValidatorAbi"
import { TokenWithPermitAbi } from "../../test/__contracts/abi/TokenWithPermitAbi"
import { testAddresses } from "../../test/callDatas"
Expand All @@ -45,8 +47,7 @@ import {
import {
BICONOMY_ATTESTER_ADDRESS,
MAINNET_ADDRESS_K1_VALIDATOR_FACTORY_ADDRESS,
k1ValidatorAddress,
k1ValidatorFactoryAddress
k1ValidatorAddress
} from "../constants"
import type { NexusAccount } from "./toNexusAccount"
import {
Expand Down Expand Up @@ -600,4 +601,21 @@ describe("nexus.account", async () => {
expect(BICONOMY_ATTESTER_ADDRESS).toBe(biconomyAttesterAddress)
}
)

testnetTest(
"should debug user operation and generate tenderly link",
async ({ config: { chain } }) => {
await nexusClient.debugUserOperation({
calls: [
{
to: testAddresses.Counter,
data: encodeFunctionData({
abi: CounterAbi,
functionName: "incrementNumber"
})
}
]
})
}
)
})
41 changes: 41 additions & 0 deletions src/sdk/account/utils/Utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -433,3 +433,44 @@ export const getAllowance = async (

return approval as bigint
}

export function parseRequestArguments(input: string[]) {
const fieldsToOmit = [
"callGasLimit",
"preVerificationGas",
"maxFeePerGas",
"maxPriorityFeePerGas",
"paymasterAndData",
"verificationGasLimit"
]

// Skip the first element which is just "Request Arguments:"
const argsString = input.slice(1).join("")

// Split by newlines and filter out empty lines
const lines = argsString.split("\n").filter((line) => line.trim())

// Create an object from the key-value pairs
const result = lines.reduce(
(acc, line) => {
// Remove extra spaces and split by ':'
const [key, value] = line.split(":").map((s) => s.trim())

// Clean up the key (remove trailing spaces and colons)
const cleanKey = key.trim()

// Clean up the value (remove 'gwei' and other units)
const cleanValue: string | number = value.replace("gwei", "").trim()

if (fieldsToOmit.includes(cleanKey)) {
return acc
}

acc[cleanKey] = cleanValue
return acc
},
{} as Record<string, string | number>
)

return result
}
29 changes: 29 additions & 0 deletions src/sdk/account/utils/contractSimulation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { http, type Address, createPublicClient, parseEther } from "viem"
import { ENTRY_POINT_ADDRESS, EntrypointAbi } from "../../constants"
import { getChain } from "./getChain"
import { getSimulationUserOp } from "./tenderlySimulation"
import type { AnyUserOperation } from "./tenderlySimulation"

export async function contractSimulation(
partialUserOp: AnyUserOperation,
chainId: number
) {
const packed = getSimulationUserOp(partialUserOp)

return createPublicClient({
chain: getChain(chainId),
transport: http()
}).simulateContract({
account: partialUserOp.sender as Address,
address: ENTRY_POINT_ADDRESS,
abi: EntrypointAbi,
functionName: "handleOps",
args: [[packed], packed.sender],
stateOverride: [
{
address: partialUserOp.sender as Address,
balance: parseEther("1000")
}
]
})
}
66 changes: 66 additions & 0 deletions src/sdk/account/utils/tenderlySimulation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import type { RpcUserOperation } from "viem"
import {
type UserOperation,
toPackedUserOperation
} from "viem/account-abstraction"
import { getTenderlyDetails } from "."
import { ENTRY_POINT_ADDRESS } from "../../constants"
import { deepHexlify } from "./deepHexlify"

export type AnyUserOperation = Partial<UserOperation<"0.7"> | RpcUserOperation>

export const getSimulationUserOp = (partialUserOp: AnyUserOperation) => {
const simulationGasLimits = {
callGasLimit: 100_000_000_000n,
verificationGasLimit: 100_000_000_000n,
preVerificationGas: 1n,
maxFeePerGas: 100_000_000_000n,
maxPriorityFeePerGas: 1n,
paymasterVerificationGasLimit: 100_000_000_000n,
paymasterPostOpGasLimit: 100_000n
}

const mergedUserOp = deepHexlify({
...simulationGasLimits,
...partialUserOp
})

return toPackedUserOperation(mergedUserOp)
}

export function tenderlySimulation(
partialUserOp: AnyUserOperation,
chainId = 84532
) {
const tenderlyDetails = getTenderlyDetails()

if (!tenderlyDetails) {
console.log(
"Tenderly details not found in environment variables. Please set TENDERLY_API_KEY, TENDERLY_ACCOUNT_SLUG, and TENDERLY_PROJECT_SLUG."
)
return null
}

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

const packedUserOp = getSimulationUserOp(partialUserOp)

const params = new URLSearchParams({
contractAddress: ENTRY_POINT_ADDRESS,
value: "0",
network: chainId.toString(),
contractFunction: "0x765e827f", // handleOps
functionInputs: JSON.stringify([packedUserOp]),
stateOverrides: JSON.stringify([
{
contractAddress: packedUserOp.sender,
balance: "100000000000000000000"
}
])
})

tenderlyUrl.search = params.toString()
return tenderlyUrl.toString()
}
Loading

0 comments on commit 9c0759d

Please sign in to comment.