Верификация смарт-контрактов на 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 plugin (@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 минут.







