From 1e722146e2a7d61d4d298b9efc12d6180758746c Mon Sep 17 00:00:00 2001 From: ChiHaoLu Date: Tue, 24 Sep 2024 14:50:00 +0800 Subject: [PATCH] first commit --- .gitignore | 10 + .npmrc | 2 + README.md | 3 + next-env.d.ts | 5 + next.config.js | 4 + package.json | 20 + pages/index.tsx | 246 +++++ tsconfig.json | 28 + yarn.lock | 2705 +++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 3023 insertions(+) create mode 100644 .gitignore create mode 100644 .npmrc create mode 100644 README.md create mode 100644 next-env.d.ts create mode 100644 next.config.js create mode 100644 package.json create mode 100644 pages/index.tsx create mode 100644 tsconfig.json create mode 100644 yarn.lock diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..64c51d8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +*/node_modules +/.pnp +.pnp.js +*/.vscode + +.next +node_modules +.DS_Store +.env.local +yarn-error.log \ No newline at end of file diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..db936b0 --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +@consenlabs:registry=https://npm.pkg.github.com/ +//npm.pkg.github.com/:_authToken=${PAT} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..a547985 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# Tenderly 4337 Debugger + +Directly gives your Tenderly's user name, project name and access key, you can debug any userOp! \ No newline at end of file diff --git a/next-env.d.ts b/next-env.d.ts new file mode 100644 index 0000000..4f11a03 --- /dev/null +++ b/next-env.d.ts @@ -0,0 +1,5 @@ +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/next.config.js b/next.config.js new file mode 100644 index 0000000..c071158 --- /dev/null +++ b/next.config.js @@ -0,0 +1,4 @@ +// next.config.js +module.exports = { + reactStrictMode: true +}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..2996960 --- /dev/null +++ b/package.json @@ -0,0 +1,20 @@ +{ + "name": "front-end", + "version": "1.0.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start" + }, + "dependencies": { + "@consenlabs/imaccount-sdk": "^0.1.0", + "next": "^13.0.0", + "react": "^18.0.0", + "react-dom": "^18.0.0", + "viem": "^2.21.12" + }, + "devDependencies": { + "@types/react": "18.3.7" + } +} diff --git a/pages/index.tsx b/pages/index.tsx new file mode 100644 index 0000000..13215ee --- /dev/null +++ b/pages/index.tsx @@ -0,0 +1,246 @@ +import React, { useState, useEffect } from "react"; +import { + simulate, + BundlerUserOperationData, + PackedUserOperation, + unwrap, + wrap, +} from "@consenlabs/imaccount-sdk"; +import { Address } from "viem"; + +const Home = () => { + // Tenderly Config + const [TENDERLY_ACCESS_KEY, setTENDERLY_ACCESS_KEY] = useState(""); + const [projectOwner, setProjectOwner] = useState("ChiHaoLu"); + const [projectName, setProjectName] = useState("aatest"); + const [richBundlerEOA, setRichBundlerEOA] = useState
( + "0x4d7f573039fddc84fdb28515ba20d75ef6b987ff" + ); + + // userOp input + const [input, setInput] = useState(`{ + sender: "0x8b8aF275602891ddDf4d60783A80A01bf56f8F64", + nonce: "0x31", + callData: "0xe9ae5c53010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001842b67b570000000000000000000000000f7728cf90ad4cb9a14342827641056fd2e88a82e0000000000000000000000001c7d4b196cb0c7b01d743fbc6116a902379c72380000000000000000000000000000000000000000000000000000000000e4e1c00000000000000000000000000000000000000000000000000000000066f0e1be000000000000000000000000000000000000000000000000000000000000000000000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc450000000000000000000000000000000000000000000000000000000066f0e1be000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000557a61f7aa49341fb0ef67b1376f84b72bf1063a678417b73b0a2bc06100a7b3d880f51c8837b46a14fa235ac1441ad436681fb0d73e39e869f79f52f46212fc9575f2bd6cb9c522f32be0e1ba49f0e2a3987c018e1c000000000000000000000000000000000000000000000000000000000000000000000000000000", + callGasLimit: "0x0", + verificationGasLimit: "0x0", + preVerificationGas: "0x0", + maxFeePerGas: "0x1", + maxPriorityFeePerGas: "0x1", + paymasterVerificationGasLimit: "0x0", + paymasterPostOpGasLimit: "0x0", + signature:"0x7a61f7aa49341fb0ef67b1376f84b72bf1063a67fffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c" + }`); + const [parsedInput, setParsedInput] = useState<{ + unwrapped: BundlerUserOperationData; + wrapped: PackedUserOperation; + serialized: string; + } | null>(null); + const [parseError, setParseError] = useState(null); + + // Result + const [loading, setLoading] = useState(false); + const [result, setResult] = useState(""); + + const isSimulateDisabled = + !TENDERLY_ACCESS_KEY || !projectOwner || !projectName || !richBundlerEOA; + + const handleSimulate = async () => { + if ( + !TENDERLY_ACCESS_KEY || + !projectOwner || + !projectName || + !richBundlerEOA || + !parsedInput + ) { + alert("Please fill in all required fields."); + return; + } + + setLoading(true); + try { + console.log(input); + const simulationResult = await simulate( + TENDERLY_ACCESS_KEY, + richBundlerEOA, + parsedInput?.wrapped, + projectOwner, + projectName + ); + + setResult(JSON.stringify(simulationResult, null, 2)); + } catch (error) { + console.error(error); + alert(`Simulation failed.\n${error}`); + setResult(""); + } finally { + setLoading(false); + } + }; + + function serialize(parsed: any): Record { + return Object.entries(parsed).reduce( + (acc, [key, value]) => { + if ( + typeof value === "string" && + /^0x[a-fA-F0-9]+$/.test(value) && + (key.includes("gas") || key.includes("Gas")) && + key !== "accountGasLimits" && + key !== "gasFees" + ) { + acc[key] = String(BigInt(value)); + } else if (typeof value === "bigint") { + acc[key] = String(value); + } else { + acc[key] = value; + } + return acc; + }, + {} as Record + ); + } + + function parse(parsed: { + unwrapped: BundlerUserOperationData; + wrapped: PackedUserOperation; + }): string { + return JSON.stringify( + { + wrapped: serialize(parsed.wrapped), + unwrapped: serialize(parsed.unwrapped), + }, + null, + 2 + ); + } + + const handleInputChange = (e: React.ChangeEvent) => { + const text = e.target.value; + setInput(text); + try { + const parsed = JSON.parse( + text + .replace(/([a-zA-Z0-9]+):/g, '"$1":') // Add quotes around keys + .replace(/'/g, '"') // Replace single quotes with double quotes + ); + + // Check and transform BigInt values where necessary + if (parsed.accountGasLimits !== undefined) { + const serialized = parse({ + wrapped: parsed as PackedUserOperation, + unwrapped: unwrap(parsed as PackedUserOperation), + }); + setParsedInput({ + wrapped: parsed as PackedUserOperation, + unwrapped: unwrap(parsed as PackedUserOperation), + serialized: serialized, + }); + } else { + const serialized = parse({ + wrapped: wrap(parsed as BundlerUserOperationData), + unwrapped: parsed as BundlerUserOperationData, + }); + setParsedInput({ + wrapped: wrap(parsed as BundlerUserOperationData), + unwrapped: parsed as BundlerUserOperationData, + serialized: serialized, + }); + } + setParseError(null); + } catch (error) { + setParseError(`Invalid JSON format.\n${error}`); + setParsedInput(null); + } + }; + + return ( +
+

AA Debugger

+

1. Give the required Tenderly Config

+
+ +
+
+ +
+
+ +
+
+ +
+ +

2. Give your userOp

+

UserOp Input

+
+