Перейти к основному содержанию
Узнайте, как настроить GitHub Action для организации пайплайна непрерывной интеграции и непрерывного развёртывания (CI/CD) с Hardhat на Tenderly Virtual Environments. Используйте Tenderly Virtual Environment Setup, чтобы включить автоматизированные сборки, тестирующие и деплоящие ваши контракты в несколько сетей. После успешного тестирования вы можете передать их остальной команде, развернув в подготовленных Virtual Environments. В этом руководстве нужно пройти два этапа:
  1. Локальная настройка: настройте Hardhat и создайте и протестируйте файл workflow.
  2. Настройка в GitHub: настройте GitHub Action, сконфигурируйте GitHub-секреты и переменные, протестируйте сборку.
Для справки используйте этот пример проекта:

Настройка CI/CD с hardhat-ignition

Это руководство демонстрирует настройку CI, полагающуюся на Hardhat-ignition. Для настройки hardhat-verify процесс и конфигурация аналогичны.
Continuous integration (CI) and continous deployment (CD) with Virtual Environments

Этап 1: локальная настройка

Сначала мы установим необходимые зависимости и создадим файл workflow.
1
Установите зависимости
2
Убедитесь, что установлены следующие пакеты:
3
npm install --save-dev @tenderly/hardhat-tenderly @nomicfoundation/hardhat-ignition
4
Создайте файл workflow
5
Чтобы настроить GitHub Action, создайте новый workflow:
6
mkdir -p .github/workflows
touch ci-cd.yaml
7
Затем вставьте следующий yaml-файл, который настраивает две задачи:
8
  • test — запускает тесты Hardhat, используя одну сеть для тестирования
  • deploy — деплоит контракты в несколько сетей (Mainnet и Base) после успешного тестирования
  • 9
    Аргумент mode принимает значения CI и CD.
    • Режим CD оставляет Virtual Environment активной, и вы можете работать с задеплоенными контрактами.
    • Режим CI приостанавливает Virtual Environment после завершения шага. Вы сможете просматривать транзакции, но не сможете отправлять дальнейшие RPC-запросы.
    10
    name: Hardhat CI/CD Multichain
    
    on: [push, pull_request]
    env:
      ## Needed available as env variables for hardhat.config.js
      TENDERLY_PROJECT_NAME: ${{ vars.TENDERLY_PROJECT_NAME }}
      TENDERLY_ACCOUNT_NAME: ${{ vars.TENDERLY_ACCOUNT_NAME }}
    jobs:
      test:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
    
          - name: Setup Node.js
            uses: actions/setup-node@v4
            with:
              node-version: '20'
              cache: 'npm'
    
          - name: Setup Virtual Environment
            uses: tenderly/vnet-github-action@v1.0.14
            with:
              mode: CI    # pauses the Virtual Environment after deployment
              access_key: ${{ secrets.TENDERLY_ACCESS_KEY }}
              project_name: ${{ vars.TENDERLY_PROJECT_NAME }}
              account_name: ${{ vars.TENDERLY_ACCOUNT_NAME }}
              testnet_name: "Testing"
              network_id: 1
              chain_id_prefix: 7357
              public_explorer: true
              verification_visibility: 'src'
              push_on_complete: true
    
          - name: Install dependencies
            run: npm install
            working-directory: examples/hardhat-ignition
    
          - name: Run Tests
            run: npm run test:1
            working-directory: examples/hardhat-ignition
    
      deploy:
        needs: test
        runs-on: ubuntu-latest
        permissions:
          contents: write
        steps:
          - uses: actions/checkout@v4
    
          - name: Setup Node.js
            uses: actions/setup-node@v4
            with:
              node-version: '20'
              cache: 'npm'
    
          - name: Setup Virtual Environment
            uses: tenderly/vnet-github-action@v1.0.14
            with:
              mode: CD
              access_key: ${{ secrets.TENDERLY_ACCESS_KEY }}
              project_name: ${{ vars.TENDERLY_PROJECT_NAME }}
              account_name: ${{ vars.TENDERLY_ACCOUNT_NAME }}
              testnet_name: "Staging"
              network_id: |
                1
                8453
              chain_id_prefix: ""
              public_explorer: true
              verification_visibility: 'src'
              push_on_complete: true
    
          - name: Install dependencies
            run: npm install
            working-directory: examples/hardhat-ignition
    
          - name: Deploy Contracts Mainnet
            run: npm run deploy:1 -- --deployment-id deploy-1-${BUILD_SLUG}
            working-directory: examples/hardhat-ignition
    
          - name: Deploy Contracts Base
            run: npm run deploy:8453 -- --deployment-id deploy-8453-${BUILD_SLUG}
            working-directory: examples/hardhat-ignition
    
    11
    Подготовьте переменные окружения
    12
    Для локального тестирования настройте файл .env, используя этот шаблон:
    13
    ## Access parameters
    TENDERLY_ACCESS_KEY=...
    TENDERLY_PROJECT_NAME=...
    TENDERLY_ACCOUNT_NAME=...
    
    ## Network-specific parameters (populated by the action in CI/CD)
    TENDERLY_ADMIN_RPC_URL_1=...    # Mainnet RPC
    TENDERLY_ADMIN_RPC_URL_8453=... # Base RPC
    TENDERLY_CHAIN_ID_1=...         # Mainnet chain ID
    TENDERLY_CHAIN_ID_8453=...      # Base chain ID
    
    14
    Обязательные переменные:
    15
  • TENDERLY_ACCESS_KEY: узнайте, как получить ваш access key
  • TENDERLY_ACCOUNT_NAME и TENDERLY_PROJECT_NAME: следуйте шагам, чтобы получить имена вашего аккаунта и проекта
  • 16
    Настройте Hardhat
    17
    Добавьте конфигурацию Virtual Environment в hardhat.config.ts:
    18
    
    dotenv.config();
    
    const config: HardhatUserConfig = {
      solidity: "0.8.27",
      networks: {
        mainnet: {
          url: process.env.TENDERLY_ADMIN_RPC_URL_1,
          chainId: parseInt(process.env.TENDERLY_CHAIN_ID_1 || "1")
        },
        base: {
          url: process.env.TENDERLY_ADMIN_RPC_URL_8453,
          chainId: parseInt(process.env.TENDERLY_CHAIN_ID_8453 || "8453")
        }
      },
      etherscan: {
        apiKey: {
          mainnet: process.env.TENDERLY_ACCESS_KEY!,
          base: process.env.TENDERLY_ACCESS_KEY!
        },
        customChains: [
          {
            network: "mainnet",
            chainId: parseInt(process.env.TENDERLY_CHAIN_ID_1!),
            urls: {
              apiURL: `${process.env.TENDERLY_ADMIN_RPC_URL_1}/verify`,
              browserURL: process.env.TENDERLY_ADMIN_RPC_URL_1!
            }
          },
          {
            network: "base",
            chainId: parseInt(process.env.TENDERLY_CHAIN_ID_8453!),
            urls: {
              apiURL: `${process.env.TENDERLY_ADMIN_RPC_URL_8453}/verify`,
              browserURL: process.env.TENDERLY_ADMIN_RPC_URL_8453!
            }
          }
        ]
      },
      tenderly: {
        project: process.env.TENDERLY_PROJECT_NAME!,
        username: process.env.TENDERLY_ACCOUNT_NAME!,
        accessKey: process.env.TENDERLY_ACCESS_KEY!
      },
      sourcify: {
        enabled: false
      }
    };
    
    export default config;
    
    19
    Добавьте скрипты тестирования и развёртывания
    20
    Добавьте следующие скрипты в ваш package.json для мультисетевого тестирования и развёртывания:
    21
    {
      "scripts": {
        "deploy:1": "npx hardhat ignition deploy ./ignition/modules/Counter.js --network mainnet",
        "deploy:8453": "npx hardhat ignition deploy ./ignition/modules/Counter.js --network base",
        "test:1": "npx hardhat test --network mainnet"
      }
    }
    
    22
    Команды деплоя используют переменную окружения BUILD_SLUG (предоставляемую action’ом), чтобы создавать уникальные идентификаторы развёртывания.
    23
    Протестируйте сборку локально
    24
    Чтобы протестировать сборку локально, выполните следующие команды:
    25
    # Test on mainnet fork
    npx hardhat test:1
    
    # Deploy to mainnet fork
    npx hardhat deploy:1
    
    # Deploy to Base fork
    npx hardhat deploy:8453
    
    26
    Протестируйте GitHub Action локально
    27
    Чтобы протестировать ваш action локально, можно использовать Act:
    28
    act --secret-file .env --var-file .env
    

    Этап 2: настройка GitHub

    После успешной локальной настройки продолжите, сконфигурировав GitHub переменными окружения и необходимыми секретами.
    1
    Настройте секреты и переменные окружения в GitHub
    2
    Нужно настроить следующие переменные и секрет GitHub:
    3
    Переменные:
    4
  • TENDERLY_PROJECT_NAME
  • TENDERLY_ACCOUNT_NAME
  • 5
    Секреты:
    6
  • TENDERLY_ACCESS_KEY
  • 7
    Это можно сделать через GitHub UI или с помощью командной строки gh:
    8
    source .env
    
    gh variable set TENDERLY_PROJECT_NAME --body ${TENDERLY_PROJECT_NAME}
    gh variable set TENDERLY_ACCOUNT_NAME --body ${TENDERLY_ACCOUNT_NAME}
    gh secret set TENDERLY_ACCESS_KEY --body ${TENDERLY_ACCESS_KEY}
    
    9
    Запушьте обновления
    10
    Чтобы запустить GitHub Action, запушьте ваши изменения:
    11
    git add .
    git commit -m "Add CI/CD workflow for multichain deployment"
    git push
    
    12
    Проверьте ваш action
    13
    Перейдите в ваш GitHub-репозиторий и посмотрите вкладку Actions. Вы должны увидеть:
    14
  • Задачу test, запускающуюся против форка mainnet
  • Задачу deploy, создающую две Virtual Environments (mainnet и Base)
  • Артефакты развёртывания, отправляемые в репозиторий
  • 15
    Получите RPC-ссылки
    16
    Чтобы получить RPC-ссылки для ваших развёрнутых контрактов:
    17
  • Перейдите в Tenderly dashboard > Virtual Environments
  • Найдите ваши CD Virtual Environments (одна для форка mainnet, одна для форка Base)
  • Щёлкните на каждой, чтобы получить их RPC URL
  • Справочник переменных окружения

    GitHub Action предоставляет следующие переменные, специфичные для сети:
    ПеременнаяОписание
    TENDERLY_TESTNET_ID_{network_id}UUID Virtual Environment
    TENDERLY_ADMIN_RPC_URL_{network_id}Эндпоинт Admin RPC с методами чит-кодов
    TENDERLY_PUBLIC_RPC_URL_{network_id}Публичный RPC-эндпоинт
    TENDERLY_CHAIN_ID_{network_id}Chain ID
    TENDERLY_TESTNET_SLUG_{network_id}Уникальный слаг Virtual Environment
    BUILD_SLUGУникальный идентификатор текущей сборки

    Дальнейшие шаги

    Изучите другие примеры: