Верифікація смарт-контрактів на Etherscan
Задеплоїв контракт, транзакція пройшла, все працює — і тут приходить запит від партнера або інвестора: «Покажи код». На Etherscan замість вихідників — байткод. Верифікація не зроблена. Це не кінець світу, але пояснювати, чому публічний контракт закритий, незручно.
Чому байткоду недостатньо
Etherscan зберігає deployedBytecode для кожного контракту, але деобфусцирувати його назад у читабельний Solidity — задача нетривіальна. Інструменти вроді Dedaub Decompiler дають приблизний результат, не точний. Без верифікації неможливо:
- викликати функції через Etherscan Read/Write інтерфейс без ABI
- переконатись, що задеплоєний код відповідає опублікованому репозиторію
- пройти листинг на CoinGecko, CoinMarketCap, більшість DEX-агрегаторів
- отримати довіру користувачів — чекмарк «Contract Source Verified» на Etherscan став стандартом де-факто
Технічно верифікація — це відтворення компіляції на стороні Etherscan. Платформа береж ваш вихідний код, компілює з тими ж параметрами (версія solc, optimizer runs, via-ir flag) та порівнює байткод з задеплоєним. При невідповідності — відмова.
Чому верифікація іноді не проходить
Невідповідність версії компілятора. Solidity 0.8.19 та 0.8.20 дають різний байткод навіть на одинаковому вихідники. Hardhat фіксує версію в hardhat.config.ts, її потрібно точно указати при верифікації.
Optimizer settings. Якщо контракт деплоївся з optimizer: { enabled: true, runs: 200 }, а при верифікації указати runs: 1000 — байткод не збіжиться. Це найчастіша причина фейла при першій спробі.
via-IR pipeline. Починаючи з Solidity 0.8.13 доступна компіляція через проміжне представлення Yul (viaIR: true). Ця опція змінює байткод. Якщо вона використовувалась при деплої — при верифікації теж потрібно указати.
Flattened контракт з конфліктами. Деякі заливають на Etherscan flattened-файл через hardhat flatten. Якщо в ньому кілька деклараій однієї бібліотеки — верифікація падає з помилкою duplicate identifier.
Immutable змінні. Значення immutable вшиваються в байткод при деплої. Якщо верифікація йде через стандартний JSON input, значення immutable потрібно указати окремо — інакше невідповідність.
Як ми верифікуємо
Використовуємо Hardhat Verify плагін (@nomicfoundation/hardhat-verify) для автоматичної верифікації одразу після деплою:
// hardhat.config.ts
etherscan: {
apiKey: {
mainnet: process.env.ETHERSCAN_API_KEY,
polygon: process.env.POLYGONSCAN_API_KEY,
arbitrumOne: process.env.ARBISCAN_API_KEY,
}
}
Після деплою одна команда:
npx hardhat verify --network mainnet 0xYourContractAddress "ConstructorArg1" "ConstructorArg2"
Для proxy-контрактів (OpenZeppelin TransparentUpgradeableProxy, UUPS) — верифікація потрібна окремо для proxy та implementation. Hardhat Verify поддерживает флаг --contract для явного указання implementation.
Якщо контракт деплоївся через Foundry — використовуємо forge verify-contract:
forge verify-contract 0xAddress src/MyContract.sol:MyContract \
--chain mainnet \
--constructor-args $(cast abi-encode "constructor(address)" 0xArg) \
--etherscan-api-key $ETHERSCAN_API_KEY
Foundry також поддерживает --verifier sourcify для верифікації на Sourcify — альтернативному відкритому реєстрі, який поддерживають багато чейни без власного Etherscan.
Мультичейн верифікація. Один та той же контракт на Ethereum Mainnet, Polygon, Arbitrum, Optimism, BSC потрібно верифікувати окремо на кожному скані. Автоматизуємо через скрипт деплою з post-deploy хуком.
Процес роботи
Якщо контракт вже задеплоєний, але не верифікований — восстанавлюємо параметри компіляції з артефактів деплою. Hardhat зберігає deployments/<network>/<Contract>.json з повним compiler input. Foundry — out/<Contract>.json з metadata.
Якщо артефакти втрачені — аналізуємо байткод через evmole або whatsabi для восстановлення ABI, потім підбираємо параметри компілятора. Це займає більше часу, але виконуємо для контрактів на стандартних версіях Solidity.
Час верифікації одного контракту — 2-4 години з урахуванням діагностики. Якщо контракт простий та артефакти збережені — 30-60 хвилин.







