A TypeScript-based CLI tool to simulate EVM contract calls using ethers.js and trace errors with detailed decoding.
- Quick Start
- Features
- Prerequisites
- Installation
- Configuration
- Usage
- Trace Output Examples
- Project Structure
- Error Handling
- Troubleshooting
- Advanced Features Roadmap
- FAQ
- Contributing
- License
# 1. Install dependencies
yarn install
# 2. Copy environment template
cp .env.example .env
# 3. Configure your transaction (edit .env)
CONTRACT_ADDRESS=0x... # Target contract
FUNCTION_CALLDATA=0x... # Encoded function call
FROM_ADDRESS=0x... # Caller address
RPC_URL=https://... # RPC endpoint
# 4. Run simulation
yarn simulate # Standard simulation
yarn simulate:anvil # Fork simulation with full tracing- π Simulate contract calls on any EVM-compatible network
- π³ Full transaction tracing with hierarchical call trees (Contract A β B β C)
- π³ Anvil fork simulation at historical blocks using Docker
- π Auto-fetch ABIs from Explorer APIs (Etherscan v2, v1, and Blockscout)
- π Contract name resolution - Display human-readable names in traces
- π¨ Color-coded trace output with ANSI color syntax highlighting
- π Decoded function signatures - Show readable function calls instead of selectors
β οΈ Custom error decoding - Parse custom errors with arguments- π€ Output value decoding - Decode function return values with type-aware formatting
- π·οΈ Type-specific colors - Different colors for addresses, booleans, numbers, etc.
- π Address formatting - Underlined addresses with optional contract names
- π¨ Advanced error diagnostics - Pinpoint exact revert location in call stack
- π‘ Troubleshooting hints - Automatic suggestions for common error patterns
- π Nested error tracking - Identify which subcall caused the revert
- π Gas analysis - Track gas usage and percentages across calls
- β Type-safe TypeScript implementation
- π§Ή ESLint and Prettier for code quality
- π Zero-config setup for most networks
- π¦ Automatic ABI caching for performance
- Node.js >= 18.x
- Yarn package manager
- Docker and Docker Compose (for Anvil fork simulation)
For Standard Simulation (yarn simulate):
- Any RPC endpoint (free or paid)
- Optional:
debug_traceCallsupport for transaction tracing (Alchemy Archive, Hardhat, Anvil)
For Anvil Fork Simulation (yarn simulate:anvil):
- Does NOT require archive node - works with standard free RPC endpoints
- RPC must support
eth_getBlockByNumberandeth_call(all standard RPCs) - Limitations:
- Some free RPCs may have rate limits
- Historical block data must be available (usually last 128 blocks minimum)
- Chain ID is auto-detected from RPC for Explorer API compatibility
Recommended RPC Providers:
- Free: Public RPC endpoints (e.g.,
https://ethereum-sepolia-rpc.publicnode.com) - Paid: Alchemy, Infura, QuickNode (better rate limits and archive access)
| Feature | Standard (yarn simulate) |
Anvil Fork (yarn simulate:anvil) |
|---|---|---|
| Setup | Just RPC URL | RPC URL + Docker |
| Tracing | Optional (RPC-dependent) | Always enabled |
| Archive Node | Required for old blocks | Not required |
| Historical State | Current state only | Any historical block |
| Speed | Faster (direct RPC) | Slightly slower (fork + Docker) |
| Use Case | Quick checks, current state | Deep debugging, historical analysis |
| Cost | Free with public RPC | Free (uses Docker locally) |
| Best For | Production monitoring | Development & debugging |
Recommendation: Use Anvil fork simulation for comprehensive debugging and historical analysis. Use standard simulation for quick checks on current state.
yarn install-
Copy the example environment file:
cp .env.example .env
-
Update
.envwith your configuration:# Required: Transaction details CONTRACT_ADDRESS=0x1234567890123456789012345678901234567890 FUNCTION_CALLDATA=0x12345678... FROM_ADDRESS=0x0000000000000000000000000000000000000000 RPC_URL=https://eth-mainnet.g.alchemy.com/v2/your-api-key # Optional: For Anvil fork simulation BLOCK_NUMBER=19000000 # Optional: Auto-fetch ABIs from Explorer API AUTO_FETCH_ABIS=true EXPLORER_API_URL=https://api.etherscan.io/v2/api ETHERSCAN_API_KEY=YourApiKeyToken # Optional: Trace timeout (default: 30000ms) TRACE_TIMEOUT=30000
Flashpoint supports multiple Explorer APIs with automatic chain ID detection:
Etherscan API v2 (Unified - Recommended)
EXPLORER_API_URL=https://api.etherscan.io/v2/api
ETHERSCAN_API_KEY=YourApiKeyToken
# Supports 50+ chains via chainid parameter (auto-detected from RPC)Etherscan API v1 (Chain-specific)
# Ethereum Mainnet
EXPLORER_API_URL=https://api.etherscan.io/api
ETHERSCAN_API_KEY=YourApiKeyToken
# Sepolia Testnet
EXPLORER_API_URL=https://api-sepolia.etherscan.io/api
ETHERSCAN_API_KEY=YourApiKeyToken
# Polygon
EXPLORER_API_URL=https://api.polygonscan.com/api
ETHERSCAN_API_KEY=YourApiKeyToken
# BSC
EXPLORER_API_URL=https://api.bscscan.com/api
ETHERSCAN_API_KEY=YourApiKeyToken
# Arbitrum
EXPLORER_API_URL=https://api.arbiscan.io/api
ETHERSCAN_API_KEY=YourApiKeyToken
# Optimism
EXPLORER_API_URL=https://api-optimistic.etherscan.io/api
ETHERSCAN_API_KEY=YourApiKeyTokenBlockscout (Open Source)
# Base
EXPLORER_API_URL=https://base.blockscout.com/api
# API key optional for most public instances
# Gnosis Chain
EXPLORER_API_URL=https://gnosis.blockscout.com/api
# Custom Blockscout instance
EXPLORER_API_URL=https://explorer.yourchain.com/apiHow it works:
- Chain ID is automatically detected from your RPC connection
- For Etherscan v2: Chain ID is sent as
chainidparameter - For Etherscan v1/Blockscout: Use chain-specific endpoint
- ABIs are cached locally to minimize API calls
- Rate limiting: 200ms between requests (5 req/sec)
Simulate a contract call on the current state:
yarn simulateThis will:
- Validate your environment configuration
- Connect to the specified RPC endpoint
- Simulate the contract call with optional tracing
- Display detailed results or error traces
For simulating at historical blocks with full transaction tracing:
# Run simulation (automatically starts/stops Anvil container)
yarn simulate:anvilThe simulate:anvil command will:
- Automatically start the Anvil Docker container (if not running)
- Fork the network at the block specified in
.env - Auto-detect chain ID from the fork source network for Explorer API
- Execute the simulation with full call tracing
- Automatically stop the container after completion
Manual container management (optional):
yarn anvil:start # Manually start container
yarn anvil:stop # Manually stop container
yarn anvil:logs # View Anvil logsImportant Notes:
β οΈ Non-Archive RPC: Works with standard RPC endpoints (no archive node required)β οΈ Chain ID Detection: Automatically fetches chain ID from the original RPC for Explorer APIβ οΈ Rate Limits: Subject to RPC provider rate limits for both fork source and Explorer API calls
See ANVIL_SIMULATION.md for detailed documentation.
======================================================================
TRANSACTION TRACE
======================================================================
CALL 0xf3fb62e0cc08eb1fe9fa090aa4f18a09b49e4f96 (MorphoLiquidationGateway) β 0x8827171fcb8739a8e5efce10b42004cb96c269b5 (Vault)
ββ Function: liquidate(address,uint256,address)
ββ Gas: 500,000 (Used: 234,567, 46.9%)
ββ Decoded Output:
β [0]: true
β [1]: 0x1234567890123456789012345678901234567890 (TokenContract)
β [2]: 1500000000000000000
ββ Raw Output: 0x0000000000000000000000000000000000000000000000000000000000000001
ββ Input Selector: 0x12345678
β
ββ DELEGATECALL 0x8827171fcb8739a8e5efce10b42004cb96c269b5 (Vault) β 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 (USDC)
ββ Function: transfer(address,uint256)
ββ Gas: 100,000 (Used: 45,123, 45.1%)
ββ Decoded Output:
β [0]: true
ββ Raw Output: 0x0000000000000000000000000000000000000000000000000000000000000001
======================================================================
SUMMARY
======================================================================
Total Gas Used: 234,567
Call Frames: 2
Max Depth: 2
Status: SUCCESS
======================================================================
======================================================================
TRANSACTION TRACE
======================================================================
CALL 0xf3fb... (MorphoLiquidationGateway) β 0x8827... (Vault)
ββ Function: liquidate(address,uint256,address)
ββ Gas: 500,000 (Used: 123,456, 24.7%)
ββ ERROR: InsufficientCollateral(uint256,uint256)
β arg0: 1000000000000000000
β arg1: 500000000000000000
ββ Raw Error Data: 0x82b42900000000000000000000000000000000000000000000000de0b6b3a7640000...
β
ββ STATICCALL 0x8827... (Vault) β 0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419 (ChainlinkOracle)
ββ Function: latestRoundData()
ββ Gas: 50,000 (Used: 12,345, 24.7%)
ββ Decoded Output:
β [0]: 18446744073709551615
β [1]: 180000000000
β [2]: 1704067200
β [3]: 1704067200
β [4]: 18446744073709551615
======================================================================
SUMMARY
======================================================================
Total Gas Used: 123,456
Call Frames: 2
Max Depth: 2
Status: FAILED
Error: InsufficientCollateral
======================================================================
When running in a terminal with color support, the trace output includes:
- Call Types: Different colors for CALL (cyan), DELEGATECALL (magenta), STATICCALL (yellow)
- Addresses: Magenta + underlined with optional contract names in blue
- Functions: Cyan for function signatures
- Gas: Yellow for gas values
- Output: Green for return data
- Errors: Red for error messages
- Booleans: Green for
true, red forfalse - Selectors: Gray for function/error selectors
# Build the project
yarn build
# Run linting
yarn lint
# Fix linting issues
yarn lint:fix
# Format code
yarn format
# Check formatting
yarn format:check
# Type checking
yarn typecheckflashpoint/
βββ src/
β βββ command/
β β βββ simulate.ts # Standard simulation
β β βββ simulate-anvil.ts # Anvil fork simulation
β βββ utils/
β β βββ logger.ts # Color-coded logging utility
β β βββ validator.ts # Environment and input validation
β β βββ abi-loader.ts # Load contract ABIs from ./abis
β β βββ etherscan-client.ts # Fetch ABIs from Explorer API (Etherscan/Blockscout)
β β βββ function-decoder.ts # Function/error signature decoder
β β βββ trace-client.ts # debug_traceCall RPC client
β β βββ trace-parser.ts # Parse call frames from traces
β β βββ trace-visualizer.ts # Render tree visualization
βββ abis/ # Contract ABIs (auto-created)
β βββ README.md # Instructions for adding ABIs
βββ docker-compose.yml # Anvil Docker setup
βββ ANVIL_SIMULATION.md # Anvil fork documentation
βββ .env.example # Environment variables template
βββ tsconfig.json # TypeScript configuration
βββ eslint.config.mjs # ESLint configuration
βββ .prettierrc # Prettier configuration
βββ package.json # Project dependencies and scripts
The tool uses ethers-decode-error to provide detailed error information when simulations fail:
- Error type and name
- Revert reason
- Function arguments
- Error signature
- Additional context (insufficient funds, gas issues, etc.)
To decode custom contract errors (like DepositAlreadySubmitted()), place your contract ABI files in the ./abis directory:
- Create the
abisdirectory (auto-created on first run) - Add your contract ABI JSON files (e.g.,
router.json,token.json) - The simulator will automatically load and use them for error decoding
Supported formats:
- Raw ABI array:
[{"type":"error","name":"CustomError"...}] - Hardhat compilation output:
{"abi": [...], "bytecode": "..."}
Example:
# Add your contract ABI
echo '[{"type":"error","name":"DepositAlreadySubmitted","inputs":[]}]' > abis/router.json
# Run simulation - custom errors will now be decoded
yarn simulate1. "Failed to connect to Anvil after 10 attempts"
- Check if Docker is running:
docker ps - View Anvil logs:
yarn anvil:logs - Manually stop and restart:
yarn anvil:stop && yarn anvil:start
2. "No ABI found for contract (NOTOK)" when using Anvil
- This happens when Etherscan API v2 receives wrong chain ID
- β Fixed in latest version: Chain ID is now auto-detected from original RPC
- Verify logs show:
[DEBUG] Using original network chain ID for Etherscan: <chainId>
3. "RPC does not support debug_traceCall"
- Normal for free/public RPCs - tracing is optional
- Simulation will fall back to standard call
- For full tracing, use: Alchemy Archive nodes, Hardhat, or Anvil fork
4. "Historical state is not available" (Anvil error)
- Free RPC doesn't have archive access for old blocks
- β
Fixed: Anvil now uses
--no-storage-caching --accounts 0 - Try a more recent block number
5. Rate limit errors from Explorer API
- Built-in rate limiting: 200ms between requests (5 req/sec)
- For Etherscan: Get a free API key to increase limits
- For Blockscout: Most public instances don't require API keys
All code is enforced with:
- TypeScript strict mode
- ESLint with TypeScript rules
- Prettier for consistent formatting
- Create a new file in
src/command/ - Implement your command logic
- Add a script in
package.json - Update this README
We're planning to add these advanced features in future releases. Vote for your favorites or contribute!
Why: Most requested feature by DeFi developers, critical for understanding protocol behavior
Features:
- Show storage slot changes before/after each call
- Display balance transfers as flow diagram
- Decode storage values using contract ABIs
- Export state changes to JSON/CSV
- Highlight critical state modifications (e.g., ownership changes)
- Implementation: Use
debug_traceCallwithprestateTracer
Use Cases:
- Verify DEX pool state changes
- Debug lending protocol liquidations
- Audit governance proposal effects
- Trace token balance flows
Why: Save real money by identifying expensive operations
Features:
- Highlight top 10 gas-consuming operations
- Compare gas usage across different call paths
- Detect common anti-patterns:
- Storage reads in loops (SLOAD spam)
- Redundant external calls
- Inefficient data structures
- Generate gas optimization report with savings estimates
- Visual gas flamegraph for complex traces
Use Cases:
- Optimize contract deployments
- Reduce transaction costs
- Identify gas griefing vectors
Why: Debug why transactions behave differently
Features:
- Side-by-side trace comparison view
- Highlight divergence points in execution
- Gas difference analysis with explanations
- Compare successful vs failed transactions
- Compare different block numbers (state evolution)
- Compare different input parameters
Use Cases:
- Debug failed vs successful transactions
- Analyze impact of parameter changes
- Verify upgrade behavior (proxy contracts)
Why: Static output is hard to navigate for complex traces
Features:
- Terminal UI with keyboard navigation (built with
blessedorink) - Expand/collapse nested call frames
- Filter by call type (CALL, DELEGATECALL, etc.)
- Search for specific addresses/functions
- Copy addresses/data to clipboard
- Export filtered traces to JSON
- Dark/light theme support
Why: Test complex workflows and MEV strategies
Features:
- Load transaction sequences from JSON/CSV
- Simulate MEV bundles (flashbots-style)
- Test different transaction orderings
- Calculate total gas and profit/loss
- Detect MEV opportunities (arbitrage, liquidation)
- Flash loan attack simulation
Example Config:
{
"transactions": [
{"to": "0x...", "data": "0x...", "value": "0"},
{"to": "0x...", "data": "0x...", "value": "1000000000000000000"}
]
}Why: Build test cases from real transactions
Features:
- Record traces to portable format
- Replay on different networks/forks
- Generate Foundry test from trace
- Generate Hardhat test from trace
- CI/CD integration for regression testing
- Differential testing (trace vs actual execution)
Why: Opcode-level debugging for complex issues
Features:
- Step-by-step opcode execution viewer
- Show stack/memory/storage at each step
- Set breakpoints on specific opcodes
- Export execution trace for Foundry/Hardhat
- Implementation: Use
debug_traceCallwithopTracer
Why: Discover edge cases and security issues
Features:
- Auto-generate test inputs based on ABI
- Detect invariant violations
- Find revert conditions
- Export failing cases for unit tests
- Integration with Echidna/Medusa
Why: Catch vulnerabilities during development
Automated Checks:
- Reentrancy detection (CEI pattern violations)
- Unchecked external calls
- Insufficient access control
- Integer overflow/underflow (pre-0.8.0)
- Dangerous delegatecall patterns
- Unprotected selfdestruct
- Front-running vulnerabilities
Output: Security report with severity ratings (Critical, High, Medium, Low)
Why: Test DeFi protocols under various market conditions
Features:
- Mock Chainlink oracle responses
- Simulate Uniswap V2/V3 price changes
- Test liquidation thresholds
- Calculate slippage and MEV opportunities
- Stress test with extreme price movements
Why: Test cross-chain protocols
Features:
- Simulate on multiple chains simultaneously
- Mock bridge messages (LayerZero, Wormhole)
- Verify state consistency across chains
- Test cross-chain MEV strategies
Why: Help developers understand cryptic errors
Features:
- Send trace + error to LLM (Claude/GPT)
- Plain English error explanations
- Suggested fixes with code examples
- Link to similar issues on GitHub
- Generate debugging checklist
Want to help build these features? Here's how:
- Vote: Star β the features you want most in GitHub Issues
- Discuss: Join feature discussions and share your use cases
- Build: Pick an unassigned feature and submit a PR
- Sponsor: Help fund development of critical features
Feature Status Legend:
- Planned - Not started yet
- [π§] In Progress - Actively being developed
- [β ] Completed - Available in latest release
Have an idea not listed here? Open an issue with:
- Use Case: What problem does it solve?
- User Story: As a [role], I want [feature] so that [benefit]
- Alternatives: What workarounds exist today?
- Priority: How critical is this for your workflow?
See our GitHub Issues for full roadmap and active discussions.
Q: What's the difference between yarn simulate and yarn simulate:anvil?
A:
yarn simulate- Runs on current network state, requires RPC withdebug_traceCallfor full tracingyarn simulate:anvil- Forks network at specific block using Docker, always has full tracing support
Q: Do I need an archive node?
A: No! Anvil simulation works with standard free RPC endpoints. It uses --no-storage-caching --accounts 0 flags to avoid requiring archive access.
Q: Which Explorer API should I use?
A:
- Etherscan API v2 (recommended) - Single endpoint for 50+ chains with
chainidparameter - Etherscan API v1 - Chain-specific endpoints (legacy)
- Blockscout - Open source, often doesn't require API keys
Q: How does chain ID auto-detection work?
A: Flashpoint connects to your RPC endpoint and queries the network chain ID. This ensures the correct chain ID is used when fetching ABIs from Etherscan, even when simulating on Anvil (which uses chain ID 31337 locally).
Q: Why am I getting "No ABI found for contract (NOTOK)"?
A: Common causes:
- Contract not verified on Explorer - Add ABI manually to
./abisdirectory - Wrong Explorer API URL - Check you're using correct endpoint for your network
- Rate limiting - Wait a moment and retry
- Chain ID mismatch (fixed in latest version via auto-detection)
Q: Trace shows all on one line without formatting?
A: This was a bug in earlier versions. Update to latest version where trace rendering uses proper newlines (join('\n')).
Q: Can I decode custom errors from my own contracts?
A: Yes! Place your contract ABI JSON files in the ./abis directory. Supported formats:
- Raw ABI array:
[{"type":"error","name":"MyError"...}] - Hardhat output:
{"abi": [...], "bytecode": "..."}
Q: How do I simulate historical transactions?
A:
- Set
BLOCK_NUMBERin.envto the historical block - Use
yarn simulate:anvilto fork at that block - Ensure your RPC has historical block data (last 128 blocks for free RPCs)
Q: What if my RPC doesn't support debug_traceCall?
A: The simulation will fall back to standard eth_call. You'll see results but without the detailed call tree. For full tracing, use:
- Alchemy Archive nodes
- Hardhat node
- Anvil fork simulation (
yarn simulate:anvil)
Q: How many contracts can Flashpoint fetch ABIs for?
A: No hard limit, but rate limiting applies:
- Built-in: 200ms delay between requests (5 req/sec)
- Etherscan: 5 req/sec with API key, 1 req/sec without
- ABIs are cached locally after first fetch
Q: How long calldata can I use?
A: No limit on calldata length. Display is automatically truncated to 0x1234...5678 format for readability, but full data is used in simulation.
Q: Can I use this in CI/CD?
A: Yes! Flashpoint works great in CI/CD:
- name: Run EVM simulation
run: |
yarn simulate:anvil
env:
CONTRACT_ADDRESS: ${{ secrets.CONTRACT_ADDRESS }}
RPC_URL: ${{ secrets.RPC_URL }}Q: What types of calls can I trace?
A: All EVM call types are supported and color-coded:
CALL(cyan)DELEGATECALL(magenta)STATICCALL(yellow)CREATE/CREATE2(green)SELFDESTRUCT(red)
Q: Can I decode function return values?
A: Yes! If you have the contract ABI (auto-fetched or in ./abis), return values are automatically decoded with type-specific formatting:
- Addresses: Underlined + magenta, with contract names if available
- Booleans: Green for
true, red forfalse - Numbers: Plain formatting
- Arrays: JSON stringified
Q: How accurate is the gas estimation?
A: Gas estimates are exact for the simulated state. Real transaction gas may differ due to:
- State changes between simulation and execution
- Block gas limit and base fee changes
- MEV searcher interference
Q: Can I use custom ABIs for error decoding?
A: Yes, place ABI files in ./abis directory. Flashpoint will:
- Load local ABIs from
./abis - Auto-fetch ABIs from Explorer API (if enabled)
- Combine all ABIs for comprehensive decoding
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes with tests
- Submit a pull request
See CONTRIBUTING.md for detailed guidelines.
ISC