diff --git a/.vscode/launch.json b/.vscode/launch.json
index 5896086b4..2567a70d4 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -190,10 +190,7 @@
// "--grep=v0.6.12",
"--exit",
],
- "outFiles": [
- "./**/*.js",
- "${workspaceFolder}/packages/lib-sourcify/build/**/*.js"
- ],
+ "sourceMaps": true,
"smartStep": true,
"console": "integratedTerminal",
// "internalConsoleOptions": "neverOpen"
diff --git a/environments/.env.dev b/environments/.env.dev
index aaae137c3..397e7e275 100644
--- a/environments/.env.dev
+++ b/environments/.env.dev
@@ -79,7 +79,7 @@ MOONSCAN_MOONBEAM_API_KEY=
MOONSCAN_MOONRIVER_API_KEY=
BOBASCAN_API_KEY=
GNOSISSCAN_API_KEY=
-OPTIMISTIC_ETHERSCAN_API_KEY=
+OPTIMISMSCAN_API_KEY=
# Needed to call create2 APIs, format is: TOKEN1,TOKEN2,...
CREATE2_CLIENT_TOKENS=
diff --git a/environments/.env.latest b/environments/.env.latest
index 789eaf4dc..05d34d5e5 100644
--- a/environments/.env.latest
+++ b/environments/.env.latest
@@ -78,7 +78,7 @@ MOONSCAN_MOONBEAM_API_KEY=xxx
MOONSCAN_MOONRIVER_API_KEY=xxx
BOBASCAN_API_KEY=xxx
GNOSISSCAN_API_KEY=xxx
-OPTIMISTIC_ETHERSCAN_API_KEY=xxx
+OPTIMISMSCAN_API_KEY=xxx
CREATE2_CLIENT_TOKENS=xxx
diff --git a/environments/.env.secrets.gpg b/environments/.env.secrets.gpg
index 41e9268d4..075fad503 100644
Binary files a/environments/.env.secrets.gpg and b/environments/.env.secrets.gpg differ
diff --git a/environments/.env.stable b/environments/.env.stable
index e9ef447aa..34200569e 100644
--- a/environments/.env.stable
+++ b/environments/.env.stable
@@ -76,7 +76,7 @@ MOONSCAN_MOONBEAM_API_KEY=xxx
MOONSCAN_MOONRIVER_API_KEY=xxx
BOBASCAN_API_KEY=xxx
GNOSISSCAN_API_KEY=xxx
-OPTIMISTIC_ETHERSCAN_API_KEY=xxx
+OPTIMISMSCAN_API_KEY=xxx
CREATE2_CLIENT_TOKENS=xxx
diff --git a/environments/grafana.yaml b/environments/grafana.yaml
index 565042106..400e1402e 100644
--- a/environments/grafana.yaml
+++ b/environments/grafana.yaml
@@ -92,3 +92,13 @@ services:
- "/:/host:ro,rslave"
networks:
- source-verify
+
+ nginx_exporter:
+ image: nginx/nginx-prometheus-exporter:0.10.0
+ container_name: grafana-nginx_exporter-${TAG}
+ command:
+ - -nginx.scrape-uri
+ - https://sourcify.dev/nginx_status
+ restart: unless-stopped
+ networks:
+ - source-verify
diff --git a/package-lock.json b/package-lock.json
index 7808bcb8d..32c7c2865 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5295,6 +5295,12 @@
"node": ">=8"
}
},
+ "node_modules/ansi-sequence-parser": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.0.tgz",
+ "integrity": "sha512-lEm8mt52to2fT8GhciPCGeCXACSz2UwIN4X2e2LJSnZ5uAbn2/dsYdOmUXq0AtWS5cpAupysIneExOgH0Vd2TQ==",
+ "dev": true
+ },
"node_modules/ansi-styles": {
"version": "3.2.1",
"license": "MIT",
@@ -14152,6 +14158,12 @@
"node": ">=6"
}
},
+ "node_modules/jsonc-parser": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz",
+ "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==",
+ "dev": true
+ },
"node_modules/jsonfile": {
"version": "4.0.0",
"license": "MIT",
@@ -15079,6 +15091,12 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/lunr": {
+ "version": "2.3.9",
+ "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz",
+ "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==",
+ "dev": true
+ },
"node_modules/macos-release": {
"version": "2.5.0",
"dev": true,
@@ -15169,6 +15187,18 @@
"node": ">=0.10.0"
}
},
+ "node_modules/marked": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz",
+ "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==",
+ "dev": true,
+ "bin": {
+ "marked": "bin/marked.js"
+ },
+ "engines": {
+ "node": ">= 12"
+ }
+ },
"node_modules/mcl-wasm": {
"version": "0.7.9",
"resolved": "https://registry.npmjs.org/mcl-wasm/-/mcl-wasm-0.7.9.tgz",
@@ -20377,6 +20407,18 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/shiki": {
+ "version": "0.14.2",
+ "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.2.tgz",
+ "integrity": "sha512-ltSZlSLOuSY0M0Y75KA+ieRaZ0Trf5Wl3gutE7jzLuIcWxLp5i/uEnLoQWNvgKXQ5OMpGkJnVMRLAuzjc0LJ2A==",
+ "dev": true,
+ "dependencies": {
+ "ansi-sequence-parser": "^1.1.0",
+ "jsonc-parser": "^3.2.0",
+ "vscode-oniguruma": "^1.7.0",
+ "vscode-textmate": "^8.0.0"
+ }
+ },
"node_modules/side-channel": {
"version": "1.0.4",
"license": "MIT",
@@ -22256,6 +22298,51 @@
"is-typedarray": "^1.0.0"
}
},
+ "node_modules/typedoc": {
+ "version": "0.24.6",
+ "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.24.6.tgz",
+ "integrity": "sha512-c3y3h45xJv3qYwKDAwU6Cl+26CjT0ZvblHzfHJ+SjQDM4p1mZxtgHky4lhmG0+nNarRht8kADfZlbspJWdZarQ==",
+ "dev": true,
+ "dependencies": {
+ "lunr": "^2.3.9",
+ "marked": "^4.3.0",
+ "minimatch": "^9.0.0",
+ "shiki": "^0.14.1"
+ },
+ "bin": {
+ "typedoc": "bin/typedoc"
+ },
+ "engines": {
+ "node": ">= 14.14"
+ },
+ "peerDependencies": {
+ "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x"
+ }
+ },
+ "node_modules/typedoc/node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/typedoc/node_modules/minimatch": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.0.tgz",
+ "integrity": "sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
"node_modules/typescript": {
"version": "4.9.4",
"license": "Apache-2.0",
@@ -22756,6 +22843,18 @@
"extsprintf": "^1.2.0"
}
},
+ "node_modules/vscode-oniguruma": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz",
+ "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==",
+ "dev": true
+ },
+ "node_modules/vscode-textmate": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz",
+ "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==",
+ "dev": true
+ },
"node_modules/wcwidth": {
"version": "1.0.1",
"dev": true,
@@ -29465,8 +29564,8 @@
"prettier": "^2.8.2",
"standard-version": "^9.5.0",
"ts-node": "^10.9.1",
- "typedoc": "^0.23.24",
- "typescript": "^4.9.4"
+ "typedoc": "^0.24.6",
+ "typescript": "^5.0.4"
},
"engines": {
"node": ">=10"
@@ -29612,6 +29711,20 @@
"node": ">=v14"
}
},
+ "packages/lib-sourcify/node_modules/@commitlint/load/node_modules/typescript": {
+ "version": "4.9.5",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
+ "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
+ "dev": true,
+ "optional": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=4.2.0"
+ }
+ },
"packages/lib-sourcify/node_modules/@commitlint/resolve-extends": {
"version": "17.4.0",
"dev": true,
@@ -36254,11 +36367,6 @@
"version": "5.0.1",
"license": "ISC"
},
- "packages/lib-sourcify/node_modules/jsonc-parser": {
- "version": "3.2.0",
- "dev": true,
- "license": "MIT"
- },
"packages/lib-sourcify/node_modules/jsonfile": {
"version": "6.1.0",
"dev": true,
@@ -36520,11 +36628,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "packages/lib-sourcify/node_modules/lunr": {
- "version": "2.3.9",
- "dev": true,
- "license": "MIT"
- },
"packages/lib-sourcify/node_modules/make-dir": {
"version": "3.1.0",
"dev": true,
@@ -36563,17 +36666,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "packages/lib-sourcify/node_modules/marked": {
- "version": "4.2.12",
- "dev": true,
- "license": "MIT",
- "bin": {
- "marked": "bin/marked.js"
- },
- "engines": {
- "node": ">= 12"
- }
- },
"packages/lib-sourcify/node_modules/md5.js": {
"version": "1.3.5",
"license": "MIT",
@@ -38348,16 +38440,6 @@
"node": ">=8"
}
},
- "packages/lib-sourcify/node_modules/shiki": {
- "version": "0.12.1",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "jsonc-parser": "^3.2.0",
- "vscode-oniguruma": "^1.7.0",
- "vscode-textmate": "^8.0.0"
- }
- },
"packages/lib-sourcify/node_modules/side-channel": {
"version": "1.0.4",
"license": "MIT",
@@ -39369,55 +39451,17 @@
"is-typedarray": "^1.0.0"
}
},
- "packages/lib-sourcify/node_modules/typedoc": {
- "version": "0.23.24",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "lunr": "^2.3.9",
- "marked": "^4.2.5",
- "minimatch": "^5.1.2",
- "shiki": "^0.12.1"
- },
- "bin": {
- "typedoc": "bin/typedoc"
- },
- "engines": {
- "node": ">= 14.14"
- },
- "peerDependencies": {
- "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x"
- }
- },
- "packages/lib-sourcify/node_modules/typedoc/node_modules/brace-expansion": {
- "version": "2.0.1",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "balanced-match": "^1.0.0"
- }
- },
- "packages/lib-sourcify/node_modules/typedoc/node_modules/minimatch": {
- "version": "5.1.4",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "brace-expansion": "^2.0.1"
- },
- "engines": {
- "node": ">=10"
- }
- },
"packages/lib-sourcify/node_modules/typescript": {
- "version": "4.9.4",
+ "version": "5.0.4",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz",
+ "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==",
"dev": true,
- "license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
- "node": ">=4.2.0"
+ "node": ">=12.20"
}
},
"packages/lib-sourcify/node_modules/uglify-js": {
@@ -39570,16 +39614,6 @@
"version": "1.0.2",
"license": "MIT"
},
- "packages/lib-sourcify/node_modules/vscode-oniguruma": {
- "version": "1.7.0",
- "dev": true,
- "license": "MIT"
- },
- "packages/lib-sourcify/node_modules/vscode-textmate": {
- "version": "8.0.0",
- "dev": true,
- "license": "MIT"
- },
"packages/lib-sourcify/node_modules/vscode-uri": {
"version": "3.0.7",
"dev": true,
@@ -44050,8 +44084,8 @@
"solc": "^0.8.17",
"standard-version": "^9.5.0",
"ts-node": "^10.9.1",
- "typedoc": "^0.23.24",
- "typescript": "^4.9.4",
+ "typedoc": "^0.24.6",
+ "typescript": "^5.0.4",
"web3": "^1.8.1",
"web3-utils": "^1.8.1"
},
@@ -44153,6 +44187,15 @@
"resolve-from": "^5.0.0",
"ts-node": "^10.8.1",
"typescript": "^4.6.4"
+ },
+ "dependencies": {
+ "typescript": {
+ "version": "4.9.5",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
+ "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
+ "dev": true,
+ "optional": true
+ }
}
},
"@commitlint/resolve-extends": {
@@ -51887,10 +51930,6 @@
"json-stringify-safe": {
"version": "5.0.1"
},
- "jsonc-parser": {
- "version": "3.2.0",
- "dev": true
- },
"jsonfile": {
"version": "6.1.0",
"dev": true,
@@ -52073,10 +52112,6 @@
"lowercase-keys": {
"version": "3.0.0"
},
- "lunr": {
- "version": "2.3.9",
- "dev": true
- },
"make-dir": {
"version": "3.1.0",
"dev": true,
@@ -52098,10 +52133,6 @@
"version": "4.3.0",
"dev": true
},
- "marked": {
- "version": "4.2.12",
- "dev": true
- },
"md5.js": {
"version": "1.3.5",
"requires": {
@@ -53205,15 +53236,6 @@
"version": "3.0.0",
"dev": true
},
- "shiki": {
- "version": "0.12.1",
- "dev": true,
- "requires": {
- "jsonc-parser": "^3.2.0",
- "vscode-oniguruma": "^1.7.0",
- "vscode-textmate": "^8.0.0"
- }
- },
"side-channel": {
"version": "1.0.4",
"requires": {
@@ -53841,34 +53863,10 @@
"is-typedarray": "^1.0.0"
}
},
- "typedoc": {
- "version": "0.23.24",
- "dev": true,
- "requires": {
- "lunr": "^2.3.9",
- "marked": "^4.2.5",
- "minimatch": "^5.1.2",
- "shiki": "^0.12.1"
- },
- "dependencies": {
- "brace-expansion": {
- "version": "2.0.1",
- "dev": true,
- "requires": {
- "balanced-match": "^1.0.0"
- }
- },
- "minimatch": {
- "version": "5.1.4",
- "dev": true,
- "requires": {
- "brace-expansion": "^2.0.1"
- }
- }
- }
- },
"typescript": {
- "version": "4.9.4",
+ "version": "5.0.4",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz",
+ "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==",
"dev": true
},
"uglify-js": {
@@ -53972,14 +53970,6 @@
}
}
},
- "vscode-oniguruma": {
- "version": "1.7.0",
- "dev": true
- },
- "vscode-textmate": {
- "version": "8.0.0",
- "dev": true
- },
"vscode-uri": {
"version": "3.0.7",
"dev": true
@@ -57938,6 +57928,12 @@
"version": "5.0.1",
"dev": true
},
+ "ansi-sequence-parser": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.0.tgz",
+ "integrity": "sha512-lEm8mt52to2fT8GhciPCGeCXACSz2UwIN4X2e2LJSnZ5uAbn2/dsYdOmUXq0AtWS5cpAupysIneExOgH0Vd2TQ==",
+ "dev": true
+ },
"ansi-styles": {
"version": "3.2.1",
"requires": {
@@ -64125,6 +64121,12 @@
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true
},
+ "jsonc-parser": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz",
+ "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==",
+ "dev": true
+ },
"jsonfile": {
"version": "4.0.0",
"requires": {
@@ -64841,6 +64843,12 @@
"version": "2.2.1",
"dev": true
},
+ "lunr": {
+ "version": "2.3.9",
+ "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz",
+ "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==",
+ "dev": true
+ },
"macos-release": {
"version": "2.5.0",
"dev": true
@@ -64900,6 +64908,12 @@
"object-visit": "^1.0.0"
}
},
+ "marked": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz",
+ "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==",
+ "dev": true
+ },
"mcl-wasm": {
"version": "0.7.9",
"resolved": "https://registry.npmjs.org/mcl-wasm/-/mcl-wasm-0.7.9.tgz",
@@ -68430,6 +68444,18 @@
"integrity": "sha512-QHsz8GgQIGKlRi24yFc6a6lN69Idnx634w49ay6+jA5yFh7a1UY+4Rp6HPx/L/1zcEDPEij8cIsiqR6bQsE5VQ==",
"dev": true
},
+ "shiki": {
+ "version": "0.14.2",
+ "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.2.tgz",
+ "integrity": "sha512-ltSZlSLOuSY0M0Y75KA+ieRaZ0Trf5Wl3gutE7jzLuIcWxLp5i/uEnLoQWNvgKXQ5OMpGkJnVMRLAuzjc0LJ2A==",
+ "dev": true,
+ "requires": {
+ "ansi-sequence-parser": "^1.1.0",
+ "jsonc-parser": "^3.2.0",
+ "vscode-oniguruma": "^1.7.0",
+ "vscode-textmate": "^8.0.0"
+ }
+ },
"side-channel": {
"version": "1.0.4",
"requires": {
@@ -69723,6 +69749,38 @@
"is-typedarray": "^1.0.0"
}
},
+ "typedoc": {
+ "version": "0.24.6",
+ "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.24.6.tgz",
+ "integrity": "sha512-c3y3h45xJv3qYwKDAwU6Cl+26CjT0ZvblHzfHJ+SjQDM4p1mZxtgHky4lhmG0+nNarRht8kADfZlbspJWdZarQ==",
+ "dev": true,
+ "requires": {
+ "lunr": "^2.3.9",
+ "marked": "^4.3.0",
+ "minimatch": "^9.0.0",
+ "shiki": "^0.14.1"
+ },
+ "dependencies": {
+ "brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dev": true,
+ "requires": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "minimatch": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.0.tgz",
+ "integrity": "sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==",
+ "dev": true,
+ "requires": {
+ "brace-expansion": "^2.0.1"
+ }
+ }
+ }
+ },
"typescript": {
"version": "4.9.4"
},
@@ -70048,6 +70106,18 @@
"extsprintf": "^1.2.0"
}
},
+ "vscode-oniguruma": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz",
+ "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==",
+ "dev": true
+ },
+ "vscode-textmate": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz",
+ "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==",
+ "dev": true
+ },
"wcwidth": {
"version": "1.0.1",
"dev": true,
diff --git a/package.json b/package.json
index 9de768026..8b44745b6 100644
--- a/package.json
+++ b/package.json
@@ -51,7 +51,7 @@
"@ethereum-sourcify/bytecode-utils": "*",
"@ethereum-sourcify/lib-sourcify": "*",
"@types/node-fetch": "^2.5.7",
- "abitype": "^0.8.0",
+ "abitype": "0.8.0",
"bunyan": "^1.8.12",
"commander": "^9.0.0",
"cors": "^2.8.5",
diff --git a/packages/lib-sourcify/package-lock.json b/packages/lib-sourcify/package-lock.json
index a74aed0fb..899cd82a2 100644
--- a/packages/lib-sourcify/package-lock.json
+++ b/packages/lib-sourcify/package-lock.json
@@ -16,6 +16,7 @@
"@ethereumjs/statemanager": "^1.0.4",
"@ethereumjs/util": "^8.0.5",
"@ethereumjs/vm": "^6.4.1",
+ "@ethersproject/abi": "^5.7.0",
"@ethersproject/address": "^5.7.0",
"@ethersproject/bignumber": "^5.7.0",
"@ethersproject/bytes": "^5.7.0",
@@ -55,8 +56,8 @@
"prettier": "^2.8.2",
"standard-version": "^9.5.0",
"ts-node": "^10.9.1",
- "typedoc": "^0.23.24",
- "typescript": "^4.9.4"
+ "typedoc": "^0.24.6",
+ "typescript": "^5.0.4"
},
"engines": {
"node": ">=10"
@@ -611,6 +612,20 @@
"typescript": ">=3"
}
},
+ "node_modules/@commitlint/load/node_modules/typescript": {
+ "version": "4.9.5",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
+ "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
+ "dev": true,
+ "optional": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=4.2.0"
+ }
+ },
"node_modules/@commitlint/resolve-extends": {
"version": "17.4.0",
"resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-17.4.0.tgz",
@@ -2567,6 +2582,12 @@
"node": ">=8"
}
},
+ "node_modules/ansi-sequence-parser": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.0.tgz",
+ "integrity": "sha512-lEm8mt52to2fT8GhciPCGeCXACSz2UwIN4X2e2LJSnZ5uAbn2/dsYdOmUXq0AtWS5cpAupysIneExOgH0Vd2TQ==",
+ "dev": true
+ },
"node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
@@ -9666,9 +9687,9 @@
}
},
"node_modules/marked": {
- "version": "4.2.5",
- "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.5.tgz",
- "integrity": "sha512-jPueVhumq7idETHkb203WDD4fMA3yV9emQ5vLwop58lu8bTclMghBWcYAavlDqIEMaisADinV1TooIFCfqOsYQ==",
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz",
+ "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==",
"dev": true,
"bin": {
"marked": "bin/marked.js"
@@ -12222,11 +12243,12 @@
}
},
"node_modules/shiki": {
- "version": "0.12.1",
- "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.12.1.tgz",
- "integrity": "sha512-aieaV1m349rZINEBkjxh2QbBvFFQOlgqYTNtCal82hHj4dDZ76oMlQIX+C7ryerBTDiga3e5NfH6smjdJ02BbQ==",
+ "version": "0.14.2",
+ "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.2.tgz",
+ "integrity": "sha512-ltSZlSLOuSY0M0Y75KA+ieRaZ0Trf5Wl3gutE7jzLuIcWxLp5i/uEnLoQWNvgKXQ5OMpGkJnVMRLAuzjc0LJ2A==",
"dev": true,
"dependencies": {
+ "ansi-sequence-parser": "^1.1.0",
"jsonc-parser": "^3.2.0",
"vscode-oniguruma": "^1.7.0",
"vscode-textmate": "^8.0.0"
@@ -13448,15 +13470,15 @@
}
},
"node_modules/typedoc": {
- "version": "0.23.24",
- "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.23.24.tgz",
- "integrity": "sha512-bfmy8lNQh+WrPYcJbtjQ6JEEsVl/ce1ZIXyXhyW+a1vFrjO39t6J8sL/d6FfAGrJTc7McCXgk9AanYBSNvLdIA==",
+ "version": "0.24.6",
+ "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.24.6.tgz",
+ "integrity": "sha512-c3y3h45xJv3qYwKDAwU6Cl+26CjT0ZvblHzfHJ+SjQDM4p1mZxtgHky4lhmG0+nNarRht8kADfZlbspJWdZarQ==",
"dev": true,
"dependencies": {
"lunr": "^2.3.9",
- "marked": "^4.2.5",
- "minimatch": "^5.1.2",
- "shiki": "^0.12.1"
+ "marked": "^4.3.0",
+ "minimatch": "^9.0.0",
+ "shiki": "^0.14.1"
},
"bin": {
"typedoc": "bin/typedoc"
@@ -13465,7 +13487,7 @@
"node": ">= 14.14"
},
"peerDependencies": {
- "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x"
+ "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x"
}
},
"node_modules/typedoc/node_modules/brace-expansion": {
@@ -13478,27 +13500,30 @@
}
},
"node_modules/typedoc/node_modules/minimatch": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz",
- "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==",
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.0.tgz",
+ "integrity": "sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==",
"dev": true,
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
- "node": ">=10"
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/typescript": {
- "version": "4.9.4",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz",
- "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==",
+ "version": "5.0.4",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz",
+ "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
- "node": ">=4.2.0"
+ "node": ">=12.20"
}
},
"node_modules/uglify-js": {
@@ -14891,6 +14916,13 @@
"dev": true,
"optional": true,
"requires": {}
+ },
+ "typescript": {
+ "version": "4.9.5",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
+ "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
+ "dev": true,
+ "optional": true
}
}
},
@@ -16278,6 +16310,12 @@
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true
},
+ "ansi-sequence-parser": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.0.tgz",
+ "integrity": "sha512-lEm8mt52to2fT8GhciPCGeCXACSz2UwIN4X2e2LJSnZ5uAbn2/dsYdOmUXq0AtWS5cpAupysIneExOgH0Vd2TQ==",
+ "dev": true
+ },
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
@@ -21705,9 +21743,9 @@
"dev": true
},
"marked": {
- "version": "4.2.5",
- "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.5.tgz",
- "integrity": "sha512-jPueVhumq7idETHkb203WDD4fMA3yV9emQ5vLwop58lu8bTclMghBWcYAavlDqIEMaisADinV1TooIFCfqOsYQ==",
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz",
+ "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==",
"dev": true
},
"mcl-wasm": {
@@ -23619,11 +23657,12 @@
"dev": true
},
"shiki": {
- "version": "0.12.1",
- "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.12.1.tgz",
- "integrity": "sha512-aieaV1m349rZINEBkjxh2QbBvFFQOlgqYTNtCal82hHj4dDZ76oMlQIX+C7ryerBTDiga3e5NfH6smjdJ02BbQ==",
+ "version": "0.14.2",
+ "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.2.tgz",
+ "integrity": "sha512-ltSZlSLOuSY0M0Y75KA+ieRaZ0Trf5Wl3gutE7jzLuIcWxLp5i/uEnLoQWNvgKXQ5OMpGkJnVMRLAuzjc0LJ2A==",
"dev": true,
"requires": {
+ "ansi-sequence-parser": "^1.1.0",
"jsonc-parser": "^3.2.0",
"vscode-oniguruma": "^1.7.0",
"vscode-textmate": "^8.0.0"
@@ -24531,15 +24570,15 @@
}
},
"typedoc": {
- "version": "0.23.24",
- "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.23.24.tgz",
- "integrity": "sha512-bfmy8lNQh+WrPYcJbtjQ6JEEsVl/ce1ZIXyXhyW+a1vFrjO39t6J8sL/d6FfAGrJTc7McCXgk9AanYBSNvLdIA==",
+ "version": "0.24.6",
+ "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.24.6.tgz",
+ "integrity": "sha512-c3y3h45xJv3qYwKDAwU6Cl+26CjT0ZvblHzfHJ+SjQDM4p1mZxtgHky4lhmG0+nNarRht8kADfZlbspJWdZarQ==",
"dev": true,
"requires": {
"lunr": "^2.3.9",
- "marked": "^4.2.5",
- "minimatch": "^5.1.2",
- "shiki": "^0.12.1"
+ "marked": "^4.3.0",
+ "minimatch": "^9.0.0",
+ "shiki": "^0.14.1"
},
"dependencies": {
"brace-expansion": {
@@ -24552,9 +24591,9 @@
}
},
"minimatch": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz",
- "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==",
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.0.tgz",
+ "integrity": "sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==",
"dev": true,
"requires": {
"brace-expansion": "^2.0.1"
@@ -24563,9 +24602,9 @@
}
},
"typescript": {
- "version": "4.9.4",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz",
- "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg=="
+ "version": "5.0.4",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz",
+ "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw=="
},
"uglify-js": {
"version": "3.17.4",
diff --git a/packages/lib-sourcify/package.json b/packages/lib-sourcify/package.json
index 942c8bb12..313afc332 100644
--- a/packages/lib-sourcify/package.json
+++ b/packages/lib-sourcify/package.json
@@ -49,6 +49,7 @@
"@ethereumjs/statemanager": "^1.0.4",
"@ethereumjs/util": "^8.0.5",
"@ethereumjs/vm": "^6.4.1",
+ "@ethersproject/abi": "^5.7.0",
"@ethersproject/address": "^5.7.0",
"@ethersproject/bignumber": "^5.7.0",
"@ethersproject/bytes": "^5.7.0",
@@ -88,8 +89,8 @@
"prettier": "^2.8.2",
"standard-version": "^9.5.0",
"ts-node": "^10.9.1",
- "typedoc": "^0.23.24",
- "typescript": "^4.9.4"
+ "typedoc": "^0.24.6",
+ "typescript": "^5.0.4"
},
"files": [
"build/main",
diff --git a/packages/lib-sourcify/src/lib/verification.ts b/packages/lib-sourcify/src/lib/verification.ts
index 8ff15b931..e012fd5d8 100644
--- a/packages/lib-sourcify/src/lib/verification.ts
+++ b/packages/lib-sourcify/src/lib/verification.ts
@@ -4,6 +4,7 @@ import {
Create2Args,
ImmutableReferences,
Match,
+ Metadata,
RecompilationResult,
SourcifyChain,
StringMap,
@@ -27,6 +28,8 @@ import { hexZeroPad, isHexString } from '@ethersproject/bytes';
import { BigNumber } from '@ethersproject/bignumber';
import { getAddress, getContractAddress } from '@ethersproject/address';
import semverSatisfies from 'semver/functions/satisfies';
+import { defaultAbiCoder as abiCoder, ParamType } from '@ethersproject/abi';
+import { AbiConstructor } from 'abitype';
const RPC_TIMEOUT = 5000;
@@ -44,6 +47,15 @@ export async function verifyDeployed(
};
const recompiled = await checkedContract.recompile();
+ if (
+ recompiled.deployedBytecode === '0x' ||
+ recompiled.creationBytecode === '0x'
+ ) {
+ throw new Error(
+ `The compiled contract bytecode is "0x". Are you trying to verify an abstract contract?`
+ );
+ }
+
const deployedBytecode = await getBytecode(sourcifyChain, address);
// Can't match if there is no deployed bytecode
@@ -114,12 +126,14 @@ export async function verifyDeployed(
// Try to match with creationTx, if available
if (creatorTxHash) {
+ const recompiledMetadata: Metadata = JSON.parse(recompiled.metadata);
await matchWithCreationTx(
match,
recompiled.creationBytecode,
sourcifyChain,
address,
- creatorTxHash
+ creatorTxHash,
+ recompiledMetadata
);
if (isPerfectMatch(match)) {
return match;
@@ -134,7 +148,8 @@ export async function verifyDeployed(
recompiled.creationBytecode,
sourcifyChain,
address,
- creatorTxHash
+ creatorTxHash,
+ recompiledMetadata
);
}
);
@@ -237,6 +252,13 @@ export function matchWithDeployedBytecode(
deployedBytecode: string,
immutableReferences?: any
) {
+ // Check if is a library with call protection
+ // See https://docs.soliditylang.org/en/v0.8.19/contracts.html#call-protection-for-libraries
+ recompiledDeployedBytecode = checkCallProtectionAndReplaceAddress(
+ recompiledDeployedBytecode,
+ deployedBytecode
+ );
+
// Replace the library placeholders in the recompiled bytecode with values from the deployed bytecode
const { replaced, libraryMap } = addLibraryAddresses(
recompiledDeployedBytecode,
@@ -348,8 +370,15 @@ export async function matchWithCreationTx(
recompiledCreationBytecode: string,
sourcifyChain: SourcifyChain,
address: string,
- creatorTxHash: string
+ creatorTxHash: string,
+ recompiledMetadata: Metadata
) {
+ if (recompiledCreationBytecode === '0x') {
+ match.status = null;
+ match.message = `Failed to match with creation bytecode: recompiled contract's creation bytecode is empty`;
+ return;
+ }
+
const creatorTx = await getTx(creatorTxHash, sourcifyChain);
const creatorTxData = creatorTx.input;
@@ -380,6 +409,40 @@ export async function matchWithCreationTx(
}
if (match.status) {
+ const abiEncodedConstructorArguments =
+ extractAbiEncodedConstructorArguments(
+ creatorTxData,
+ recompiledCreationBytecode
+ );
+ const constructorAbiParamInputs = (
+ recompiledMetadata?.output?.abi?.find(
+ (param) => param.type === 'constructor'
+ ) as AbiConstructor
+ )?.inputs as ParamType[];
+ if (abiEncodedConstructorArguments) {
+ if (!constructorAbiParamInputs) {
+ match.status = null;
+ match.message = `Failed to match with creation bytecode: constructor ABI Inputs are missing`;
+ return;
+ }
+ // abiCoder doesn't break if called with a wrong `abiEncodedConstructorArguments`
+ // so in order to successfuly check if the constructor arguments actually match
+ // we need to re-encode it and compare them
+ const decodeResult = abiCoder.decode(
+ constructorAbiParamInputs,
+ abiEncodedConstructorArguments
+ );
+ const encodeResult = abiCoder.encode(
+ constructorAbiParamInputs,
+ decodeResult
+ );
+ if (encodeResult !== abiEncodedConstructorArguments) {
+ match.status = null;
+ match.message = `Failed to match with creation bytecode: constructor arguments ABI decoding failed ${encodeResult} vs ${abiEncodedConstructorArguments}`;
+ return;
+ }
+ }
+
// we need to check if this contract creation tx actually yields the same contract address https://github.com/ethereum/sourcify/issues/887
const createdContractAddress = getContractAddress({
from: creatorTx.from,
@@ -391,11 +454,7 @@ export async function matchWithCreationTx(
return;
}
match.libraryMap = libraryMap;
- const abiEncodedConstructorArguments =
- extractAbiEncodedConstructorArguments(
- creatorTxData,
- recompiledCreationBytecode
- );
+
match.abiEncodedConstructorArguments = abiEncodedConstructorArguments;
match.creatorTxHash = creatorTxHash;
}
@@ -506,6 +565,20 @@ export function addLibraryAddresses(
};
}
+export function checkCallProtectionAndReplaceAddress(
+ template: string,
+ real: string
+): string {
+ const push20CodeOp = '73';
+ const callProtection = `0x${push20CodeOp}${'00'.repeat(20)}`;
+
+ if (template.startsWith(callProtection)) {
+ const replacedCallProtection = real.slice(0, 0 + callProtection.length);
+ return replacedCallProtection + template.substring(callProtection.length);
+ }
+ return template;
+}
+
/**
* Replaces the values of the immutable variables in the (onchain) deployed bytecode with zeros, so that the bytecode can be compared with the (offchain) recompiled bytecode.
* Example immutableReferences: {"97":[{"length":32,"start":137}],"99":[{"length":32,"start":421}]} where 97 and 99 are the AST ids
diff --git a/packages/lib-sourcify/test/sources/AbstractCreationBytecodeAttack/metadata.json b/packages/lib-sourcify/test/sources/AbstractCreationBytecodeAttack/metadata.json
new file mode 100644
index 000000000..d434360de
--- /dev/null
+++ b/packages/lib-sourcify/test/sources/AbstractCreationBytecodeAttack/metadata.json
@@ -0,0 +1,44 @@
+{
+ "compiler": {
+ "version": "0.6.12+commit.27d51765"
+ },
+ "language": "Solidity",
+ "output": {
+ "abi": [],
+ "devdoc": {
+ "kind": "dev",
+ "methods": {},
+ "version": 1
+ },
+ "userdoc": {
+ "kind": "user",
+ "methods": {},
+ "version": 1
+ }
+ },
+ "settings": {
+ "compilationTarget": {
+ "sources/FFF.sol": "FFF"
+ },
+ "evmVersion": "istanbul",
+ "libraries": {},
+ "metadata": {
+ "bytecodeHash": "ipfs"
+ },
+ "optimizer": {
+ "enabled": false,
+ "runs": 200
+ },
+ "remappings": []
+ },
+ "sources": {
+ "sources/FFF.sol": {
+ "keccak256": "0x7ed3554b3f768ad3b3069d7fc8b1a08a24500507fc8a60eb11c726e37f3cd9a3",
+ "urls": [
+ "bzz-raw://6d83c127e075a149ec14c6af579bc7b24955cdb7578ae7da2f253b7142d267cc",
+ "dweb:/ipfs/QmW6tdCTV7X5dd5LCKDWedbMmkurQTMi4ePx7LY3DNuLn7"
+ ]
+ }
+ },
+ "version": 1
+}
diff --git a/packages/lib-sourcify/test/sources/AbstractCreationBytecodeAttack/sources/FFF.sol b/packages/lib-sourcify/test/sources/AbstractCreationBytecodeAttack/sources/FFF.sol
new file mode 100644
index 000000000..b12b1d274
--- /dev/null
+++ b/packages/lib-sourcify/test/sources/AbstractCreationBytecodeAttack/sources/FFF.sol
@@ -0,0 +1,6 @@
+pragma solidity 0.6.12;
+
+abstract contract FFF{
+ constructor (uint256 a) public payable {
+ }
+}
\ No newline at end of file
diff --git a/packages/lib-sourcify/test/sources/CallProtectionForLibraries/artifact.json b/packages/lib-sourcify/test/sources/CallProtectionForLibraries/artifact.json
new file mode 100644
index 000000000..a14553168
--- /dev/null
+++ b/packages/lib-sourcify/test/sources/CallProtectionForLibraries/artifact.json
@@ -0,0 +1,4 @@
+{
+ "abi": [],
+ "bytecode": "0x60bd610039600b82828239805160001a60731461002c57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe730000000000000000000000000000000000000000301460806040526004361060335760003560e01c8063fe073d11146038575b600080fd5b818015604357600080fd5b50604a604c565b005b60006057600182605b565b5050565b60ff8181168382160190811115608157634e487b7160e01b600052601160045260246000fd5b9291505056fea264697066735822122026efb28b74c882aa2f1f86cbe51d40fba727849fa6113630f5c12c98c1a9eb9b64736f6c63430008130033"
+}
diff --git a/packages/lib-sourcify/test/sources/CallProtectionForLibraries/metadata.json b/packages/lib-sourcify/test/sources/CallProtectionForLibraries/metadata.json
new file mode 100644
index 000000000..2fb60e9be
--- /dev/null
+++ b/packages/lib-sourcify/test/sources/CallProtectionForLibraries/metadata.json
@@ -0,0 +1,27 @@
+{
+ "compiler": { "version": "0.8.19+commit.7dd6d404" },
+ "language": "Solidity",
+ "output": {
+ "abi": [],
+ "devdoc": { "kind": "dev", "methods": {}, "version": 1 },
+ "userdoc": { "kind": "user", "methods": {}, "version": 1 }
+ },
+ "settings": {
+ "compilationTarget": { "Ballot.sol": "Ballot" },
+ "evmVersion": "paris",
+ "libraries": {},
+ "metadata": { "bytecodeHash": "ipfs" },
+ "optimizer": { "enabled": true, "runs": 200 },
+ "remappings": []
+ },
+ "sources": {
+ "Ballot.sol": {
+ "keccak256": "0x21d251aa06c7fcbb362bca4b1645ef4fbc3d0844f6774f4598588f9045fdfe97",
+ "urls": [
+ "bzz-raw://7464b55b34107bd79040fa11eed489e2d20bde5e15b801e2ba144d7bd10bbeca",
+ "dweb:/ipfs/Qmbrd7Up3r6Q5JA9NMvZZawsJ5EuuoFfRuMBEjAYk7oDod"
+ ]
+ }
+ },
+ "version": 1
+}
diff --git a/packages/lib-sourcify/test/sources/CallProtectionForLibraries/sources/Ballot.sol b/packages/lib-sourcify/test/sources/CallProtectionForLibraries/sources/Ballot.sol
new file mode 100644
index 000000000..8714a01b0
--- /dev/null
+++ b/packages/lib-sourcify/test/sources/CallProtectionForLibraries/sources/Ballot.sol
@@ -0,0 +1,7 @@
+pragma solidity 0.8.19;
+library Ballot {
+ function giveRightToVote() public {
+ uint8 tempnumber = 0;
+ tempnumber += 1;
+ }
+}
\ No newline at end of file
diff --git a/packages/lib-sourcify/test/sources/CallProtectionForLibrariesViaIR/artifact.json b/packages/lib-sourcify/test/sources/CallProtectionForLibrariesViaIR/artifact.json
new file mode 100644
index 000000000..f7c1d4fb5
--- /dev/null
+++ b/packages/lib-sourcify/test/sources/CallProtectionForLibrariesViaIR/artifact.json
@@ -0,0 +1,4 @@
+{
+ "abi": [],
+ "bytecode": "0x60808060405234601a57608d90816100208239308160240152f35b600080fdfe6004361015600c57600080fd5b6000803560e01c63fe073d1114602157600080fd5b307f0000000000000000000000000000000000000000000000000000000000000000146054578060031936011260545780f35b80fdfea26469706673582212201104b959cf92e8eead2cb6513fe1d88ee97c7b264a0dea0bd7ccaffd488db72764736f6c63430008130033"
+}
diff --git a/packages/lib-sourcify/test/sources/CallProtectionForLibrariesViaIR/metadata.json b/packages/lib-sourcify/test/sources/CallProtectionForLibrariesViaIR/metadata.json
new file mode 100644
index 000000000..14d67f26e
--- /dev/null
+++ b/packages/lib-sourcify/test/sources/CallProtectionForLibrariesViaIR/metadata.json
@@ -0,0 +1,28 @@
+{
+ "compiler": { "version": "0.8.19+commit.7dd6d404" },
+ "language": "Solidity",
+ "output": {
+ "abi": [],
+ "devdoc": { "kind": "dev", "methods": {}, "version": 1 },
+ "userdoc": { "kind": "user", "methods": {}, "version": 1 }
+ },
+ "settings": {
+ "compilationTarget": { "Ballot.sol": "Ballot" },
+ "evmVersion": "paris",
+ "libraries": {},
+ "metadata": { "bytecodeHash": "ipfs" },
+ "optimizer": { "enabled": true, "runs": 200 },
+ "remappings": [],
+ "viaIR": true
+ },
+ "sources": {
+ "Ballot.sol": {
+ "keccak256": "0x21d251aa06c7fcbb362bca4b1645ef4fbc3d0844f6774f4598588f9045fdfe97",
+ "urls": [
+ "bzz-raw://7464b55b34107bd79040fa11eed489e2d20bde5e15b801e2ba144d7bd10bbeca",
+ "dweb:/ipfs/Qmbrd7Up3r6Q5JA9NMvZZawsJ5EuuoFfRuMBEjAYk7oDod"
+ ]
+ }
+ },
+ "version": 1
+}
diff --git a/packages/lib-sourcify/test/sources/CallProtectionForLibrariesViaIR/sources/Ballot.sol b/packages/lib-sourcify/test/sources/CallProtectionForLibrariesViaIR/sources/Ballot.sol
new file mode 100644
index 000000000..8714a01b0
--- /dev/null
+++ b/packages/lib-sourcify/test/sources/CallProtectionForLibrariesViaIR/sources/Ballot.sol
@@ -0,0 +1,7 @@
+pragma solidity 0.8.19;
+library Ballot {
+ function giveRightToVote() public {
+ uint8 tempnumber = 0;
+ tempnumber += 1;
+ }
+}
\ No newline at end of file
diff --git a/packages/lib-sourcify/test/sources/WithImmutablesCreationBytecodeAttack/artifact.json b/packages/lib-sourcify/test/sources/WithImmutablesCreationBytecodeAttack/artifact.json
new file mode 100644
index 000000000..56fc11e2e
--- /dev/null
+++ b/packages/lib-sourcify/test/sources/WithImmutablesCreationBytecodeAttack/artifact.json
@@ -0,0 +1,4 @@
+{
+ "bytecode": "60a060405234801561001057600080fd5b506040516103ca0000000000000000000000000000000000000000000000000000000000000001",
+ "abi": []
+}
diff --git a/packages/lib-sourcify/test/sources/WithImmutablesCreationBytecodeAttack/metadata.json b/packages/lib-sourcify/test/sources/WithImmutablesCreationBytecodeAttack/metadata.json
new file mode 100644
index 000000000..06a0ba48c
--- /dev/null
+++ b/packages/lib-sourcify/test/sources/WithImmutablesCreationBytecodeAttack/metadata.json
@@ -0,0 +1,44 @@
+{
+ "compiler": {
+ "version": "0.8.19+commit.7dd6d404"
+ },
+ "language": "Solidity",
+ "output": {
+ "abi": [],
+ "devdoc": {
+ "kind": "dev",
+ "methods": {},
+ "version": 1
+ },
+ "userdoc": {
+ "kind": "user",
+ "methods": {},
+ "version": 1
+ }
+ },
+ "settings": {
+ "compilationTarget": {
+ "sources/WithImmutables.sol": "WithImmutables"
+ },
+ "evmVersion": "paris",
+ "libraries": {},
+ "metadata": {
+ "bytecodeHash": "ipfs"
+ },
+ "optimizer": {
+ "enabled": false,
+ "runs": 200
+ },
+ "remappings": []
+ },
+ "sources": {
+ "sources/WithImmutables.sol": {
+ "keccak256": "0xa67bac14ebd5956d06bd0f33e2ffd55db729d4ec85bca19ec5b321e6be0b7cc8",
+ "urls": [
+ "bzz-raw://6d83c127e075a149ec14c6af579bc7b24955cdb7578ae7da2f253b7142d267cc",
+ "dweb:/ipfs/QmW6tdCTV7X5dd5LCKDWedbMmkurQTMi4ePx7LY3DNuLn7"
+ ]
+ }
+ },
+ "version": 1
+}
diff --git a/packages/lib-sourcify/test/sources/WithImmutablesCreationBytecodeAttack/sources/WithImmutables.sol b/packages/lib-sourcify/test/sources/WithImmutablesCreationBytecodeAttack/sources/WithImmutables.sol
new file mode 100644
index 000000000..4f90eb28e
--- /dev/null
+++ b/packages/lib-sourcify/test/sources/WithImmutablesCreationBytecodeAttack/sources/WithImmutables.sol
@@ -0,0 +1,6 @@
+pragma solidity >=0.7.0;
+
+contract WithImmutables{
+ constructor (uint256 a) {
+ }
+}
\ No newline at end of file
diff --git a/packages/lib-sourcify/test/verification.spec.ts b/packages/lib-sourcify/test/verification.spec.ts
index 8a3675638..821bed1bf 100644
--- a/packages/lib-sourcify/test/verification.spec.ts
+++ b/packages/lib-sourcify/test/verification.spec.ts
@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-var-requires */
import path from 'path';
-import { SourcifyChain } from '../src/lib/types';
+import { Metadata, SourcifyChain } from '../src/lib/types';
import Web3 from 'web3';
import Ganache from 'ganache';
import {
@@ -398,6 +398,46 @@ describe('lib-sourcify tests', () => {
);
expectMatch(match, 'perfect', deployedAddress);
});
+
+ it('should fully verify a library with call protection when viaIR is disabled (legacy compilation placeholder: 0x73 plus 20 zero bytes)', async () => {
+ const contractFolderPath = path.join(
+ __dirname,
+ 'sources',
+ 'CallProtectionForLibraries'
+ );
+ const [deployedAddress] = await deployFromAbiAndBytecode(
+ localWeb3Provider,
+ contractFolderPath,
+ accounts[0]
+ );
+
+ const match = await checkAndVerifyDeployed(
+ contractFolderPath,
+ sourcifyChainGanache,
+ deployedAddress
+ );
+ expectMatch(match, 'perfect', deployedAddress);
+ });
+
+ it('should fully verify a library with call protection when viaIR is enabled', async () => {
+ const contractFolderPath = path.join(
+ __dirname,
+ 'sources',
+ 'CallProtectionForLibrariesViaIR'
+ );
+ const [deployedAddress] = await deployFromAbiAndBytecode(
+ localWeb3Provider,
+ contractFolderPath,
+ accounts[0]
+ );
+
+ const match = await checkAndVerifyDeployed(
+ contractFolderPath,
+ sourcifyChainGanache,
+ deployedAddress
+ );
+ expectMatch(match, 'perfect', deployedAddress);
+ });
});
describe('Unit tests', function () {
@@ -524,14 +564,138 @@ describe('lib-sourcify tests', () => {
chainId: sourcifyChainGanache.chainId.toString(),
status: null,
};
+ const recompiledMetadata: Metadata = JSON.parse(recompiled.metadata);
+ await matchWithCreationTx(
+ match,
+ recompiled.creationBytecode,
+ sourcifyChainGanache,
+ deployedAddress,
+ wrongCreatorTxHash,
+ recompiledMetadata
+ );
+ expectMatch(match, null, deployedAddress, undefined); // status is null
+ });
+
+ it('should fail to matchWithCreationTx with creatorTxHash having wrong constructor arguments', async () => {
+ const contractFolderPath = path.join(
+ __dirname,
+ 'sources',
+ 'WithImmutables'
+ );
+ const maliciousContractFolderPath = path.join(
+ __dirname,
+ 'sources',
+ 'WithImmutablesCreationBytecodeAttack'
+ );
+
+ const [deployedAddress, wrongCreatorTxHash] =
+ await deployFromAbiAndBytecode(
+ localWeb3Provider,
+ contractFolderPath,
+ accounts[0],
+ ['12345']
+ );
+ const [,] = await deployFromAbiAndBytecode(
+ localWeb3Provider,
+ maliciousContractFolderPath,
+ accounts[0],
+ ['12345']
+ );
+
+ const checkedContracts = await checkFilesFromContractFolder(
+ maliciousContractFolderPath
+ );
+ const recompiled = await checkedContracts[0].recompile();
+ const match = {
+ address: deployedAddress,
+ chainId: sourcifyChainGanache.chainId.toString(),
+ status: null,
+ };
+ const recompiledMetadata: Metadata = JSON.parse(recompiled.metadata);
+ await matchWithCreationTx(
+ match,
+ '0x60a060405234801561001057600080fd5b506040516103ca', // I force recompiled.creationBytecode because it would take time to generate the right attack,
+ sourcifyChainGanache,
+ deployedAddress,
+ wrongCreatorTxHash,
+ recompiledMetadata
+ );
+ expectMatch(match, null, deployedAddress, undefined); // status is null
+ });
+
+ it('should fail to matchWithCreationTx when passing an abstract contract', async () => {
+ const contractFolderPath = path.join(
+ __dirname,
+ 'sources',
+ 'WithImmutables'
+ );
+
+ const [deployedAddress, creatorTxHash] = await deployFromAbiAndBytecode(
+ localWeb3Provider,
+ contractFolderPath,
+ accounts[0],
+ ['12345']
+ );
+
+ const maliciousContractFolderPath = path.join(
+ __dirname,
+ 'sources',
+ 'AbstractCreationBytecodeAttack'
+ );
+ const checkedContracts = await checkFilesFromContractFolder(
+ maliciousContractFolderPath
+ );
+ const recompiled = await checkedContracts[0].recompile();
+ const match = {
+ address: deployedAddress,
+ chainId: sourcifyChainGanache.chainId.toString(),
+ status: null,
+ };
+ const recompiledMetadata: Metadata = JSON.parse(recompiled.metadata);
+
await matchWithCreationTx(
match,
recompiled.creationBytecode,
sourcifyChainGanache,
deployedAddress,
- wrongCreatorTxHash
+ creatorTxHash,
+ recompiledMetadata
);
expectMatch(match, null, deployedAddress, undefined); // status is null
});
+
+ it('should successfuly verify with matchWithCreationTx with creationTxHash', async () => {
+ const contractFolderPath = path.join(
+ __dirname,
+ 'sources',
+ 'WithImmutables'
+ );
+ const [deployedAddress, creatorTxHash] = await deployFromAbiAndBytecode(
+ localWeb3Provider,
+ contractFolderPath,
+ accounts[0],
+ ['12345']
+ );
+
+ const checkedContracts = await checkFilesFromContractFolder(
+ contractFolderPath
+ );
+ const recompiled = await checkedContracts[0].recompile();
+ const match = {
+ address: deployedAddress,
+ chainId: sourcifyChainGanache.chainId.toString(),
+ status: null,
+ };
+ const recompiledMetadata: Metadata = JSON.parse(recompiled.metadata);
+ await matchWithCreationTx(
+ match,
+ recompiled.creationBytecode,
+ sourcifyChainGanache,
+ deployedAddress,
+ creatorTxHash,
+ recompiledMetadata
+ );
+ expectMatch(match, 'perfect', deployedAddress, undefined); // status is null
+ });
});
});
diff --git a/scripts/find_replace.sh b/scripts/find_replace.sh
index 7d5d76f00..a859276ad 100755
--- a/scripts/find_replace.sh
+++ b/scripts/find_replace.sh
@@ -38,7 +38,7 @@ if [ "$CIRCLE_BRANCH" == "staging" ]; then
MOONSCAN_MOONRIVER_API_KEY=$MOONSCAN_MOONRIVER_API_KEY_STAGING
BOBASCAN_API_KEY=$BOBASCAN_API_KEY_STAGING
GNOSISSCAN_API_KEY=$GNOSISSCAN_API_KEY_STAGING
- OPTIMISTIC_ETHERSCAN_API_KEY=$OPTIMISTIC_ETHERSCAN_API_KEY_STAGING
+ OPTIMISMSCAN_API_KEY=$OPTIMISMSCAN_API_KEY_STAGING
fi
if [ "$CIRCLE_BRANCH" == "master" ]; then
@@ -68,14 +68,15 @@ if [ "$CIRCLE_BRANCH" == "master" ]; then
MOONSCAN_MOONRIVER_API_KEY=$MOONSCAN_MOONRIVER_API_KEY_MASTER
BOBASCAN_API_KEY=$BOBASCAN_API_KEY_MASTER
GNOSISSCAN_API_KEY=$GNOSISSCAN_API_KEY_MASTER
- OPTIMISTIC_ETHERSCAN_API_KEY=$OPTIMISTIC_ETHERSCAN_API_KEY_MASTER
+ OPTIMISMSCAN_API_KEY=$OPTIMISMSCAN_API_KEY_MASTER
fi
-for VAR_NAME in INFURA_ID ALCHEMY_ID AWS_S3_ACCESS_KEY_ID AWS_S3_SECRET_ACCESS_KEY IPFS_SECRET NPM_TOKEN PUBLIC_IP LOCAL_IP SESSION_SECRET ALCHEMY_ID_OPTIMISM ALCHEMY_ID_ARBITRUM CHAINSAFE_S3_ACCESS_KEY_ID CHAINSAFE_S3_SECRET_ACCESS_KEY ESTUARY_PINNING_SECRET WEB3_STORAGE_PINNING_SECRET CREATE2_CLIENT_TOKENS GRAFANA_HTTP_USER GRAFANA_HTTP_PASS ETHERSCAN_API_KEY ARBISCAN_API_KEY POLYGONSCAN_API_KEY BSCSCAN_API_KEY SNOWTRACE_API_KEY CELOSCAN_API_KEY MOONSCAN_MOONBEAM_API_KEY MOONSCAN_MOONRIVER_API_KEY BOBASCAN_API_KEY GNOSISSCAN_API_KEY OPTIMISTIC_ETHERSCAN_API_KEY
+for VAR_NAME in INFURA_ID ALCHEMY_ID AWS_S3_ACCESS_KEY_ID AWS_S3_SECRET_ACCESS_KEY IPFS_SECRET NPM_TOKEN PUBLIC_IP LOCAL_IP SESSION_SECRET ALCHEMY_ID_OPTIMISM ALCHEMY_ID_ARBITRUM CHAINSAFE_S3_ACCESS_KEY_ID CHAINSAFE_S3_SECRET_ACCESS_KEY ESTUARY_PINNING_SECRET WEB3_STORAGE_PINNING_SECRET CREATE2_CLIENT_TOKENS GRAFANA_HTTP_USER GRAFANA_HTTP_PASS ETHERSCAN_API_KEY ARBISCAN_API_KEY POLYGONSCAN_API_KEY BSCSCAN_API_KEY SNOWTRACE_API_KEY CELOSCAN_API_KEY MOONSCAN_MOONBEAM_API_KEY MOONSCAN_MOONRIVER_API_KEY BOBASCAN_API_KEY GNOSISSCAN_API_KEY OPTIMISMSCAN_API_KEY
do
echo "find_repace.sh: replacing $VAR_NAME"
VAR_VAL=$(eval "echo \${$VAR_NAME}")
# Use @ as delimiter instead of / as values may contain / but @ is unlikely
+ # sed on MacOS has different syntax. Install "gsed" with brew install gnu-sed and replace when developing on MacOS
sed -i "s@${VAR_NAME}=xxx@${VAR_NAME}=${VAR_VAL}@g" ../environments/.env.$TAG
done
diff --git a/src/config.ts b/src/config.ts
index abfa62bfe..9e4ac0cae 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -80,11 +80,11 @@ export const etherscanAPIs: EtherscanAPIs = {
},
"10": {
apiURL: "https://api-optimistic.etherscan.io",
- apiKey: process.env.OPTIMISTIC_ETHERSCAN_API_KEY,
+ apiKey: process.env.OPTIMISMSCAN_API_KEY,
},
"420": {
apiURL: "https://api-goerli-optimism.etherscan.io",
- apiKey: process.env.OPTIMISTIC_ETHERSCAN_API_KEY,
+ apiKey: process.env.OPTIMISMSCAN_API_KEY,
},
"43114": {
apiURL: "https://api.snowtrace.io",
diff --git a/src/server/controllers/VerificationController-util.ts b/src/server/controllers/VerificationController-util.ts
index e9a63aad9..b4411c488 100644
--- a/src/server/controllers/VerificationController-util.ts
+++ b/src/server/controllers/VerificationController-util.ts
@@ -567,6 +567,12 @@ export const processRequestFromEtherscan = async (
) {
throw new BadRequestError("Etherscan API rate limit reached, try later");
}
+
+ if (resultJson.message === "NOTOK") {
+ throw new BadRequestError(
+ "Error in Etherscan API response. Result message: " + resultJson.message
+ );
+ }
if (resultJson.result[0].SourceCode === "") {
throw new BadRequestError("This contract is not verified on Etherscan");
}
diff --git a/src/server/services/RepositoryService.ts b/src/server/services/RepositoryService.ts
index 34628f113..0ef87d004 100644
--- a/src/server/services/RepositoryService.ts
+++ b/src/server/services/RepositoryService.ts
@@ -6,7 +6,6 @@ import {
Status,
Create2Args,
StringMap,
- Metadata,
/* ContextVariables, */
CheckedContract,
} from "@ethereum-sourcify/lib-sourcify";
@@ -631,8 +630,22 @@ export default class RepositoryService implements IRepositoryService {
}
// This needs to be removed at some point https://github.com/ethereum/sourcify/issues/515
private sanitizePath(originalPath: string): string {
- return originalPath
+ const parsedPath = path.parse(originalPath);
+ const sanitizedDir = parsedPath.dir
+ .split(path.sep)
+ .filter((segment) => segment !== "..")
+ .join(path.sep)
.replace(/[^a-z0-9_./-]/gim, "_")
.replace(/(^|\/)[.]+($|\/)/, "_");
+
+ // Force absolute paths to be relative
+ if (parsedPath.root) {
+ parsedPath.root = "";
+ parsedPath.dir = sanitizedDir.slice(parsedPath.root.length);
+ } else {
+ parsedPath.dir = sanitizedDir;
+ }
+
+ return path.format(parsedPath);
}
}
diff --git a/src/sourcify-chains.ts b/src/sourcify-chains.ts
index 821167f2b..e94dcb654 100644
--- a/src/sourcify-chains.ts
+++ b/src/sourcify-chains.ts
@@ -196,6 +196,12 @@ const sourcifyChainsExtensions: SourcifyChainsExtensionsObject = {
"https://blockscout.com/xdai/mainnet/" + BLOCKSCOUT_SUFFIX,
txRegex: getBlockscoutRegex("/xdai/mainnet"),
},
+ "295": {
+ // Hedera Mainnet
+ supported: true,
+ monitored: false,
+ contractFetchAddress: "https://hashscan.io/mainnet/" + ETHERSCAN_SUFFIX,
+ },
"300": {
supported: true,
monitored: false,
@@ -561,6 +567,13 @@ const sourcifyChainsExtensions: SourcifyChainsExtensionsObject = {
contractFetchAddress: "https://tuber.build/" + BLOCKSCOUT_SUFFIX,
txRegex: getBlockscoutRegex(),
},
+ "7701": {
+ // Canto Testnet
+ supported: true,
+ monitored: false,
+ contractFetchAddress: "https://testnet.tuber.build/" + BLOCKSCOUT_SUFFIX,
+ txRegex: getBlockscoutRegex(),
+ },
"99": {
// POA Network Core
supported: true,
diff --git a/test/chains/chain-tests.js b/test/chains/chain-tests.js
index 58e4909c1..34b1e7d4a 100644
--- a/test/chains/chain-tests.js
+++ b/test/chains/chain-tests.js
@@ -1071,7 +1071,23 @@ describe("Test Supported Chains", function () {
["shared/WithImmutables.sol"],
"shared/withImmutables.metadata.json"
);
-
+ // Canto Testnet
+ verifyContract(
+ "0x37e12c98b4663DcE9ab1460073D9Fe82A7bFD0d8",
+ "7701",
+ "Canto Testnet",
+ ["shared/1_Storage.sol"],
+ "shared/1_Storage.metadata.json"
+ );
+ verifyContractWithImmutables(
+ "0x652785B4512F7e664448708852e59eF256D3f478",
+ "7701",
+ "Canto Testnet",
+ ["uint256"],
+ [7700],
+ ["shared/WithImmutables.sol"],
+ "shared/withImmutables.metadata.json"
+ );
// POA Network Core
verifyContract(
"0x3b2e3383AeE77A58f252aFB3635bCBd842BaeCB3",
@@ -1444,6 +1460,24 @@ describe("Test Supported Chains", function () {
"shared/withImmutables.metadata.json"
);
+ // Hedera Mainnet
+ verifyContract(
+ "0x00000000000000000000000000000000002265bb",
+ "295",
+ "Hedera Mainnet",
+ ["shared/1_Storage.sol"],
+ "shared/1_Storage.metadata.json"
+ );
+ verifyContractWithImmutables(
+ "0x00000000000000000000000000000000002265dd",
+ "295",
+ "Hedera Mainnet",
+ ["uint256"],
+ [42],
+ ["shared/WithImmutables.sol"],
+ "shared/withImmutables.metadata.json"
+ );
+
//////////////////////
// Helper functions //
//////////////////////
diff --git a/test/server.js b/test/server.js
index 6b211554d..bce28a0ca 100644
--- a/test/server.js
+++ b/test/server.js
@@ -890,6 +890,60 @@ describe("Server", function () {
);
});
});
+
+ it("should store a contract in /contracts/full_match|partial_match/0xADDRESS despite the files paths in the metadata", async () => {
+ const artifact = require("./testcontracts/Storage/Storage.json");
+ const [address] = await deployFromAbiAndBytecodeForCreatorTxHash(
+ localWeb3Provider,
+ artifact.abi,
+ artifact.bytecode,
+ accounts[0],
+ []
+ );
+
+ const metadata = require("./testcontracts/Storage/metadata.upMultipleDirs.json");
+ const sourcePath = path.join(
+ "test",
+ "testcontracts",
+ "Storage",
+ "Storage.sol"
+ );
+ const sourceBuffer = fs.readFileSync(sourcePath);
+
+ // Now pass the creatorTxHash
+ const res = await chai
+ .request(server.app)
+ .post("/")
+ .send({
+ address: address,
+ chain: defaultContractChain,
+ files: {
+ "metadata.json": JSON.stringify(metadata),
+ "Storage.sol": sourceBuffer.toString(),
+ },
+ });
+ assertVerification(
+ null,
+ res,
+ null,
+ address,
+ defaultContractChain,
+ "partial"
+ );
+ const isExist = fs.existsSync(
+ path.join(
+ server.repository,
+ "contracts",
+ "partial_match",
+ defaultContractChain,
+ address,
+ "sources",
+ "..contracts",
+ "Storage.sol"
+ )
+ );
+ chai.expect(isExist, "Files saved in the wrong directory").to.be.true;
+ });
});
describe("solc v0.6.12 and v0.7.0 extra files in compilation causing metadata match but bytecode mismatch", function () {
diff --git a/test/testcontracts/Storage/metadata.upMultipleDirs.json b/test/testcontracts/Storage/metadata.upMultipleDirs.json
new file mode 100644
index 000000000..e51b7ceac
--- /dev/null
+++ b/test/testcontracts/Storage/metadata.upMultipleDirs.json
@@ -0,0 +1,64 @@
+{
+ "compiler": { "version": "0.8.4+commit.c7e474f2" },
+ "language": "Solidity",
+ "output": {
+ "abi": [
+ {
+ "inputs": [],
+ "name": "retrieve",
+ "outputs": [
+ { "internalType": "uint256", "name": "", "type": "uint256" }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "uint256", "name": "num", "type": "uint256" }
+ ],
+ "name": "store",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ }
+ ],
+ "devdoc": {
+ "details": "Store & retrieve value in a variable",
+ "kind": "dev",
+ "methods": {
+ "retrieve()": {
+ "details": "Return value ",
+ "returns": { "_0": "value of 'number'" }
+ },
+ "store(uint256)": {
+ "details": "Store value in variable",
+ "params": { "num": "value to store" }
+ }
+ },
+ "title": "Storage",
+ "version": 1
+ },
+ "userdoc": { "kind": "user", "methods": {}, "version": 1 }
+ },
+ "settings": {
+ "compilationTarget": {
+ "..contracts/../../../../../Storage.sol": "Storage"
+ },
+ "evmVersion": "istanbul",
+ "libraries": {},
+ "metadata": { "bytecodeHash": "ipfs" },
+ "optimizer": { "enabled": false, "runs": 200 },
+ "remappings": []
+ },
+ "sources": {
+ "..contracts/../../../../../Storage.sol": {
+ "keccak256": "0x88c47206b5ec3d60ab820e9d126c4ac54cb17fa7396ff49ebe27db2862982ad8",
+ "license": "GPL-3.0",
+ "urls": [
+ "bzz-raw://5d1eeb01c8c10bed9e290f4a80a8d4081422a7b298a13049d72867022522cf6b",
+ "dweb:/ipfs/QmaFRC9ZtT7y3t9XNWCbDuMTEwKkyaQJzYFzw3NbeohSn5"
+ ]
+ }
+ },
+ "version": 1
+}
diff --git a/ui/src/pages/Lookup/Result.tsx b/ui/src/pages/Lookup/Result.tsx
index ce2c66ab7..df1b5e08c 100644
--- a/ui/src/pages/Lookup/Result.tsx
+++ b/ui/src/pages/Lookup/Result.tsx
@@ -49,9 +49,11 @@ type NetworkRowProp = {
};
type FoundProp = {
response: CheckAllByAddressResult;
+ goBack: () => void;
};
type NotFoundProp = {
address: any;
+ goBack: () => void;
};
type MatchStatusProps = {
@@ -268,7 +270,7 @@ const Create2Info = (response: CheckAllByAddressResult) => {
);
};
-const Found = ({ response }: FoundProp) => {
+const Found = ({ response, goBack }: FoundProp) => {
const chains = response?.chainIds.filter((chain) => chain.chainId !== "0");
const isCreate2Verified =
response?.chainIds.findIndex((chain) => chain.chainId === "0") >= 0;
@@ -293,13 +295,22 @@ const Found = ({ response }: FoundProp) => {
{isCreate2Verified && <>create2>} verified
{chains.length > 0 && on the following networks:}
@@ -325,12 +336,15 @@ const Found = ({ response }: FoundProp) => { + ); }; -const NotFound = ({ address }: NotFoundProp) => { +const NotFound = ({ address, goBack }: NotFoundProp) => { return ( <>