113 lines
3.7 KiB
Markdown
113 lines
3.7 KiB
Markdown
|
|
# Blockscout Forge Verification — Fix Evaluation & Dedicated API
|
|||
|
|
|
|||
|
|
**Date:** 2026-02-02
|
|||
|
|
**Status:** Evaluation complete; dedicated proxy implemented
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 1. Fix Evaluation
|
|||
|
|
|
|||
|
|
### What Was Attempted
|
|||
|
|
|
|||
|
|
| Change | Purpose | Result |
|
|||
|
|
|--------|---------|--------|
|
|||
|
|
| `location = /api` + `rewrite ^ /api/$is_args$args last` | Internal redirect `/api` → `/api/` to avoid 301 on POST | **Partial**: Eliminates nginx 301; does not fix API format mismatch |
|
|||
|
|
| `proxy_set_header Host 127.0.0.1` | Avoid Blockscout redirect when Host is IP | **Unclear**: 301 may originate elsewhere |
|
|||
|
|
| `VERIFIER_URL="http://${IP}/api/"` | Correct base URL per Blockscout docs | **Correct**: URL format is fine |
|
|||
|
|
|
|||
|
|
### Root Cause
|
|||
|
|
|
|||
|
|
Forge sends a **single JSON body** (Etherscan-style):
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"contractaddress": "0x...",
|
|||
|
|
"sourceCode": "{\"language\":\"Solidity\",\"sources\":{...}}",
|
|||
|
|
"codeformat": "solidity-standard-json-input",
|
|||
|
|
"contractname": "CCIPSender",
|
|||
|
|
"compilerversion": "v0.8.20+...",
|
|||
|
|
...
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Blockscout’s **Etherscan-compatible handler** (`/api?module=contract&action=verifysourcecode`) expects `module` and `action` in the **query string**. Forge does not add them and puts all data in the body. That produces:
|
|||
|
|
|
|||
|
|
> `Params 'module' and 'action' are required parameters`
|
|||
|
|
|
|||
|
|
### Conclusion
|
|||
|
|
|
|||
|
|
The nginx changes help routing and redirects but do **not** resolve the format mismatch. Forge’s payload is not compatible with the Etherscan-compatible RPC API.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. Dedicated API Approach
|
|||
|
|
|
|||
|
|
### Blockscout v2 Smart Contract API
|
|||
|
|
|
|||
|
|
Blockscout exposes a **v2 verification API** that accepts JSON:
|
|||
|
|
|
|||
|
|
- **Flattened code:** `POST /api/v2/smart-contracts/{address}/verification/via/flattened-code`
|
|||
|
|
- **Standard JSON input:** `POST /api/v2/smart-contracts/{address}/verification/via/standard-input`
|
|||
|
|
|
|||
|
|
This matches what Forge uses when it sends Standard JSON in `sourceCode`.
|
|||
|
|
|
|||
|
|
### Solution: Forge Verification Proxy
|
|||
|
|
|
|||
|
|
A small proxy service:
|
|||
|
|
|
|||
|
|
1. **Accepts** Forge’s Etherscan-style JSON POST.
|
|||
|
|
2. **Maps** fields to Blockscout v2 parameters.
|
|||
|
|
3. **Forwards** to `/api/v2/smart-contracts/{address}/verification/via/standard-input` (or flattened).
|
|||
|
|
4. **Returns** Blockscout’s response to Forge.
|
|||
|
|
|
|||
|
|
### Field Mapping
|
|||
|
|
|
|||
|
|
| Forge (Etherscan) | Blockscout v2 |
|
|||
|
|
|-------------------|---------------|
|
|||
|
|
| `contractaddress` | URL path `{address}` |
|
|||
|
|
| `sourceCode` | `files` (standard JSON) or `source_code` (flattened) |
|
|||
|
|
| `codeformat` | Chooses `/via/standard-input` vs `/via/flattened-code` |
|
|||
|
|
| `contractname` | `contract_name` |
|
|||
|
|
| `compilerversion` | `compiler_version` |
|
|||
|
|
| `optimizationUsed` | `is_optimization_enabled` |
|
|||
|
|
| `runs` | `optimization_runs` |
|
|||
|
|
| `constructorArguments` | `constructor_args` |
|
|||
|
|
| `evmversion` | `evm_version` |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. Implementation
|
|||
|
|
|
|||
|
|
See [`forge-verification-proxy/`](../../forge-verification-proxy/) for:
|
|||
|
|
|
|||
|
|
- Node.js/Express proxy
|
|||
|
|
- Field mapping and v2 API calls
|
|||
|
|
- Usage and deployment notes
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. Usage
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 1. Start the proxy (from project root; Blockscout API at 192.168.11.140:4000)
|
|||
|
|
BLOCKSCOUT_URL=http://192.168.11.140:4000 node forge-verification-proxy/server.js
|
|||
|
|
|
|||
|
|
# 2. Verify via proxy (preferred: ./scripts/verify/run-contract-verification-with-proxy.sh; or run verify-contracts-blockscout.sh)
|
|||
|
|
./scripts/verify-contracts-blockscout.sh
|
|||
|
|
|
|||
|
|
# Or directly:
|
|||
|
|
forge verify-contract <ADDR> <PATH> \
|
|||
|
|
--chain-id 138 \
|
|||
|
|
--verifier blockscout \
|
|||
|
|
--verifier-url "http://<proxy-host>:3080/" \
|
|||
|
|
--rpc-url "http://192.168.11.211:8545"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5. References
|
|||
|
|
|
|||
|
|
- [Blockscout Smart Contract Verification API v2](https://docs.blockscout.com/devs/verification/blockscout-smart-contract-verification-api)
|
|||
|
|
- [Blockscout Foundry Verification](https://docs.blockscout.com/devs/verification/foundry-verification)
|
|||
|
|
- [Etherscan RPC Contract API](https://docs.blockscout.com/devs/apis/rpc/contract) — module/action format
|