diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..dbc5b2e --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,23 @@ +name: Lint + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + lint: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Deno + uses: denoland/setup-deno@v2 + with: + deno-version: v2.x + + - name: Run linter + run: deno task lint diff --git a/README.md b/README.md index 7a28f40..894f174 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ This does the following: Update `tools/deploy.ts` to include new contracts you want to deploy. Make sure to specify the constructor arguments and the value, if needed. -Once you have the chain running (see [Running the Development Stack](#running-the-development-stack)), deploy the contracts by running: +Once you have the chain running (see [Running the Revive Stack](#running-the-revive-stack)), deploy the contracts by running: ```sh deno task deploy [--filter ] @@ -94,9 +94,21 @@ eth-rpc build These commands will compile the binaries into `~/polkadot-sdk/target/debug/`. The build process may take some time on the first run. -## Running the Development Stack +# Testing Tips -Once built, you can run the complete development stack in tmux: +## Running the Revive Stack + +Once built, you can run each service individually: + +```sh +# Run the development node +dev-node run + +# In another terminal, run the Ethereum RPC bridge +eth-rpc run ws://localhost:9944 +``` + +Alternatively, you can run the complete development stack in tmux: ```sh # Run both services in separate tmux panes @@ -107,23 +119,61 @@ revive_dev_stack revive_dev_stack proxy ``` -Alternatively, you can run each service individually: +## Running the Geth Stack + +To test contracts against standard Ethereum with Geth: ```sh -# Run the development node -dev-node run +# Run geth in development mode (default port 8545) +geth-dev -# In another terminal, run the Ethereum RPC bridge -eth-rpc run ws://localhost:9944 +# Or specify a custom port +geth-dev 8546 ``` -To test contracts with Geth +Alternatively, you can run geth with mitmproxy in a tmux window: ```sh # Run geth with mitmproxy in a tmux window geth_stack ``` +This will start a local Geth development node with HTTP RPC enabled, useful for comparing behavior between Revive and standard EVM environments. + +## Recording and Replaying RPC Requests + +### Recording RPC Requests + +When testing and debugging, you can record all `eth_sendRawTransaction` requests using the `--record` flag: + +```sh +# Record requests when running eth-rpc +eth-rpc run ws://localhost:9944 --record +``` + +When `--record` is enabled, eth-rpc will: + +- Log all output to console and `/tmp/eth-rpc.log` +- Extract and save all `eth_sendRawTransaction` requests to `/tmp/eth-rpc-requests.log` + +### Replaying Recorded Requests + +You can replay recorded requests using the `scripts/run-all.sh` script: + +```sh +# Replay all recorded requests against localhost:8545 +./scripts/run-all.sh +``` + +This script will: + +- Send each recorded transaction to the RPC endpoint +- Wait for transaction receipts +- Display status (✓ for success, ✗ for failure) +- Report any errors or failed transactions at the end + +This is useful for regression testing - record a successful test session, then replay it against new builds to ensure compatibility. + # Learn more - [Asset Hub documentation](https://contracts.polkadot.io) to learn more about building Smart Contracts on Asset Hub. diff --git a/deno.json b/deno.json index 857e8c7..8a01541 100644 --- a/deno.json +++ b/deno.json @@ -1,5 +1,6 @@ { "tasks": { + "lint": "deno fmt --check && deno lint", "build": { "description": "Build contracts from the contracts directory and output bytecode and abi in the codegen directory", "command": "deno run --env-file --allow-all tools/build.ts" @@ -20,7 +21,7 @@ "react/jsx-runtime": "npm:react@^19.2.0/jsx-runtime", "solc": "npm:solc@^0.8.30", "viem": "npm:viem@^2.38.4", - "viem/accounts": "npm:viem@^2.38.4/accounts", + "viem/accounts": "npm:viem@^2.38.4/accounts" }, "compilerOptions": { "strict": true, diff --git a/scripts/node-env.sh b/scripts/node-env.sh index 35abbc5..b084627 100755 --- a/scripts/node-env.sh +++ b/scripts/node-env.sh @@ -1,5 +1,18 @@ #!/bin/bash +# Detect current shell and its RC file +if [ -n "$ZSH_VERSION" ]; then + CURRENT_SHELL="zsh" + SHELL_RC="$HOME/.zshrc" +elif [ -n "$BASH_VERSION" ]; then + CURRENT_SHELL="bash" + SHELL_RC="$HOME/.bashrc" +else + # Fallback to $SHELL environment variable + CURRENT_SHELL="$(basename "$SHELL")" + SHELL_RC="$HOME/.${CURRENT_SHELL}rc" +fi + # Environment variables for Polkadot and Ethereum RPC URLs export ETH_MAINNET_HTTP_URL=https://eth.llamarpc.com @@ -240,7 +253,7 @@ function eth-rpc() { arg=$1 # Set default logging levels (can be overridden by environment variable) - RUST_LOG="${RUST_LOG:-info,eth-rpc=debug}" + RUST_LOG="${RUST_LOG:-info,eth-rpc=debug,jsonrpsee-server=trace}" # Define the polkadot-sdk directory path POLKADOT_SDK_DIR=~/polkadot-sdk @@ -270,14 +283,17 @@ function eth-rpc() { # Requires custom mitmproxy branch: https://github.com/pgherveou/mitmproxy shift # Strip "proxy" - # Detect and handle "--release" and NODE_RPC_URL + # Detect and handle "--release", "--record", and NODE_RPC_URL bin_folder="debug" NODE_RPC_URL="" + record_mode="false" args=() for var in "$@"; do if [ "$var" = "--release" ]; then bin_folder="release" + elif [ "$var" = "--record" ]; then + record_mode="true" elif [ -z "$NODE_RPC_URL" ] && [[ "$var" =~ ^wss?:// ]]; then NODE_RPC_URL="$var" else @@ -287,7 +303,7 @@ function eth-rpc() { # Default NODE_RPC_URL if not provided if [ -z "$NODE_RPC_URL" ]; then - NODE_RPC_URL="wss://westend-asset-hub-rpc.polkadot.io" + NODE_RPC_URL="wss://localhost:9944" fi # Kill any existing mitmproxy instances and start new one @@ -298,24 +314,49 @@ function eth-rpc() { tmux rename-window "eth-rpc" fi - # Build and execute command with output redirection + # Build and execute command with optional output redirection PS4=' ' set -x - "$POLKADOT_SDK_DIR/target/$bin_folder/eth-rpc" --log="$RUST_LOG" --no-prometheus --dev --rpc-port 8546 --node-rpc-url "$NODE_RPC_URL" "${args[@]}" 2>&1 | tee /tmp/eth-rpc.log + if [ "$record_mode" = "true" ]; then + "$POLKADOT_SDK_DIR/target/$bin_folder/eth-rpc" \ + --log="$RUST_LOG" \ + --no-prometheus \ + --dev \ + --rpc-port 8546 \ + --node-rpc-url "$NODE_RPC_URL" \ + "${args[@]}" 2>&1 | + tee /tmp/eth-rpc.log | + tee >(grep --line-buffered 'recv=' | + grep --line-buffered '\\"method\\":\\"eth_sendRawTransaction\\"' | + sed -u -E 's/.*recv="(.*)"/\1/' | + sed -u 's/\\"/"/g' \ + >/tmp/eth-rpc-requests.log) + else + "$POLKADOT_SDK_DIR/target/$bin_folder/eth-rpc" \ + --log="$RUST_LOG" \ + --no-prometheus \ + --dev \ + --rpc-port 8546 \ + --node-rpc-url "$NODE_RPC_URL" \ + "${args[@]}" + fi { set +x; } 2>/dev/null ;; run) # Run pre-built binary from target/debug or target/release shift # Strip "run" - # Detect and handle "--release" and NODE_RPC_URL + # Detect and handle "--release", "--record", and NODE_RPC_URL bin_folder="debug" NODE_RPC_URL="" + record_mode="false" args=() for var in "$@"; do if [ "$var" = "--release" ]; then bin_folder="release" + elif [ "$var" = "--record" ]; then + record_mode="true" elif [ -z "$NODE_RPC_URL" ] && [[ "$var" =~ ^wss?:// ]]; then NODE_RPC_URL="$var" else @@ -328,26 +369,84 @@ function eth-rpc() { NODE_RPC_URL="wss://westend-asset-hub-rpc.polkadot.io" fi - # Build command + # Build and execute command with optional output redirection PS4=' ' set -x - "$POLKADOT_SDK_DIR/target/$bin_folder/eth-rpc" --log="$RUST_LOG" --no-prometheus --dev --node-rpc-url "$NODE_RPC_URL" "${args[@]}" 2>&1 | tee /tmp/eth-rpc.log + if [ "$record_mode" = "true" ]; then + "$POLKADOT_SDK_DIR/target/$bin_folder/eth-rpc" \ + --log="$RUST_LOG" \ + --no-prometheus \ + --dev \ + --node-rpc-url "$NODE_RPC_URL" \ + "${args[@]}" 2>&1 | + tee /tmp/eth-rpc.log | + tee >(grep --line-buffered 'recv=' | + grep --line-buffered '\\"method\\":\\"eth_sendRawTransaction\\"' | + sed -u -E 's/.*recv="(.*)"/\1/' | + sed -u 's/\\"/"/g' \ + >/tmp/eth-rpc-requests.log) + else + "$POLKADOT_SDK_DIR/target/$bin_folder/eth-rpc" \ + --log="$RUST_LOG" \ + --no-prometheus \ + --dev \ + --node-rpc-url "$NODE_RPC_URL" \ + "${args[@]}" + fi { set +x; } 2>/dev/null ;; *) # Default: build and run in one command using cargo run - # Accept optional node RPC URL or use default - if [ -n "$1" ]; then - NODE_RPC_URL="$1" - shift - else + # Detect and handle "--record" and NODE_RPC_URL + NODE_RPC_URL="" + record_mode="false" + args=() + + for var in "$@"; do + if [ "$var" = "--record" ]; then + record_mode="true" + elif [ -z "$NODE_RPC_URL" ] && [[ "$var" =~ ^wss?:// ]]; then + NODE_RPC_URL="$var" + else + args+=("$var") + fi + done + + # Default NODE_RPC_URL if not provided + if [ -z "$NODE_RPC_URL" ]; then NODE_RPC_URL="wss://westend-asset-hub-rpc.polkadot.io" fi - # Build the command to display + # Build and execute command with optional output redirection PS4=' ' set -x - cargo run --quiet --manifest-path "$POLKADOT_SDK_DIR/Cargo.toml" -p pallet-revive-eth-rpc -- --log="$RUST_LOG" --no-prometheus --dev --node-rpc-url "$NODE_RPC_URL" "$@" 2>&1 | tee /tmp/eth-rpc.log + if [ "$record_mode" = "true" ]; then + cargo run \ + --quiet \ + --manifest-path "$POLKADOT_SDK_DIR/Cargo.toml" \ + -p pallet-revive-eth-rpc -- \ + --log="$RUST_LOG" \ + --no-prometheus \ + --dev \ + --node-rpc-url "$NODE_RPC_URL" \ + "${args[@]}" 2>&1 | + tee /tmp/eth-rpc.log | + tee >(grep --line-buffered 'recv=' | + grep --line-buffered '\\"method\\":\\"eth_sendRawTransaction\\"' | + sed -u -E 's/.*recv="(.*)"/\1/' | + sed -u 's/\\"/"/g' \ + >/tmp/eth-rpc-requests.log) + else + cargo run \ + --quiet \ + --manifest-path "$POLKADOT_SDK_DIR/Cargo.toml" \ + -p pallet-revive-eth-rpc -- \ + --log="$RUST_LOG" \ + --no-prometheus \ + --dev \ + --node-rpc-url "$NODE_RPC_URL" \ + "${args[@]}" + fi { set +x; } 2>/dev/null ;; esac @@ -389,13 +488,13 @@ function revive_dev_stack() { done # Create new 'servers' window in detached mode - tmux new-window -d -n servers "zsh -c 'source $HOME/.zshrc; dev-node run $build_type; exec \$SHELL'" + tmux new-window -d -n servers "$CURRENT_SHELL -c 'source $SHELL_RC; dev-node run $build_type; exec \$SHELL'" # Split the window, run eth-rpc with or without proxy if [ "$use_proxy" = "false" ]; then - tmux split-window -t servers -d "zsh -c 'source $HOME/.zshrc; eth-rpc run ws://localhost:9944 $build_type; exec \$SHELL'" + tmux split-window -t servers -d "$CURRENT_SHELL -c 'source $SHELL_RC; eth-rpc run ws://localhost:9944 $build_type; exec \$SHELL'" else - tmux split-window -t servers -d "zsh -c 'source $HOME/.zshrc; eth-rpc proxy ws://localhost:9944 $build_type; exec \$SHELL'" + tmux split-window -t servers -d "$CURRENT_SHELL -c 'source $SHELL_RC; eth-rpc proxy ws://localhost:9944 $build_type; exec \$SHELL'" fi # Select the first pane @@ -621,6 +720,25 @@ function passet() { esac } +# Runs geth (Ethereum node) in development mode +# Useful for testing contracts against standard Ethereum +# Usage: geth-dev [port] +# Examples: +# geth-dev - Use default port 8545 +# geth-dev 8546 - Use custom port 8546 +function geth-dev() { + # Parse port argument with default + port="${1:-8545}" + + # Rename tmux window if running in tmux + if [ -n "$TMUX" ]; then + tmux rename-window "geth" + fi + + # Start geth in development mode with HTTP RPC enabled + geth --http --http.api web3,eth,txpool,miner,debug,net --http.port "$port" --dev +} + # Runs geth (Ethereum node) with mitmproxy for traffic inspection # Useful for debugging Ethereum RPC calls during development # Usage: geth-proxy [proxy_port] [server_port] @@ -656,7 +774,7 @@ function geth_stack() { # Create new 'servers' window in detached mode # Source shell config and run geth-proxy with default ports (8545->8546) - tmux new-window -d -n servers "zsh -c 'source $HOME/.zshrc; geth-proxy 8545 8546; exec \$SHELL'" + tmux new-window -d -n servers "$CURRENT_SHELL -c 'source $SHELL_RC; geth-proxy 8545 8546; exec \$SHELL'" } # Runs the complete PAsset Hub stack (passet node + eth-rpc) in tmux window @@ -681,13 +799,13 @@ function passet_stack() { done # Create new 'servers' window running passet node - tmux new-window -d -n servers "zsh -c 'source $HOME/.zshrc; passet run; exec \$SHELL'" + tmux new-window -d -n servers "$CURRENT_SHELL -c 'source $SHELL_RC; passet run; exec \$SHELL'" # Split the window and run eth-rpc with or without proxy if [ "$use_proxy" = "false" ]; then - tmux split-window -t servers -d "zsh -c 'source $HOME/.zshrc; eth-rpc run ws://localhost:9944; exec \$SHELL'" + tmux split-window -t servers -d "$CURRENT_SHELL -c 'source $SHELL_RC; eth-rpc run ws://localhost:9944; exec \$SHELL'" else - tmux split-window -t servers -d "zsh -c 'source $HOME/.zshrc; eth-rpc proxy ws://localhost:9944; exec \$SHELL'" + tmux split-window -t servers -d "$CURRENT_SHELL -c 'source $SHELL_RC; eth-rpc proxy ws://localhost:9944; exec \$SHELL'" fi # Select the first pane @@ -716,13 +834,13 @@ function westend_stack() { done # Create new 'servers' window running westend node - tmux new-window -d -n servers "zsh -c 'source $HOME/.zshrc; westend run; exec \$SHELL'" + tmux new-window -d -n servers "$CURRENT_SHELL -c 'source $SHELL_RC; westend run; exec \$SHELL'" # Split the window and run eth-rpc with or without proxy if [ "$use_proxy" = "false" ]; then - tmux split-window -t servers -d "zsh -c 'source $HOME/.zshrc; eth-rpc run ws://localhost:9944; exec \$SHELL'" + tmux split-window -t servers -d "$CURRENT_SHELL -c 'source $SHELL_RC; eth-rpc run ws://localhost:9944; exec \$SHELL'" else - tmux split-window -t servers -d "zsh -c 'source $HOME/.zshrc; eth-rpc proxy ws://localhost:9944; exec \$SHELL'" + tmux split-window -t servers -d "$CURRENT_SHELL -c 'source $SHELL_RC; eth-rpc proxy ws://localhost:9944; exec \$SHELL'" fi # Select the first pane diff --git a/scripts/re-run-all.sh b/scripts/re-run-all.sh new file mode 100755 index 0000000..05fe3e7 --- /dev/null +++ b/scripts/re-run-all.sh @@ -0,0 +1,99 @@ +#!/bin/bash + +# Script to send RPC requests from eth-rpc.log to localhost:8545 +# Collects all errors and reports them at the end +# Usage: ./run-all.sh [log-file] + +set -e + +LOG_FILE="${1:-/tmp/eth-rpc-requests.log}" +RPC_URL="http://localhost:8545" + +# Check if log file exists +if [ ! -f "$LOG_FILE" ]; then + echo "Error: Log file $LOG_FILE not found" + exit 1 +fi + +# Counter for tracking transactions +tx_count=0 +failed_txs=() +errored_txs=() + +# Read each line from the log file +while IFS= read -r line; do + tx_count=$((tx_count + 1)) + printf "Sending tx %4d" "$tx_count" + + # Send the raw transaction + response=$(curl -s -X POST \ + -H "Content-Type: application/json" \ + -H "Accept: application/json" \ + -d "$line" \ + "$RPC_URL") + + # Extract transaction hash from response using jq + tx_hash=$(echo "$response" | jq -r '.result') + + # Print the hash (without newline, will add status later) + echo -n " $tx_hash" + + if [ -z "$tx_hash" ] || [ "$tx_hash" = "null" ]; then + echo -e " \033[31mERROR: Failed to get transaction hash\033[0m" + errored_txs+=("$tx_count: Failed to get transaction hash from response") + continue + fi + + # Get the transaction receipt + receipt_request="{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getTransactionReceipt\",\"params\":[\"$tx_hash\"]}" + receipt_response=$(curl -s -X POST \ + -H "Content-Type: application/json" \ + -H "Accept: application/json" \ + -d "$receipt_request" \ + "$RPC_URL") + + # Check if receipt was returned + receipt_result=$(echo "$receipt_response" | jq -r '.result') + if [ "$receipt_result" = "null" ] || [ -z "$receipt_result" ]; then + echo -e " \033[31mERROR: No receipt found\033[0m" + errored_txs+=("$tx_count $tx_hash: No receipt found") + continue + fi + + # Extract status from receipt (0x1 = success, 0x0 = failure) + receipt_status=$(echo "$receipt_response" | jq -r '.result.status') + if [ "$receipt_status" = "0x1" ]; then + echo -e " status: \033[32m✓\033[0m" + else + echo -e " status: \033[31m✗\033[0m" + failed_txs+=("$tx_count $tx_hash") + fi + +done <"$LOG_FILE" + +echo "" +echo "All transactions processed!" +echo "Total transactions: $tx_count" + +# Display errored transactions if any +if [ ${#errored_txs[@]} -gt 0 ]; then + echo "" + echo -e "\033[31mErrored transactions (${#errored_txs[@]}):\033[0m" + for errored_tx in "${errored_txs[@]}"; do + echo " tx $errored_tx" + done +fi + +# Display failed transactions if any +if [ ${#failed_txs[@]} -gt 0 ]; then + echo "" + echo -e "\033[31mFailed transactions (${#failed_txs[@]}):\033[0m" + for failed_tx in "${failed_txs[@]}"; do + echo " tx $failed_tx" + done +fi + +# Display success message if no errors or failures +if [ ${#errored_txs[@]} -eq 0 ] && [ ${#failed_txs[@]} -eq 0 ]; then + echo -e "\033[32mAll transactions succeeded! ✓\033[0m" +fi diff --git a/tools/build.ts b/tools/build.ts index bb50d5f..23eb99e 100644 --- a/tools/build.ts +++ b/tools/build.ts @@ -108,7 +108,7 @@ async function pvmCompile(file: Deno.DirEntry, sources: CompileInput) { args: ['--version'], stdout: 'piped', }).output() - ).stdout + ).stdout, ) .trim() } @@ -140,7 +140,7 @@ function evmCompile(file: Deno.DirEntry, sources: CompileInput) { return solc.compile(JSON.stringify(input), { import: (relativePath: string) => { const source = Deno.readTextFileSync( - resolc.tryResolveImport(relativePath) + resolc.tryResolveImport(relativePath), ) return { contents: source } }, @@ -176,8 +176,8 @@ for (const file of input) { // Create marker files to track if this source has been compiled const pvmSourceMarkerFile = join(pvmDir, `.${name}.sha256.txt`) const pvmSourceMarkerHash = readCachedHash(pvmSourceMarkerFile) - const needsPvmCompilation = - !solcOnly && (force || pvmSourceMarkerHash !== sourceHash) + const needsPvmCompilation = !solcOnly && + (force || pvmSourceMarkerHash !== sourceHash) const evmSourceMarkerFile = join(evmDir, `.${name}.sha256.txt`) const evmSourceMarkerHash = readCachedHash(evmSourceMarkerFile) @@ -194,7 +194,7 @@ for (const file of input) { const bytecode = new Uint8Array( contract.evm.bytecode.object .match(/.{1,2}/g)! - .map((byte) => parseInt(byte, 16)) + .map((byte) => parseInt(byte, 16)), ) Deno.writeFileSync(pvmFile, bytecode) } @@ -203,19 +203,19 @@ for (const file of input) { writeCachedHash(pvmSourceMarkerFile, sourceHash) } else if (!solcOnly) { logger.debug( - `⏭️ Skipping PVM compilation for ${file.name} (unchanged)` + `⏭️ Skipping PVM compilation for ${file.name} (unchanged)`, ) } if (!needsEvmCompilation) { logger.debug( - `⏭️ Skipping EVM compilation for ${file.name} (unchanged)` + `⏭️ Skipping EVM compilation for ${file.name} (unchanged)`, ) continue } const evmOut = JSON.parse( - evmCompile(file, inputSources) + evmCompile(file, inputSources), ) as resolc.SolcOutput if (evmOut.errors) { @@ -245,7 +245,7 @@ for (const file of input) { const bytecode = new Uint8Array( bytecodeHex .match(/.{1,2}/g)! - .map((byte) => parseInt(byte, 16)) + .map((byte) => parseInt(byte, 16)), ) Deno.writeFileSync(evmFile, bytecode) } @@ -254,11 +254,13 @@ for (const file of input) { logger.info(`📜 Add ABI ${name}`) const abi = contract.abi const abiName = `${name}Abi` - const tsContent = `export const ${abiName} = ${JSON.stringify( - abi, - null, - 2 - )} as const\n` + const tsContent = `export const ${abiName} = ${ + JSON.stringify( + abi, + null, + 2, + ) + } as const\n` Deno.writeTextFileSync(abiFile, tsContent) generateAbiIndex = true } @@ -289,19 +291,20 @@ if (generateAbiIndex) { for (const abiFile of abiFiles) { const contractName = basename(abiFile.name, '.ts') const abiName = `${contractName}Abi` - const importStatement = `import { ${abiName} } from './abi/${contractName}.ts'` + const importStatement = + `import { ${abiName} } from './abi/${contractName}.ts'` indexCode.unshift(importStatement) indexCode.push(`${contractName}: ${abiName},`) } } catch (error) { logger.warn( - `⚠️ Could not read ABI directory (it may not exist yet): ${error}` + `⚠️ Could not read ABI directory (it may not exist yet): ${error}`, ) } indexCode.push('}') Deno.writeFileSync( join(codegenDir, `abis.ts`), - await format(indexCode.join('\n')) + await format(indexCode.join('\n')), ) } diff --git a/utils/index.ts b/utils/index.ts index 177eb53..be713f6 100644 --- a/utils/index.ts +++ b/utils/index.ts @@ -90,15 +90,16 @@ export async function createEnv({ function getByteCode( name: string, - bytecodeType: 'evm' | 'polkavm' = 'evm' + bytecodeType: 'evm' | 'polkavm' = 'evm', ): Hex { - const bytecode = - bytecodeType == 'evm' - ? Deno.readFileSync(`codegen/evm/${name}.bin`) - : Deno.readFileSync(`codegen/pvm/${name}.polkavm`) - return `0x${Array.from(bytecode) - .map((b: number) => b.toString(16).padStart(2, '0')) - .join('')}` as Hex + const bytecode = bytecodeType == 'evm' + ? Deno.readFileSync(`codegen/evm/${name}.bin`) + : Deno.readFileSync(`codegen/pvm/${name}.polkavm`) + return `0x${ + Array.from(bytecode) + .map((b: number) => b.toString(16).padStart(2, '0')) + .join('') + }` as Hex } const chain = defineChain({ @@ -156,10 +157,11 @@ export async function createEnv({ traceTransaction( txHash: Hex, tracer: Tracer, - tracerConfig?: TracerConfig[Tracer] + tracerConfig?: TracerConfig[Tracer], ) { - const params: Record = - tracer == null ? (tracerConfig ?? {}) : { tracer, tracerConfig } + const params: Record = tracer == null + ? (tracerConfig ?? {}) + : { tracer, tracerConfig } return client.request({ method: 'debug_traceTransaction' as never, @@ -169,7 +171,7 @@ export async function createEnv({ traceBlock( blockNumber: bigint, tracer: Tracer, - tracerConfig?: TracerConfig[Tracer] + tracerConfig?: TracerConfig[Tracer], ) { return client.request({ method: 'debug_traceBlockByNumber' as never, @@ -183,10 +185,11 @@ export async function createEnv({ traceCall( args: CallParameters, tracer: Tracer | null, - tracerConfig?: TracerConfig[Tracer] + tracerConfig?: TracerConfig[Tracer], ) { - const params: Record = - tracer == null ? (tracerConfig ?? {}) : { tracer, tracerConfig } + const params: Record = tracer == null + ? (tracerConfig ?? {}) + : { tracer, tracerConfig } return client.request({ method: 'debug_traceCall' as never,