From 5b1d53587d76852fad1d9bfda90082adaf456b7c Mon Sep 17 00:00:00 2001 From: Larry Date: Tue, 10 Mar 2026 20:26:19 +0800 Subject: [PATCH 1/2] Add solc dependency for contract verification solc was used via dynamic import but missing from package.json, causing /contract/verify to 500 in production. Co-Authored-By: Claude Opus 4.6 --- package-lock.json | 103 +++++++++++++++++++++++++++++++++++++++++++++- package.json | 3 +- 2 files changed, 104 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index db9ca5c..03a2395 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,8 @@ "js-sha3": "^0.9.3", "jsonwebtoken": "^9.0.3", "pg": "^8.13.1", - "prom-client": "^15.1.3" + "prom-client": "^15.1.3", + "solc": "^0.8.28" }, "devDependencies": { "@types/bcrypt": "^6.0.0", @@ -847,6 +848,21 @@ "dev": true, "license": "MIT" }, + "node_modules/command-exists": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", + "license": "MIT" + }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/cookie": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", @@ -1136,6 +1152,26 @@ "node": ">=20" } }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -1385,6 +1421,14 @@ "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", "license": "MIT" }, + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "engines": { + "node": ">= 0.10.0" + } + }, "node_modules/minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", @@ -1439,6 +1483,15 @@ "wrappy": "1" } }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/pg": { "version": "8.20.0", "resolved": "https://registry.npmjs.org/pg/-/pg-8.20.0.tgz", @@ -1845,6 +1898,42 @@ "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", "license": "MIT" }, + "node_modules/solc": { + "version": "0.8.34", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.8.34.tgz", + "integrity": "sha512-qf8HajA1sHhXRV0hMSDXLjVbc4v3Q+SQbL9zok+1WmgVj7Z4oMjMHxaysCzfGtFVqjZdfDDJWyZI+tcx5bO7Dw==", + "license": "MIT", + "dependencies": { + "command-exists": "^1.2.8", + "commander": "^8.1.0", + "follow-redirects": "^1.12.1", + "js-sha3": "0.8.0", + "memorystream": "^0.3.1", + "semver": "^5.5.0", + "tmp": "0.0.33" + }, + "bin": { + "solcjs": "solc.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/solc/node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", + "license": "MIT" + }, + "node_modules/solc/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, "node_modules/sonic-boom": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.1.tgz", @@ -1918,6 +2007,18 @@ "node": ">=20" } }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "license": "MIT", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/toad-cache": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/toad-cache/-/toad-cache-3.7.0.tgz", diff --git a/package.json b/package.json index 0f78f58..34d2d59 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,8 @@ "js-sha3": "^0.9.3", "jsonwebtoken": "^9.0.3", "pg": "^8.13.1", - "prom-client": "^15.1.3" + "prom-client": "^15.1.3", + "solc": "^0.8.28" }, "devDependencies": { "@types/bcrypt": "^6.0.0", From 0122626e1d0a48b5f60856125c53e79ed9cb0602 Mon Sep 17 00:00:00 2001 From: Larry Date: Wed, 11 Mar 2026 13:17:04 +0800 Subject: [PATCH 2/2] chore: update default evmVersion from paris to cancun QFC node runs Cancun EVM spec. Update all contract verification defaults to compile with cancun (PUSH0, MCOPY, TSTORE/TLOAD). Existing verified contracts retain their stored evm_version. Co-Authored-By: Claude Opus 4.6 --- CLAUDE.md | 2 +- src/lib/vyper-compiler.ts | 2 +- src/routes/contracts.ts | 10 +++++----- src/routes/etherscan.ts | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 661acf6..8a28154 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -143,7 +143,7 @@ Admin commands via `indexer_state` table: rescan from height, retry failed block Refreshes `daily_stats` table after each batch. ## QFC-Specific Notes -- **EVM version**: QFC does NOT support PUSH0. Always `evmVersion: "paris"`. +- **EVM version**: QFC runs Cancun spec. Default `evmVersion: "cancun"`. Supports PUSH0, MCOPY, TSTORE/TLOAD. - **eth_call quirk**: QFC testnet may return `0x` for view functions. Use `eth_getStorageAt` as workaround. - **Proxy detection**: Reads EIP-1967/1822/Beacon storage slots to identify proxy contracts. - **Custom RPC methods**: `qfc_getEpoch`, `qfc_getValidators`, `qfc_getNodeInfo`, `qfc_getInferenceStats`, `qfc_getSupportedModels`, etc. diff --git a/src/lib/vyper-compiler.ts b/src/lib/vyper-compiler.ts index 7b82e80..a9a49b1 100644 --- a/src/lib/vyper-compiler.ts +++ b/src/lib/vyper-compiler.ts @@ -33,7 +33,7 @@ function exec(cmd: string, args: string[], timeout = 60_000): Promise<{ stdout: export async function compileVyper( source: string, version: string, - evmVersion: string = 'paris', + evmVersion: string = 'cancun', ): Promise { const tmpDir = await mkdtemp(join(tmpdir(), 'vyper-')); const srcPath = join(tmpDir, 'contract.vy'); diff --git a/src/routes/contracts.ts b/src/routes/contracts.ts index 71031f9..6496cbe 100644 --- a/src/routes/contracts.ts +++ b/src/routes/contracts.ts @@ -400,7 +400,7 @@ export default async function contractsRoutes(app: FastifyInstance) { // Dynamic import solc (optional dependency) // eslint-disable-next-line @typescript-eslint/no-require-imports const solc = await import(/* webpackIgnore: true */ 'solc' as string) as { compile: (input: string) => string }; - const evmVersion = body.evmVersion || 'paris'; + const evmVersion = body.evmVersion || 'cancun'; const input = JSON.stringify({ language: 'Solidity', sources: { 'contract.sol': { content: body.sourceCode } }, @@ -506,8 +506,8 @@ export default async function contractsRoutes(app: FastifyInstance) { // Ensure output selection includes what we need if (!jsonInput.settings) jsonInput.settings = {}; jsonInput.settings.outputSelection = { '*': { '*': ['abi', 'evm.bytecode', 'evm.deployedBytecode'] } }; - // QFC: always paris - if (!jsonInput.settings.evmVersion) jsonInput.settings.evmVersion = 'paris'; + // QFC: default to cancun + if (!jsonInput.settings.evmVersion) jsonInput.settings.evmVersion = 'cancun'; const solc = await import(/* webpackIgnore: true */ 'solc' as string) as { compile: (input: string) => string }; const output = JSON.parse(solc.compile(JSON.stringify(jsonInput))); @@ -617,7 +617,7 @@ export default async function contractsRoutes(app: FastifyInstance) { try { const solc = await import(/* webpackIgnore: true */ 'solc' as string) as { compile: (input: string) => string }; - const evmVersion = body.evm_version || 'paris'; + const evmVersion = body.evm_version || 'cancun'; const optimizationRuns = body.optimization_runs ?? null; // Build Solidity Standard JSON Input from multi-file sources @@ -764,7 +764,7 @@ export default async function contractsRoutes(app: FastifyInstance) { } try { - const evmVersion = body.evm_version || 'paris'; + const evmVersion = body.evm_version || 'cancun'; const result = await compileVyper(body.source_code, body.compiler_version, evmVersion); if ('error' in result) { diff --git a/src/routes/etherscan.ts b/src/routes/etherscan.ts index 9784cb9..2b59dbd 100644 --- a/src/routes/etherscan.ts +++ b/src/routes/etherscan.ts @@ -599,8 +599,8 @@ async function handleVerifySourceCode(params: Record): Promise('eth_getCode', [address, 'latest']);