Skip to content

Commit

Permalink
Timelock authorizer configuration CI (#89)
Browse files Browse the repository at this point in the history
  • Loading branch information
jubeira authored Oct 23, 2023
1 parent fbd7914 commit c1590bd
Show file tree
Hide file tree
Showing 15 changed files with 1,480 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: 'Verify Timelock Authorizer Config'
inputs:
network-name:
required: true
runs:
using: "composite"
steps:
- uses: actions/checkout@v3
- name: Set up environment
uses: ./.github/actions/setup
- name: Prepare Config
run: yarn ci:prepare-config
shell: bash
- name: Check Timelock Authorizer config
run: yarn verify-network-timelock-authorizer-config ${{ inputs.network-name }}
shell: bash
11 changes: 11 additions & 0 deletions .github/workflows/deployment-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,17 @@ jobs:
- name: Check Deployment Address Lookup File
run: yarn check-address-lookup

check-timelock-authorizer-config:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up environment
uses: ./.github/actions/setup
- name: Prepare Config
run: yarn ci:prepare-config
- name: Check Timelock Authorizer Configuration Files
run: yarn check-timelock-authorizer-config

markdown-link-check:
runs-on: ubuntu-latest
steps:
Expand Down
124 changes: 124 additions & 0 deletions .github/workflows/timelock-authorizer-config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
name: Timelock Authorizer

on:
push:
branches:
- master
pull_request:
branches: ['*', '**/*']
schedule:
- cron: "0 0 * * *"

jobs:
verify-mainnet-timelock-authorizer-config:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Verify Mainnet Timelock Authorizer Configuration
uses: ./.github/actions/verify-network-timelock-authorizer-config
env:
MAINNET_RPC_ENDPOINT: ${{ secrets.MAINNET_RPC_ENDPOINT }}
with:
network-name: mainnet

verify-polygon-timelock-authorizer-config:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Verify Polygon Timelock Authorizer Configuration
uses: ./.github/actions/verify-network-timelock-authorizer-config
env:
POLYGON_RPC_ENDPOINT: ${{ secrets.POLYGON_RPC_ENDPOINT }}
with:
network-name: polygon

verify-arbitrum-timelock-authorizer-config:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Verify Arbitrum Timelock Authorizer Configuration
uses: ./.github/actions/verify-network-timelock-authorizer-config
env:
ARBITRUM_RPC_ENDPOINT: ${{ secrets.ARBITRUM_RPC_ENDPOINT }}
with:
network-name: arbitrum

verify-optimism-timelock-authorizer-config:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Verify Optimism Timelock Authorizer Configuration
uses: ./.github/actions/verify-network-timelock-authorizer-config
env:
OPTIMISM_RPC_ENDPOINT: ${{ secrets.OPTIMISM_RPC_ENDPOINT }}
with:
network-name: optimism

verify-bsc-timelock-authorizer-config:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Verify Binance Timelock Authorizer Configuration
uses: ./.github/actions/verify-network-timelock-authorizer-config
env:
BINANCE_RPC_ENDPOINT: ${{ secrets.BINANCE_RPC_ENDPOINT }}
with:
network-name: bsc

verify-gnosis-timelock-authorizer-config:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Verify Gnosis Timelock Authorizer Configuration
uses: ./.github/actions/verify-network-timelock-authorizer-config
env:
GNOSIS_RPC_ENDPOINT: ${{ secrets.GNOSIS_RPC_ENDPOINT }}
with:
network-name: gnosis

verify-avalanche-timelock-authorizer-config:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Verify Avalanche Timelock Authorizer Configuration
uses: ./.github/actions/verify-network-timelock-authorizer-config
env:
AVALANCHE_RPC_ENDPOINT: ${{ secrets.AVALANCHE_RPC_ENDPOINT }}
with:
network-name: avalanche

verify-zkevm-timelock-authorizer-config:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Verify Polygon-ZkEvm Timelock Authorizer Configuration
uses: ./.github/actions/verify-network-timelock-authorizer-config
env:
ZKEVM_RPC_ENDPOINT: ${{ secrets.ZKEVM_RPC_ENDPOINT }}
with:
network-name: zkevm

verify-goerli-timelock-authorizer-config:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Verify Goerli Timelock Authorizer Configuration
uses: ./.github/actions/verify-network-timelock-authorizer-config
env:
GOERLI_RPC_ENDPOINT: ${{ secrets.GOERLI_RPC_ENDPOINT }}
with:
network-name: goerli

verify-sepolia-timelock-authorizer-config:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Verify Sepolia Timelock Authorizer Configuration
uses: ./.github/actions/verify-network-timelock-authorizer-config
env:
SEPOLIA_RPC_ENDPOINT: ${{ secrets.SEPOLIA_RPC_ENDPOINT }}
with:
network-name: sepolia

env:
CI: true
107 changes: 105 additions & 2 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { existsSync, readdirSync, readFileSync, statSync } from 'fs';

import { checkArtifact, extractArtifact } from './src/artifact';
import test from './src/test';
import Task, { TaskMode } from './src/task';
import Task, { TaskMode, TaskStatus } from './src/task';
import Verifier from './src/verifier';
import logger, { Logger } from './src/logger';
import {
Expand All @@ -26,7 +26,13 @@ import {
getActionIdInfo,
fetchTheGraphPermissions,
} from './src/actionId';
import { checkContractDeploymentAddresses, saveContractDeploymentAddresses } from './src/network';
import {
checkContractDeploymentAddresses,
checkTimelockAuthorizerConfig,
getTimelockAuthorizerConfigDiff,
saveContractDeploymentAddresses,
saveTimelockAuthorizerConfig,
} from './src/network';

const THEGRAPHURLS: { [key: string]: string } = {
goerli: 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-authorizer-goerli',
Expand Down Expand Up @@ -298,6 +304,103 @@ task(
}
});

task('build-timelock-authorizer-config', `Builds JSON file with Timelock Authorizer configuration`).setAction(
async (args: { verbose?: boolean }, hre: HardhatRuntimeEnvironment) => {
Logger.setDefaults(false, args.verbose || false);

if (hre.network.name === 'hardhat') {
logger.warn(`invalid network: ${hre.network.name}`);
return;
}

// Get active timelock authorizer task.
const tasks = Task.getAllTaskIds()
.filter((taskId) => taskId.includes('timelock-authorizer'))
.map((taskId) => new Task(taskId, TaskMode.READ_ONLY, hre.network.name))
.filter((task) => task.getStatus() === TaskStatus.ACTIVE);

if (tasks.length !== 1) {
const errorMsg = tasks.length === 0 ? 'not found' : 'is not unique';
logger.error(`Active timelock authorizer task ${errorMsg}`);
return;
}

saveTimelockAuthorizerConfig(tasks[0], hre.network.name);

logger.success(`Timelock Authorizer config JSON generated for network ${hre.network.name}`);
}
);

task(
'check-timelock-authorizer-config',
`Check whether the existing timelock authorizer configuration file is correct`
).setAction(async (args: { verbose?: boolean }, hre: HardhatRuntimeEnvironment) => {
Logger.setDefaults(false, args.verbose || false);

if (hre.network.name === 'hardhat') {
logger.warn(`invalid network: ${hre.network.name}`);
return;
}

// Get active timelock authorizer task.
const tasks = Task.getAllTaskIds()
.filter((taskId) => taskId.includes('timelock-authorizer'))
.map((taskId) => new Task(taskId, TaskMode.READ_ONLY, hre.network.name))
.filter((task) => task.getStatus() === TaskStatus.ACTIVE);

if (tasks.length !== 1) {
const errorMsg = tasks.length === 0 ? 'not found' : 'is not unique';
logger.error(`Active timelock authorizer task ${errorMsg}`);
return;
}

const isConfigOk = checkTimelockAuthorizerConfig(tasks[0], hre.network.name);

if (isConfigOk) {
logger.success(`Timelock Authorizer config JSON is correct for network ${hre.network.name}`);
} else {
throw new Error(
`Timelock Authorizer config file is incorrect for network ${hre.network.name}. Please run 'build-timelock-authorizer-config' to regenerate it`
);
}
});

task(
'verify-timelock-authorizer-config',
`Check whether the existing timelock authorizer configuration file matches the delays configured onchain`
).setAction(async (args: { verbose?: boolean }, hre: HardhatRuntimeEnvironment) => {
Logger.setDefaults(false, args.verbose || false);

if (hre.network.name === 'hardhat') {
logger.warn(`invalid network: ${hre.network.name}`);
return;
}

// Get active timelock authorizer task.
const tasks = Task.getAllTaskIds()
.filter((taskId) => taskId.includes('timelock-authorizer'))
.map((taskId) => new Task(taskId, TaskMode.READ_ONLY, hre.network.name))
.filter((task) => task.getStatus() === TaskStatus.ACTIVE);

if (tasks.length !== 1) {
const errorMsg = tasks.length === 0 ? 'not found' : 'is not unique';
logger.error(`Active timelock authorizer task ${errorMsg}`);
return;
}

const configDiff = await getTimelockAuthorizerConfigDiff(tasks[0], hre.network.name);

if (configDiff.length === 0) {
logger.success(`Timelock Authorizer config is correctly applied on-chain for network ${hre.network.name}`);
} else {
throw new Error(
`Timelock Authorizer config file is incorrect for network ${
hre.network.name
}. Differences found:\n${JSON.stringify(configDiff, null, 2)}`
);
}
});

task(TASK_TEST).addOptionalParam('id', 'Specific task ID of the fork test to run.').setAction(test);

export default {
Expand Down
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@
"extract-artifacts": "hardhat extract-artifacts",
"build-address-lookup": "hardhat build-address-lookup --network mainnet && hardhat build-address-lookup --network polygon && hardhat build-address-lookup --network arbitrum && hardhat build-address-lookup --network optimism && hardhat build-address-lookup --network gnosis && hardhat build-address-lookup --network bsc && hardhat build-address-lookup --network avalanche && hardhat build-address-lookup --network zkevm && hardhat build-address-lookup --network base && hardhat build-address-lookup --network fantom && hardhat build-address-lookup --network goerli && hardhat build-address-lookup --network sepolia",
"check-address-lookup": "hardhat check-address-lookup --network mainnet && hardhat check-address-lookup --network polygon && hardhat check-address-lookup --network arbitrum && hardhat check-address-lookup --network optimism && hardhat check-address-lookup --network gnosis && hardhat check-address-lookup --network bsc && hardhat check-address-lookup --network avalanche && hardhat check-address-lookup --network zkevm && hardhat check-address-lookup --network base && hardhat check-address-lookup --network fantom && hardhat check-address-lookup --network goerli && hardhat check-address-lookup --network sepolia",
"build-timelock-authorizer-config": "hardhat build-timelock-authorizer-config --network mainnet && hardhat build-timelock-authorizer-config --network polygon && hardhat build-timelock-authorizer-config --network arbitrum && hardhat build-timelock-authorizer-config --network optimism && hardhat build-timelock-authorizer-config --network gnosis && hardhat build-timelock-authorizer-config --network bsc && hardhat build-timelock-authorizer-config --network avalanche && hardhat build-timelock-authorizer-config --network zkevm && hardhat build-timelock-authorizer-config --network base && hardhat build-timelock-authorizer-config --network fantom && hardhat build-timelock-authorizer-config --network goerli && hardhat build-timelock-authorizer-config --network sepolia",
"check-timelock-authorizer-config": "hardhat check-timelock-authorizer-config --network mainnet && hardhat check-timelock-authorizer-config --network polygon && hardhat check-timelock-authorizer-config --network arbitrum && hardhat check-timelock-authorizer-config --network optimism && hardhat check-timelock-authorizer-config --network gnosis && hardhat check-timelock-authorizer-config --network bsc && hardhat check-timelock-authorizer-config --network avalanche && hardhat check-timelock-authorizer-config --network zkevm && hardhat check-timelock-authorizer-config --network base && hardhat check-timelock-authorizer-config --network fantom && hardhat check-timelock-authorizer-config --network goerli && hardhat check-timelock-authorizer-config --network sepolia",
"verify-network-timelock-authorizer-config": "hardhat verify-timelock-authorizer-config --network",
"verify-timelock-authorizer-config": "hardhat verify-timelock-authorizer-config --network mainnet && hardhat verify-timelock-authorizer-config --network polygon && hardhat verify-timelock-authorizer-config --network arbitrum && hardhat verify-timelock-authorizer-config --network optimism && hardhat verify-timelock-authorizer-config --network gnosis && hardhat verify-timelock-authorizer-config --network bsc && hardhat verify-timelock-authorizer-config --network avalanche && hardhat verify-timelock-authorizer-config --network zkevm && hardhat verify-timelock-authorizer-config --network base && hardhat verify-timelock-authorizer-config --network fantom && hardhat verify-timelock-authorizer-config --network goerli && hardhat verify-timelock-authorizer-config --network sepolia",
"lint": "yarn lint:solidity && yarn lint:typescript",
"lint:solidity": "solhint 'src/helpers/contracts/**/*.sol'",
"lint:typescript": "NODE_NO_WARNINGS=1 eslint . --ext .ts --ignore-path ./.eslintignore --max-warnings 0",
Expand Down
2 changes: 1 addition & 1 deletion src/actionId.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ async function checkFactoryOutput(task: Task, contractName: string, factoryOutpu
}

/** Returns full info for a given actionId and network */
export async function getActionIdInfo(actionId: string, network: string): Promise<ActionIdInfo | undefined> {
export function getActionIdInfo(actionId: string, network: string): ActionIdInfo | undefined {
// read network JSON file from action-ids dir
const tasks = safeReadJsonFile<TaskActionIds>(path.join(ACTION_ID_DIRECTORY, network, 'action-ids.json'));
// filter all the entries which have the same actionId
Expand Down
17 changes: 16 additions & 1 deletion src/helpers/time.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { BigNumber, ContractReceipt } from 'ethers';
import { ethers } from 'hardhat';

import { BigNumberish, bn } from './numbers';

Expand Down Expand Up @@ -33,6 +32,8 @@ export const setNextBlockTimestamp = async (timestamp: BigNumberish): Promise<vo
export const lastBlockNumber = async (): Promise<number> => await time.latestBlock();

export const receiptTimestamp = async (receipt: ContractReceipt | Promise<ContractReceipt>): Promise<number> => {
const { ethers } = await import('hardhat');

const blockHash = (await receipt).blockHash;
const block = await ethers.provider.getBlock(blockHash);
return block.timestamp;
Expand All @@ -44,3 +45,17 @@ export const HOUR = MINUTE * 60;
export const DAY = HOUR * 24;
export const WEEK = DAY * 7;
export const MONTH = DAY * 30;

export const timestampToString = (timestamp: number): string => {
if (timestamp >= SECOND && timestamp < MINUTE) {
return `${timestamp} ${timestamp > SECOND ? 'seconds' : 'second'}`;
} else if (timestamp >= MINUTE && timestamp < HOUR) {
return `${timestamp / MINUTE} ${timestamp > MINUTE ? 'minutes' : 'minute'}`;
} else if (timestamp >= HOUR && timestamp < DAY) {
return `${timestamp / HOUR} ${timestamp > HOUR ? 'hours' : 'hour'}`;
} else if (timestamp >= DAY && timestamp < MONTH) {
return `${timestamp / DAY} ${timestamp > DAY ? 'days' : 'day'}`;
} else {
return `${timestamp / MONTH} ${timestamp > MONTH ? 'months' : 'month'}`;
}
};
Loading

0 comments on commit c1590bd

Please sign in to comment.