Перейти к основному содержанию
Работает на: Virtual Environments и публичных сетях (mainnet и testnet). Один и тот же плагин работает и там, и там; укажите нужную сеть в hardhat.config.ts.
Плагин Tenderly-Hardhat верифицирует контракты, развёрнутые из Hardhat, для Virtual Environments или публичных сетей. Используйте автоматическую верификацию, чтобы верифицировать при каждом деплое, или ручную верификацию, чтобы вызывать tenderly.verify() явно из ваших скриптов.
В публичных сетях плагин по умолчанию верифицирует публично. Чтобы верифицировать приватно (видимо только внутри вашего проекта/организации), установите privateVerification: true в hardhat.config.ts. См. Настройка аутентификации и видимости верификации.

Версии и совместимость

В зависимости от версии Ethers, которую вы используете с Hardhat, вам нужно установить соответствующую версию плагина Tenderly-Hardhat.
Настоятельно рекомендуется перейти на Ethers 6 и использовать последнюю версию плагина Tenderly-Hardhat из соображений безопасности, производительности, а также ради дополнительных возможностей.
Ваш стекВерсия HardhatВерсия плагина Tenderly-Hardhat
Ethers 6+ с Hardhat Ignition>=2.19.0 <=2.22.0@tenderly/hardhat-tenderly@^2.3.0
Ethers 6+ с hardhat-verify>=2.19.0 <=2.22.0@tenderly/hardhat-tenderly@^2.2.1
Ethers 5+ с hardhat-verify< 2.19.0@tenderly/hardhat-tenderly@1.8.0

Методы верификации

Плагин Tenderly-Hardhat поддерживает три метода верификации контрактов.
  • Автоматическая верификация (рекомендуется): просто импортируйте и настройте плагин. Этот метод идеален для верификации во время деплоя, поскольку процесс полностью автоматизирован. Автоматическая верификация работает как с обычной настройкой деплоя Hardhat, так и при использовании hardhat-ignition. Управляйте автоматической верификацией через переменную окружения TENDERLY_AUTOMATIC_VERIFICATION.
  • Ручная верификация (low-code): предоставляет явный шаг верификации внутри вашего кода, что полезно в сценариях типа пост-деплойной верификации, условной верификации (например, только после падения теста) или верификации экземпляров, созданных фабричными контрактами.
  • Подробная ручная верификация (high-code): даёт детальный контроль над процессом верификации, позволяя задать адреса библиотек, исходный код и конфигурации компилятора. Необходима для верификации нескольких контрактов с разными версиями или настройками компилятора.

Примеры

Лучший способ изучить процесс автоматической верификации — пройти пример, который есть в нашем GitHub-репозитории. Все примеры используют образцовый контракт Greeter. Просмотрите примеры проектов напрямую:

Настройка плагина Tenderly-Hardhat

Выполните шаги ниже, чтобы установить и инициализировать плагин Tenderly-Hardhat.
1
Установка
2
Установите плагин Tenderly-Hardhat и добавьте его в зависимости.
3
Ethers 6 (плагин v2.x)
yarn add -D @tenderly/hardhat-tenderly@^2.2.2
Ethers 5 (плагин v1.x)
yarn add -D @tenderly/hardhat-tenderly@^1.8.0
4
Войдите в Tenderly CLI
5
Плагин требует, чтобы вы были залогинены в Tenderly CLI.
6
macOS
curl https://raw.githubusercontent.com/Tenderly/tenderly-cli/master/scripts/install-macos.sh | sudo sh
Linux
curl https://raw.githubusercontent.com/Tenderly/tenderly-cli/master/scripts/install-linux.sh | sudo sh
7
Проверить, залогинены ли вы, можно этой командой:
8
tenderly whoami
9
Для входа выполните:
10
tenderly login
11
Инициализация
12
Включите пакет Tenderly-Hardhat в файл hardhat.config.ts или hardhat.config.js простым импортом и вызовом метода setup.
13
Импортируйте @tenderly/hardhat-tenderly после других пакетов, таких как @nomicfoundation/hardhat-toolbox, @nomiclabs/hardhat-ethers, @openzeppelin/hardhat-upgrades и подобных.
14
До версий 2.4.0 и 1.10.0 было необходимо вызывать tdly.setup() для инициализации плагина:
tdly.setup({automaticVerifications: !!process.env.TENDERLY_AUTOMATIC_VERIFICATION});
15


const config: HardhatUserConfig = {
solidity: "0.8.19",
};

export default config;
16
Настройка аутентификации и видимости верификации
17
Необходимо настроить Tenderly, передав информацию об аккаунте и уровень видимости верификации.
18
  • Параметр privateVerification гарантирует, что исходный код виден только соавторам вашего проекта или организации.
  • Видимость верификации также можно контролировать через переменную окружения TENDERLY_PUBLIC_VERIFICATION.
  • 19
    Настройте Tenderly, добавив следующий фрагмент кода в файл hardhat.config.ts:
    20
    
    
    const config: HardhatUserConfig = {
    solidity: "0.8.19",
    tenderly: {
    username: "Your account slug" ?? "error",
    project: "Your project slug",
    
    // Contract visible only in Tenderly.
    // Omitting or setting to `false` makes it visible to the whole world.
    // Alternatively, configure verification visibility using
    // an environment variable `TENDERLY_PUBLIC_VERIFICATION`.
    privateVerification: process.env.TENDERLY_PUBLIC_VERIFICATION !== 'true',
    },
    };
    
    export default config;
    
    21
    Настройте деплой
    22
    Настроив плагин Tenderly-Hardhat в проекте Hardhat, вы можете верифицировать контракты, развёрнутые в различных сетях для разработки и продакшена:
    23
  • Публичные mainnet или testnet через Node RPC
  • Virtual Environments для разработки, staging и демо
  • 24
    Чтобы включить верификацию при работе с hardhat-ignition, задайте конфигурацию etherscan. В качестве apiUrl используйте URL верификации: $TENDERLY_VIRTUAL_TESTNET_RPC/verify/etherscan.
    25
    С Hardhat Ignition
    hardhat.config.ts
    
    const config: HardhatUserConfig = {
    solidity: "0.8.19",
    networks: {
    mainnet_base: {
    url: "https://base.gateway.tenderly.co",
    chainId: 8453
    },
    tenderly_base_testnet: {
    // your Tenderly Virtual Environment RPC
    url: "https://virtual.base.rpc.tenderly.co/872ac073-1de1-4422-b01d-8d057781d77d",
    chainId: 888
    }
    },
    tenderly: {
    username: "Your account slug",
    project: "Your project slug",
    
    // Mainnet contract verification visible only in Tenderly.
    // Omitting or setting to `false` makes it visible to the whole world.
    // Alternatively, configure verification visibility using
    // an environment variable `TENDERLY_PUBLIC_VERIFICATION`.
    privateVerification: process.env.TENDERLY_PUBLIC_VERIFICATION !== 'true',
    },
    etherscan:{
    apiKey: "YOUR_API_KEY",
    customChains: [
    {
    network: "tenderly_base_testnet",
    chainId: 888,
    urls:{
    apiURL: `https://virtual.base.rpc.tenderly.co/872ac073-1de1-4422-b01d-8d057781d77d/verify/etherscan`,
    browserURL: "https://virtual.base.rpc.tenderly.co/872ac073-1de1-4422-b01d-8d057781d77d"
    }
    }
    ]
    },
    };
    
    export default config;
    
    Стандартная настройка
    hardhat.config.ts
    
    
    const config: HardhatUserConfig = {
    solidity: "0.8.19",
    networks: {
    mainnet_base: {
    url: "https://base.gateway.tenderly.co",
    chainId: 8453
    },
    tenderly_base_testnet: {
    // your Tenderly Virtual Environment RPC
    url: "https://virtual.base.rpc.tenderly.co/872ac073-1de1-4422-b01d-8d057781d77d",
    chainId: 888
    }
    },
    tenderly: {
    username: "Your account name",
    project: "Your project name",
    
    // Mainnet contract verification visible only in Tenderly.
    // Omitting or setting to `false` makes it visible to the whole world.
    // Alternatively, configure verification visibility using
    // an environment variable `TENDERLY_PUBLIC_VERIFICATION`.
    privateVerification: process.env.TENDERLY_PUBLIC_VERIFICATION !== 'true',
    },
    };
    
    export default config;
    
    В следующих разделах вы узнаете, как верифицировать контракты разными методами.

    Автоматическая верификация

    Автоматическая верификация происходит бесшовно, когда вы разворачиваете контракт через Ethers.js. Подход с автоматической верификацией выполняет верификацию автоматически, собирая настройки компилятора, адрес развёрнутого контракта и исходный код. Чтобы включить или отключить автоматическую верификацию, используйте переменную окружения TENDERLY_AUTOMATIC_VERIFICATION, которую распознаёт плагин. Плагин Tenderly-Hardhat верифицирует контракты, когда обнаруживает, что контракт развёрнут и Ethers получил квитанцию о транзакции деплоя. Чтобы это работало, нужно await-ать деплой при развёртывании через вспомогательные методы Ethers ethers.deployContract() и ethers.getContractFactory(), вызывая waitForDeployment() или deployed() на экземпляре контракта соответственно.
    Необходимо захватить ссылку на объект контракта, возвращаемый waitForDeployment() (Ethers 6) и deployed() (Ethers 5), если вы намерены с ним взаимодействовать.
    1
    Измените скрипт деплоя
    2
    Ethers 6
    Измените скрипт Hardhat так, чтобы захватить значение, возвращённое из waitForDeployment().
    deploy.ts
    
    export async function main() {
    console.log("🖖🏽[ethers] Deploying and Verifying Greeter in Tenderly");
    
    -   const greeter = await ethers.deployContract("Greeter", ["Hello, Hardhat!"]);
    +   let greeter = await ethers.deployContract("Greeter", ["Hello, Hardhat!"]);
    
    -   await greeter.waitForDeployment();
    +   greeter = await greeter.waitForDeployment();
    
    const greeterAddress = await greeter.getAddress();
    console.log("{Greeter} deployed to", greeterAddress);
    }
    
    main().catch((error) => {
    console.error(error);
    process.exitCode = 1;
    });
    
    В более компактной форме:
    const greeter = await (
    await ethers.deployContract("Greeter", ["Hello, Hardhat!"])
    ).waitForDeployment();
    
    Ethers 5
    Лучший способ изучить, как работает процесс автоматической верификации, — пройти пример в нашем GitHub-репозитории.Этот пример использует наш образцовый контракт Greeter.Измените скрипт Hardhat так, чтобы захватить значение, возвращённое из deployed().
    deploy.ts
    
    export async function main() {
    console.log("🖖🏽[ethers] Deploying and Verifying Greeter in Tenderly");
    
    const Greeter = await ethers.getContractFactory("Greeter");
    
    -   const greeter = await Greeter.deploy("Hello, Hardhat!");
    +   let greeter = await Greeter.deploy("Hello, Hardhat!");
    
    -   await greeter.deployed();
    +   greeter = await greeter.deployed();
    
    const greeterAddress = await greeter.address;
    console.log("{Greeter} deployed to", greeterAddress);
    }
    
    main().catch((error) => {
    console.error(error);
    process.exitCode = 1;
    });
    
    В более компактной форме:
    const greeter = await (
    await Greeter.deploy("Hello, Hardhat!")
    ).deployed();
    
    3
    Запустите скрипт
    4
    При запуске скриптов Hardhat вы можете установить переменную окружения TENDERLY_AUTOMATIC_VERIFICATION в true, чтобы включить автоматическую верификацию для конкретного запуска.
    5
    Запустите скрипт командами ниже. Ссылка на верифицированный контракт появится в выводе терминала.
    6
    Hardhat Ignition (Virtual Environment)
    TENDERLY_AUTOMATIC_VERIFICATION=true \
    npx hardhat ignition deploy ./ignition/modules/Lock.ts --network virtual_base --deployment-id deploy-to-virtual-base
    
    При запуске команды обязательно добавляйте --deployment-id с конкретным значением.
    Hardhat (Virtual Environment)
    TENDERLY_AUTOMATIC_VERIFICATION=true \
    npx hardhat run scripts/deploy.ts --network virtual_base
    
    Публичная сеть
    При деплое в публичный mainnet или testnet укажите, нужна ли публичная или приватная верификация. Убедитесь, что в разделе tenderly вашего hardhat.config.ts эта переменная окружения считывается.
    TENDERLY_PUBLIC_VERIFICATION=true \ # Verify publicly. Omit to verify privately.
    TENDERLY_AUTOMATIC_VERIFICATION=true \
    npx hardhat run scripts/deploy.ts --network mainnet_base
    

    Верификация прокси-контрактов

    Автоматическая верификация прокси-контрактов, развёрнутых и обновляемых через hardhat-upgrades, возможна в следующих версиях пакета @tenderly/hardhat-tenderly:
    • >= 1.10.0
    • >= 2.1.0
    Для версий 1.x.x < 1.10.0 и 2.x.x < 2.1.0 следуйте руководству по верификации прокси.

    Ручная верификация

    Low-code верификация через tenderly.verify() позволяет явно указать точку верификации внутри скрипта деплоя или теста Hardhat. Этот метод особенно полезен для:
    • Верификации ранее развёрнутых контрактов через кастомные скрипты.
    • Верификации экземпляров, созданных фабричными контрактами.
    • Улучшения тестовых прогонов за счёт выборочной верификации контрактов в конце падающего набора (after), что ускоряет выполнение.
    Чтобы вручную контролировать верификацию, отключите автоматическую, изменив TENDERLY_AUTOMATIC_VERIFICATION на false при запуске скриптов.

    Функция verify

    Функция verify() принимает объект, в котором необходимо указать:
    • name контракта
    • address, по которому развёрнут контракт
    • libraries (необязательно), используемые контрактом
    Плагин Tenderly-Hardhat подхватит существующую конфигурацию компилятора и исходный код, чтобы верифицировать указанные вами контракты.
    Необходимо вызывать verify() после того, как контракт развёрнут.Если вы выполняете верификацию параллельно с деплоем, необходимо await-ать waitForDeployment() в случае Ethers 6 и deployed() в случае Ethers 5.
    let greeter = await ethers.deployContract("Greeter", ["Hello, Hardhat!"]);
    greeter = await greeter.waitForDeployment();
    
    await tenderly.verify({
      name: 'Greeter',
      address: await greeter.getAddress(),
      libraries: {
        AwsomeLib: "0x...",
      }
    });
    
    Если вы верифицируете несколько контрактов, функция принимает переменное число аргументов:
    let greeter = await ethers.deployContract("Greeter", ["Hello, Hardhat!"]);
    greeter = await greeter.waitForDeployment();
    
    const counter = (await ethers.deployContract("Counter", [42])).waitForDeployment();
    
    await tenderly.verify(
      {
        name: 'Greeter',
        address: await greeter.getAddress(),
      },
      {
        name: 'Counter',
        address: await counter.getAddress(),
        libraries: {
            KickAssLib: "0x...",
        }
      },
    );
    
    1
    Отключите автоматический режим в hardhat.config.ts
    2
    Если вы предпочитаете отключить автоматическую верификацию:
    3
    
    - tdly.setup();
    + tdly.setup({automaticVerifications: false});
    
    const config: HardhatUserConfig = {
    
    4
    Измените скрипт деплоя
    5
    Здесь используются те же примеры, что и при автоматической верификации, но на этот раз для верификации контракта применяется метод tenderly.verify().
    6
    Ethers 6
    deploy.ts
        + import { tenderly } from "hardhat";
    
        async function main() {
        console.log("🖖🏽[ethers] Deploying and Verifying Greeter in Tenderly");
    
        -   const greeter = await ethers.deployContract("Greeter", ["Hello, Manual Hardhat!",]);
        +   let greeter = await ethers.deployContract("Greeter", ["Hello, Manual Hardhat!",]);
    
        -   await greeter.waitForDeployment();
        +   greeter = await greeter.waitForDeployment();
    
        const address = await greeter.getAddress();
        console.log("Manual Simple: {Greeter} deployed to:", address);
    
        +    await tenderly.verify({
        +        address,
        +        name: "Greeter",
        +    });
      }
    
        main().catch((error) => {
        console.error(error);
        process.exitCode = 1;
      });
    
    Ethers 5
    deploy.ts
        + import { tenderly } from "hardhat";
    
        async function main() {
        console.log("🖖🏽[ethers] Deploying and Verifying Greeter in Tenderly");
    
        const Greeter = await ethers.getContractFactory("Greeter");
    
        -   const greeter = await Greeter.deploy("Hello, Manual Hardhat!");
        +   let greeter = await Greeter.deploy("Hello, Manual Hardhat!");
    
        -   await greeter.deployed();
        +   greeter = await greeter.deployed();
    
        const address = await greeter.address;
        console.log("Manual Simple: {Greeter} deployed to:", address);
    
        await tenderly.verify({
        address,
        name: "Greeter",
      });
      }
    
        main().catch((error) => {
        console.error(error);
        process.exitCode = 1;
      });
    
    7
    Запустите скрипт
    8
    При запуске скриптов Hardhat вы можете установить переменную окружения TENDERLY_AUTOMATIC_VERIFICATION в false, чтобы отключить автоматическую верификацию.
    9
    Virtual Environment
    TENDERLY_AUTOMATIC_VERIFICATION=false \
    npx hardhat run scripts/deploy.ts --network virtual_base
    
    Публичная сеть
    При деплое в публичный mainnet или testnet укажите, нужна ли публичная или приватная верификация.
    TENDERLY_PUBLIC_VERIFICATION=false \ # Omit or set to true to verify publicly.
    TENDERLY_AUTOMATIC_VERIFICATION=false \
    npx hardhat run scripts/deploy.ts --network mainnet_base
    

    Подробная ручная верификация

    Метод verifyMultiCompilerAPI() даёт вам полный контроль над процессом верификации, позволяя указать каждую деталь процесса. Это редко рекомендуется, но может быть полезно, если вы верифицируете контракты, скомпилированные разными версиями или конфигурациями компилятора. Полностью управляемый метод верификации позволяет явно:
    • Указать исходный код контрактов (sources)
    • Задать аргументы компиляции (compiler)
    • Задать связанные библиотеки (libraries)
    Следующий пример демонстрирует, как выполнить полностью управляемую верификацию.
    await tenderly.verifyMultiCompilerAPI({
      contracts: [
        {
          contractToVerify: 'Greeter',
          sources: {
            'contracts/Greeter.sol': {
              name: 'Greeter',
              code: readFileSync('contracts/Greeter.sol', 'utf-8').toString(),
            },
            'hardhat/console.sol': {
              name: 'console',
              code: readFileSync('node_modules/hardhat/console.sol', 'utf-8').toString(),
            },
          },
          // solidity format compiler with a little modification at libraries param
          compiler: {
            version: '0.8.17',
            settings: {
              optimizer: {
                enabled: true,
                runs: 200,
              },
            },
            libraries: {
              'path/to/lib.sol': {
                addresses: {
                  LibName1: '0x...',
                  LibName2: '0x...',
                },
              },
            },
          },
          networks: {
            [NETWORK_ID]: {
              address: greeterAddress,
            },
          },
        },
      ],
    });
    

    Аргументы верификации

    Метод verifyMultiCompilerAPI() принимает один аргумент — массив объектов-контрактов. Каждый объект-контракт состоит из следующих полей:
    contractToVerifystringИмя контракта, который нужно верифицировать. Это может быть короткое имя вроде Greeter или полностью квалифицированное имя контракта вроде contracts/A/Greeter.sol:Greeter.
    sourcesmapКарта всех источников, необходимых для компиляции контракта. Ключ карты — путь к исходному коду контракта, а значение — объект с именем и UTF-8-кодированным исходником. js sources: { 'contracts/Greeter.sol': { name: 'Greeter', code: readFileSync('contracts/Greeter.sol', 'utf-8').toString(), }, 'hardhat/console.sol': { name: 'console', code: readFileSync('node_modules/hardhat/console.sol', 'utf-8').toString(), }, },
    networksmapКарта, содержащая все адреса деплоев в разных сетях. js { networks: { [NETWORK_ID]: { address: greeterAddress, }, }, }
    librariesmapКарта, содержащая информацию о деплоях библиотек. Ключ — относительный путь к исходнику библиотеки, относительно папки contracts. js compiler.settings.libraries = { "path/to/lib.sol": { addresses: { "LibName1": "0x...", "LibName2": "0x..." } } }