mit einem Klick
debug-diff
// Debug a failed diffyscan verification run. Analyzes diffs, identifies root causes. Use when diffyscan exits with non-zero or shows unexpected diffs.
// Debug a failed diffyscan verification run. Analyzes diffs, identifies root causes. Use when diffyscan exits with non-zero or shows unexpected diffs.
Add support for a new blockchain explorer API to diffyscan. Use when a new chain or explorer type needs to be supported.
Create a new diffyscan verification config file for a deployed smart contract. Use when the user wants to verify a new contract or deployment.
Validate a diffyscan config file for correctness before running verification. Checks schema, required fields, type correctness, and common mistakes.
| name | debug-diff |
| description | Debug a failed diffyscan verification run. Analyzes diffs, identifies root causes. Use when diffyscan exits with non-zero or shows unexpected diffs. |
| argument-hint | ["config-path-or-contract-address"] |
Help debug a failed diffyscan verification. The user may provide a config path, contract address, or describe the failure.
Each run creates a timestamped directory under digest/. The timestamp is int(time.time()) captured at process start (see diffyscan/utils/constants.py):
digest/{timestamp}/logs.txt -- full run log (written by Logger in diffyscan/utils/logger.py)digest/{timestamp}/diffs/{contract_address}/{filename}.html -- per-file HTML source diff reportsFind the most recent run:
ls -lt digest/ | grep "^d" | head -5
Then inspect its contents:
# View the log
cat digest/<timestamp>/logs.txt
# List HTML diff reports for a specific contract
ls digest/<timestamp>/diffs/<contract_address>/
Source code diffs -- files differ between GitHub and the blockchain explorer:
commit in github_repo matches what was actually deployedrelative_root is correct (sources may live in a subdirectory of the repo)dependencies have the right commit hashes and relative_root paths--support-brownie for brownie-verified contracts)digest/{timestamp}/diffs/{address}/*.html) to see exactly which lines differ#, Filename, Found, Diffs, Origin, ReportBytecode diffs -- compiled bytecode does not match on-chain:
constructor_calldata or constructor_args under the bytecode_comparison config keybytecode_comparison.librariesdeep_match_bytecode() in diffyscan/utils/binary_verifier.py compares instruction-by-instruction and tolerates differences that fall within known immutable reference regions. If all diffs are in immutable positions it logs a warning and returns False (still reported as a non-match — use --allow-bytecode-diff 0xAddr to accept). Differences outside immutable regions raise BinVerifierErrorCompilation errors (raised as CompileError):
relative_root. The error message is: "missing GitHub sources for bytecode compilation; count=N; first=path1, path2..." (from run_bytecode_diff() in diffyscan/diffyscan.py)~/.cache/diffyscan/solc/ or equivalent via XDG_CACHE_HOME)Constructor calldata errors (raised as CalldataError from diffyscan/utils/calldata.py):
"No constructor calldata found for 0x... (not in config and not in explorer metadata)" -- need to add constructor_calldata or constructor_args to the config"Contract 0x... found in both 'constructor_args' and 'constructor_calldata'" -- only one should be specified per contractNetwork/API errors:
--cache-explorer to reuse cached responses (cached in .diffyscan_cache/)REMOTE_RPC_URL env var is valid and the node supports eth_callexplorer_token_env_var names the env var holding the API token; if absent, falls back to ETHERSCAN_EXPLORER_TOKEN| Symptom | Likely fix |
|---|---|
"missing GitHub sources for bytecode compilation" | Add the missing dependency to dependencies in the config with correct url, commit, and relative_root |
| Source diffs in OpenZeppelin or other dependency imports | Check the dependency commit hash matches what was used at deploy time |
| Bytecode mismatch after constructor | Add constructor_calldata (raw hex) or constructor_args (ABI-typed values) for the contract under bytecode_comparison |
"Failed to infer source path for library '...' from explorer metadata" | Add library addresses to bytecode_comparison.libraries keyed by "path/to/File.sol": {"LibName": "0xAddr"} |
| All files show diffs | Wrong commit or relative_root in github_repo |
| Single contract fails | May need a per-contract constructor_calldata or constructor_args entry |
"Bytecodes have differences not on the immutable reference position" | Real bytecode mismatch -- check compiler version, optimizer settings, EVM version, and library addresses |
"Exiting with non-zero code due to unallowed diffs" | Either fix the diffs or use --allow-source-diff 0xAddr / --allow-bytecode-diff 0xAddr for known acceptable diffs |
After fixing, suggest:
uv run diffyscan <config-path> --yes --cache-explorer --cache-github
--yes (-Y) skips the interactive prompt before each contract--cache-explorer (-E) reuses cached explorer responses from .diffyscan_cache/--cache-github (-G) reuses cached GitHub file fetches--support-brownie enables recursive retrieval for brownie-verified contracts with flattened import paths--allow-source-diff 0xAddr accepts source diffs for a specific address (can be repeated)--allow-bytecode-diff 0xAddr accepts bytecode diffs for a specific address (can be repeated)If any of these apply, explicitly tell the user — these are inherent constraints of the tool, not bugs to debug.
When a contract was verified on the explorer as a single flattened file (the explorer's SourceCode is a plain string, not JSON wrapped in {{}}), diffyscan cannot reliably reproduce the bytecode. Two problems arise:
ContractName field is used as the solc source file key (e.g. {"sources": {"MyContract": {...}}}). If the explorer does not return ContractName, or the name does not match the actual contract declaration in the Solidity source, the compiled output cannot be remapped and get_target_compiled_contract() will fail.How to detect: check the explorer response or logs — if the solc input has a source key that looks like a contract name (no .sol extension, no path separators) rather than a file path, the contract was flat-verified.
What to tell the user: explain that bytecode comparison is unreliable for this contract due to the flat-source limitation. Recommend using --allow-bytecode-diff 0xAddr to accept the mismatch, and note that source comparison is still valid.