Skip to content

Commit ad54736

Browse files
committed
feat: added ep0.7 debugger
1 parent 2ab65b6 commit ad54736

File tree

8 files changed

+601
-5
lines changed

8 files changed

+601
-5
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
config.sh
1+
config.sh
2+
node_modules

0_7_userop_debug.sh

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#!/bin/bash
2+
set -euo pipefail
3+
4+
source config.sh
5+
6+
readonly ENTRYPOINT_ADDRESS="0x0000000071727De22E5E9d8BAf0edAc6f37da032"
7+
readonly SIMULATION_CONTRACT_ADDRESS="0x5465089caC0f710BA895E2711491F1D8AfB7D245"
8+
9+
check_dependency() {
10+
local DEPENDENCY="$1"
11+
if ! command -v "$DEPENDENCY" &>/dev/null; then
12+
printf >&2 "%s could not be found. Please install it and try again.\n" "$DEPENDENCY"
13+
exit 1
14+
fi
15+
}
16+
17+
get_node_url_for_chain_id() {
18+
local LOCAL_CHAIN_ID="$1"
19+
local -a CHAIN_IDS=(1 5 80001 11155111 137 11155420 10)
20+
local -a NODE_URLS=(
21+
"https://mainnet.infura.io/v3/${INFURA_API_KEY}"
22+
"https://goerli.infura.io/v3/${INFURA_API_KEY}"
23+
"https://polygon-mumbai.infura.io/v3/${INFURA_API_KEY}"
24+
"https://sepolia.infura.io/v3/${INFURA_API_KEY}"
25+
"https://polygon-mainnet.infura.io/v3/${INFURA_API_KEY}"
26+
"https://optimism-sepolia.infura.io/v3/${INFURA_API_KEY}"
27+
"https://optimism-mainnet.infura.io/v3/${INFURA_API_KEY}"
28+
)
29+
30+
for ((i=0; i<${#CHAIN_IDS[@]}; i++)); do
31+
if [[ "${CHAIN_IDS[$i]}" == "$LOCAL_CHAIN_ID" ]]; then
32+
printf "%s\n" "${NODE_URLS[$i]}"
33+
return
34+
fi
35+
done
36+
37+
printf >&2 "Unsupported chainId: %s\n" "$LOCAL_CHAIN_ID"
38+
exit 1
39+
}
40+
41+
execute_cast_call_with_sender_data_url() {
42+
local SENDER="$1" CALL_DATA="$2" NODE_URL="$3"
43+
cast call "$SENDER" "$CALL_DATA" -f "$ENTRYPOINT_ADDRESS" -r "$NODE_URL" --trace
44+
# echo cast call "$SENDER" "$CALL_DATA" -f "$ENTRYPOINT_ADDRESS" -r "$NODE_URL" --trace
45+
}
46+
47+
extract_field_value_from_json() {
48+
echo "$USER_OP_JSON" | jq -r --arg FIELD "$1" '.[$FIELD]'
49+
}
50+
51+
check_dependency jq
52+
check_dependency cast
53+
54+
if [[ $# -lt 2 ]]; then
55+
printf >&2 "Usage: %s '<userOpJson>' <chainId>\n" "$0"
56+
exit 1
57+
fi
58+
59+
# readonly UNPACKED_USER_OP_JSON="$1"
60+
readonly USER_OP_JSON=$(npx ts-node cli.ts --operation $1)
61+
readonly CHAIN_ID="$2"
62+
63+
SENDER=$(extract_field_value_from_json 'sender')
64+
NONCE=$(extract_field_value_from_json 'nonce')
65+
INIT_CODE=$(extract_field_value_from_json 'initCode')
66+
CALL_DATA=$(extract_field_value_from_json 'callData')
67+
ACCOUNT_GAS_LIMITS=$(extract_field_value_from_json 'accountGasLimits')
68+
PRE_VERIFICATION_GAS=$(extract_field_value_from_json 'preVerificationGas')
69+
GAS_FEES=$(extract_field_value_from_json 'gasFees')
70+
PAYMASTER_AND_DATA=$(extract_field_value_from_json 'paymasterAndData')
71+
SIGNATURE=$(extract_field_value_from_json 'signature')
72+
73+
NODE_URL=$(get_node_url_for_chain_id "$CHAIN_ID")
74+
75+
# execute_cast_call_with_sender_data_url "$SENDER" "$CALL_DATA" "$NODE_URL"
76+
77+
SIMULATE_VALIDATION_CALL_DATA=$(cast calldata 'simulateValidation((address,uint256,bytes,bytes,bytes32,uint256,bytes32,bytes,bytes))' "($SENDER,$NONCE,$INIT_CODE,$CALL_DATA,$ACCOUNT_GAS_LIMITS,$PRE_VERIFICATION_GAS,$GAS_FEES,$PAYMASTER_AND_DATA,$SIGNATURE)")
78+
79+
SIMULATE_ENTRYPOINT_CALL_DATA=$(cast calldata 'simulateEntryPoint(address,bytes[])' "$ENTRYPOINT_ADDRESS" [$SIMULATE_VALIDATION_CALL_DATA])
80+
echo $SIMULATE_ENTRYPOINT_CALL_DATA
81+
82+
execute_cast_call_with_sender_data_url "$SIMULATION_CONTRACT_ADDRESS" "$SIMULATE_ENTRYPOINT_CALL_DATA" "$NODE_URL"

cli.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { toPackedUserOperation } from "./packUserOperation";
2+
import yargs from "yargs";
3+
import { hideBin } from "yargs/helpers";
4+
import dotenv from "dotenv";
5+
dotenv.config();
6+
7+
async function main() {
8+
const argv = await yargs(hideBin(process.argv))
9+
.option("operation", {
10+
alias: "o",
11+
description: "The unpacked user operation as a JSON string",
12+
type: "string",
13+
})
14+
.parse();
15+
16+
if (argv.operation) {
17+
try {
18+
const unpackedUserOperation = JSON.parse(argv.operation);
19+
20+
const packedOperation = toPackedUserOperation(unpackedUserOperation);
21+
22+
console.log(JSON.stringify(packedOperation));
23+
} catch (error) {
24+
console.error("Failed to parse unpacked user operation:", error);
25+
}
26+
} else {
27+
console.error(
28+
"No operation provided. Please pass an operation using the --operation flag."
29+
);
30+
}
31+
}
32+
33+
main();

packUserOperation.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { pad, toHex, Hex, concat } from "viem"
2+
3+
export function toPackedUserOperation(
4+
unpackedUserOperation: any
5+
) {
6+
return {
7+
sender: unpackedUserOperation.sender,
8+
nonce: unpackedUserOperation.nonce,
9+
initCode: getInitCode(unpackedUserOperation),
10+
callData: unpackedUserOperation.callData,
11+
accountGasLimits: getAccountGasLimits(unpackedUserOperation),
12+
preVerificationGas: unpackedUserOperation.preVerificationGas,
13+
gasFees: getGasLimits(unpackedUserOperation),
14+
paymasterAndData: getPaymasterAndData(unpackedUserOperation),
15+
signature: unpackedUserOperation.signature
16+
}
17+
}
18+
19+
export function getInitCode(unpackedUserOperation: any) {
20+
return unpackedUserOperation.factory
21+
? concat([
22+
unpackedUserOperation.factory,
23+
unpackedUserOperation.factoryData || ("0x" as Hex)
24+
])
25+
: "0x"
26+
}
27+
28+
export function getAccountGasLimits(
29+
unpackedUserOperation: any
30+
) {
31+
return concat([
32+
pad(toHex(unpackedUserOperation.verificationGasLimit), {
33+
size: 16
34+
}),
35+
pad(toHex(unpackedUserOperation.callGasLimit), { size: 16 })
36+
])
37+
}
38+
39+
export function getGasLimits(unpackedUserOperation: any) {
40+
return concat([
41+
pad(toHex(unpackedUserOperation.maxPriorityFeePerGas), {
42+
size: 16
43+
}),
44+
pad(toHex(unpackedUserOperation.maxFeePerGas), { size: 16 })
45+
])
46+
}
47+
48+
export function getPaymasterAndData(
49+
unpackedUserOperation: any
50+
) {
51+
return unpackedUserOperation.paymaster
52+
? concat([
53+
unpackedUserOperation.paymaster,
54+
pad(
55+
toHex(
56+
unpackedUserOperation.paymasterVerificationGasLimit || 0n
57+
),
58+
{
59+
size: 16
60+
}
61+
),
62+
pad(toHex(unpackedUserOperation.paymasterPostOpGasLimit || 0n), {
63+
size: 16
64+
}),
65+
unpackedUserOperation.paymasterData || ("0x" as Hex)
66+
])
67+
: "0x"
68+
}

0 commit comments

Comments
 (0)