From d5709f8dc0201216d41a22e5a0dcec310f36ac86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Migone?= Date: Tue, 26 Jul 2022 11:17:01 +0200 Subject: [PATCH 1/5] feat: add account management methods to GRE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Migone --- .env.example | 1 + .solcover.js | 2 +- cli/defaults.ts | 2 +- config/graph.goerli.yml | 16 +++++++++ config/graph.localhost.yml | 12 +++---- e2e/deployment/graphToken.test.ts | 17 +++------ e2e/scenarios/lib/staking.ts | 13 +++++++ hardhat.config.ts | 9 +++-- tasks/deployment/accounts.ts | 10 +++--- tasks/deployment/ownership.ts | 12 +++---- tasks/deployment/unpause.ts | 6 ++-- tasks/gre.ts | 57 +++++++++++++++++++++++++++++-- tasks/type-extensions.d.ts | 20 ++++++++++- 13 files changed, 134 insertions(+), 43 deletions(-) create mode 100644 e2e/scenarios/lib/staking.ts diff --git a/.env.example b/.env.example index ae575474d..e4ff1626f 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,4 @@ +DEFAULT_TEST_MNEMONIC=myth like bonus scare over problem client lizard pioneer submit female collect MNEMONIC= ETHERSCAN_API_KEY= INFURA_KEY= diff --git a/.solcover.js b/.solcover.js index 747f078e5..0eb9b6c9e 100644 --- a/.solcover.js +++ b/.solcover.js @@ -2,7 +2,7 @@ const skipFiles = ['bancor', 'ens', 'erc1056'] module.exports = { providerOptions: { - mnemonic: 'myth like bonus scare over problem client lizard pioneer submit female collect', + mnemonic: process.env.DEFAULT_TEST_MNEMONIC, network_id: 1337, }, skipFiles, diff --git a/cli/defaults.ts b/cli/defaults.ts index 5c0a1dd6a..40496479a 100644 --- a/cli/defaults.ts +++ b/cli/defaults.ts @@ -2,7 +2,7 @@ import { Options } from 'yargs' import { Overrides } from 'ethers' export const local = { - mnemonic: 'myth like bonus scare over problem client lizard pioneer submit female collect', + mnemonic: process.env.DEFAULT_TEST_MNEMONIC, providerUrl: 'http://localhost:8545', addressBookPath: './addresses.json', graphConfigPath: './config/graph.mainnet.yml', diff --git a/config/graph.goerli.yml b/config/graph.goerli.yml index 1d8261b67..fe9189bf0 100644 --- a/config/graph.goerli.yml +++ b/config/graph.goerli.yml @@ -30,6 +30,14 @@ contracts: - fn: "setContractProxy" id: "0x45fc200c7e4544e457d3c5709bfe0d520442c30bbcbdaede89e8d4a4bbc19247" # keccak256('GraphToken') contractAddress: "${{GraphToken.address}}" + - fn: "setPauseGuardian" + pauseGuardian: *pauseGuardian + - fn: "transferOwnership" + owner: *governor + GraphProxyAdmin: + calls: + - fn: "transferOwnership" + owner: *governor ServiceRegistry: proxy: true init: @@ -45,6 +53,9 @@ contracts: calls: - fn: "addMinter" minter: "${{RewardsManager.address}}" + - fn: "renounceMinter" + - fn: "transferOwnership" + owner: *governor Curation: proxy: true init: @@ -79,6 +90,8 @@ contracts: tokenDescriptor: "${{SubgraphNFTDescriptor.address}}" - fn: "setMinter" minter: "${{GNS.address}}" + - fn: "transferOwnership" + owner: *governor Staking: proxy: true init: @@ -107,6 +120,9 @@ contracts: init: controller: "${{Controller.address}}" issuanceRate: "1000000012184945188" # per block increase of total supply, blocks in a year = 365*60*60*24/13 + calls: + - fn: "setSubgraphAvailabilityOracle" + subgraphAvailabilityOracle: *availabilityOracle AllocationExchange: init: graphToken: "${{GraphToken.address}}" diff --git a/config/graph.localhost.yml b/config/graph.localhost.yml index 03f83682d..a1d3440bf 100644 --- a/config/graph.localhost.yml +++ b/config/graph.localhost.yml @@ -1,10 +1,10 @@ general: - arbitrator: &arbitrator "0xFFcf8FDEE72ac11b5c542428B35EEF5769C409f0" # Arbitration Council - governor: &governor "0x22d491Bde2303f2f43325b2108D26f1eAbA1e32b" # Governor Council - authority: &authority "0xE11BA2b4D45Eaed5996Cd0823791E0C93114882d" # Authority that signs payment vouchers - availabilityOracle: &availabilityOracle "0xd03ea8624C8C5987235048901fB614fDcA89b117" # Subgraph Availability Oracle - pauseGuardian: &pauseGuardian "0x95cED938F7991cd0dFcb48F0a06a40FA1aF46EBC" # Protocol pause guardian - allocationExchangeOwner: &allocationExchangeOwner "0x3E5e9111Ae8eB78Fe1CC3bb8915d5D461F3Ef9A9" # Allocation Exchange owner + arbitrator: &arbitrator "0x3fD652C93dFA333979ad762Cf581Df89BaBa6795" # Arbitration Council + governor: &governor "0x325A621DeA613BCFb5B1A69a7aCED0ea4AfBD73A" # Governor Council + authority: &authority "0xF0D5BC18421fa04D0a2A2ef540ba5A9f04014BE3" # Authority that signs payment vouchers + availabilityOracle: &availabilityOracle "0x66FC63C2572bF3ADD0Fe5d44b97c2E614E35e9a3" # Subgraph Availability Oracle + pauseGuardian: &pauseGuardian "0xf408f04F9b7691f7174FA2bb73ad6d45fD5d3CBe" # Protocol pause guardian + allocationExchangeOwner: &allocationExchangeOwner "0x2F560290FEF1B3Ada194b6aA9c40aa71f8e95598" # Allocation Exchange owner contracts: Controller: diff --git a/e2e/deployment/graphToken.test.ts b/e2e/deployment/graphToken.test.ts index df089f3dc..fbee3bed5 100644 --- a/e2e/deployment/graphToken.test.ts +++ b/e2e/deployment/graphToken.test.ts @@ -1,4 +1,3 @@ -import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' import { expect } from 'chai' import hre from 'hardhat' import { getItemValue } from '../../cli/config' @@ -7,14 +6,9 @@ describe('GraphToken deployment', () => { const { graphConfig, contracts: { GraphToken, RewardsManager }, + getDeployer, } = hre.graph() - let deployer: SignerWithAddress - - before(async () => { - ;[deployer] = await hre.ethers.getSigners() - }) - it('should be owned by governor', async function () { const owner = await GraphToken.governor() const governorAddress = getItemValue(graphConfig, 'general/governor') @@ -22,8 +16,9 @@ describe('GraphToken deployment', () => { }) it('deployer should not be minter', async function () { + const deployer = await getDeployer() const deployerIsMinter = await GraphToken.isMinter(deployer.address) - expect(deployerIsMinter).eq(false) + hre.network.config.chainId === 1337 ? this.skip() : expect(deployerIsMinter).eq(false) }) it('RewardsManager should be minter', async function () { @@ -34,10 +29,6 @@ describe('GraphToken deployment', () => { it('total supply should match "initialSupply" on the config file', async function () { const value = await GraphToken.totalSupply() const expected = getItemValue(graphConfig, 'contracts/GraphToken/init/initialSupply') - if (hre.network.config.chainId === 1337) { - expect(value).eq(expected) - } else { - expect(value).gte(expected) - } + hre.network.config.chainId === 1337 ? expect(value).eq(expected) : expect(value).gte(expected) }) }) diff --git a/e2e/scenarios/lib/staking.ts b/e2e/scenarios/lib/staking.ts new file mode 100644 index 000000000..6fab0e5cb --- /dev/null +++ b/e2e/scenarios/lib/staking.ts @@ -0,0 +1,13 @@ +import hre from 'hardhat' +import { Staking } from '../../../build/types/Staking' + +export const stake = async (amountWei: string): Promise => { + const graph = hre.graph() + + // Approve + const stakeAmountWei = hre.ethers.utils.parseEther(amountWei).toString() + await graph.contracts.GraphToken.approve(graph.contracts.Staking.address, stakeAmountWei) + + // Stake + await graph.contracts.Staking.stake(stakeAmountWei) +} diff --git a/hardhat.config.ts b/hardhat.config.ts index 5ce3b085d..a51f2fc17 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -86,9 +86,6 @@ function setupNetworkProviders(hardhatConfig) { // Config -const DEFAULT_TEST_MNEMONIC = - 'myth like bonus scare over problem client lizard pioneer submit female collect' - const config: HardhatUserConfig = { paths: { sources: './contracts', @@ -126,7 +123,7 @@ const config: HardhatUserConfig = { initialBaseFeePerGas: 0, blockGasLimit: 12000000, accounts: { - mnemonic: DEFAULT_TEST_MNEMONIC, + mnemonic: process.env.DEFAULT_TEST_MNEMONIC, }, mining: { auto: false, @@ -136,7 +133,9 @@ const config: HardhatUserConfig = { }, localhost: { accounts: - process.env.FORK === 'true' ? getAccountsKeys() : { mnemonic: DEFAULT_TEST_MNEMONIC }, + process.env.FORK === 'true' + ? getAccountsKeys() + : { mnemonic: process.env.DEFAULT_TEST_MNEMONIC }, }, }, etherscan: { diff --git a/tasks/deployment/accounts.ts b/tasks/deployment/accounts.ts index 6562104de..1ab2bd9c7 100644 --- a/tasks/deployment/accounts.ts +++ b/tasks/deployment/accounts.ts @@ -10,19 +10,21 @@ task('migrate:accounts', '[localhost] Creates protocol accounts and saves them i throw new Error('This task can only be run on localhost network') } - const { graphConfig } = hre.graph({ graphConfig: taskArgs.graphConfig }) + const { graphConfig, getNamedAccounts, getDeployer } = hre.graph({ + graphConfig: taskArgs.graphConfig, + }) console.log('> Generating addresses') - const [ - deployer, + const deployer = await getDeployer() + const { arbitrator, governor, authority, availabilityOracle, pauseGuardian, allocationExchangeOwner, - ] = await hre.ethers.getSigners() + } = await getNamedAccounts() console.log(`- Deployer: ${deployer.address}`) console.log(`- Arbitrator: ${arbitrator.address}`) diff --git a/tasks/deployment/ownership.ts b/tasks/deployment/ownership.ts index 473ae8cc7..e983528e3 100644 --- a/tasks/deployment/ownership.ts +++ b/tasks/deployment/ownership.ts @@ -12,17 +12,17 @@ task( throw new Error('This task can only be run on localhost network') } - const { contracts } = hre.graph({ addressBook: taskArgs.addressBook }) - const [, , governor] = await hre.ethers.getSigners() + const { contracts, getNamedAccounts } = hre.graph({ addressBook: taskArgs.addressBook }) + const { governor } = await getNamedAccounts() console.log('> Accepting ownership of contracts') console.log(`- Governor: ${governor.address}`) const txs: ContractTransaction[] = [] - txs.push(await contracts.GraphToken.connect(governor).acceptOwnership()) - txs.push(await contracts.Controller.connect(governor).acceptOwnership()) - txs.push(await contracts.GraphProxyAdmin.connect(governor).acceptOwnership()) - txs.push(await contracts.SubgraphNFT.connect(governor).acceptOwnership()) + txs.push(await contracts.GraphToken.connect(governor.signer).acceptOwnership()) + txs.push(await contracts.Controller.connect(governor.signer).acceptOwnership()) + txs.push(await contracts.GraphProxyAdmin.connect(governor.signer).acceptOwnership()) + txs.push(await contracts.SubgraphNFT.connect(governor.signer).acceptOwnership()) await Promise.all(txs.map((tx) => tx.wait())) console.log('Done!') diff --git a/tasks/deployment/unpause.ts b/tasks/deployment/unpause.ts index 6a9fceecd..2ffa34e3f 100644 --- a/tasks/deployment/unpause.ts +++ b/tasks/deployment/unpause.ts @@ -4,11 +4,11 @@ import { cliOpts } from '../../cli/defaults' task('migrate:unpause', 'Unpause protocol') .addParam('addressBook', cliOpts.addressBook.description, cliOpts.addressBook.default) .setAction(async (taskArgs, hre) => { - const { contracts } = hre.graph({ addressBook: taskArgs.addressBook }) - const [, , governor] = await hre.ethers.getSigners() + const { contracts, getNamedAccounts } = hre.graph({ addressBook: taskArgs.addressBook }) + const { governor } = await getNamedAccounts() console.log('> Unpausing protocol') - const tx = await contracts.Controller.connect(governor).setPaused(false) + const tx = await contracts.Controller.connect(governor.signer).setPaused(false) await tx.wait() console.log('Done!') }) diff --git a/tasks/gre.ts b/tasks/gre.ts index baced85d9..9e99a2a02 100644 --- a/tasks/gre.ts +++ b/tasks/gre.ts @@ -1,12 +1,13 @@ import { HardhatRuntimeEnvironment } from 'hardhat/types' import { extendEnvironment } from 'hardhat/config' -import { lazyObject } from 'hardhat/plugins' +import { lazyFunction, lazyObject } from 'hardhat/plugins' import { getAddressBook } from '../cli/address-book' import { loadContracts } from '../cli/contracts' -import { readConfig } from '../cli/config' -import { GREOptions } from './type-extensions' +import { getItemValue, readConfig } from '../cli/config' +import { Account, GREOptions, NamedAccounts } from './type-extensions' import fs from 'fs' +import { Signer, VoidSigner } from 'ethers' // Graph Runtime Environment (GRE) extensions for the HRE extendEnvironment((hre: HardhatRuntimeEnvironment) => { @@ -23,12 +24,62 @@ extendEnvironment((hre: HardhatRuntimeEnvironment) => { throw new Error(`Graph config not found: ${graphConfigPath}`) } + const getAccounts = async (): Promise => { + const accounts = [] + const signers: Signer[] = await hre.ethers.getSigners() + + for (const signer of signers) { + accounts.push({ signer, address: await signer.getAddress() }) + } + return accounts + } + + const getNamedAccounts = async (): Promise => { + const names = [ + 'arbitrator', + 'governor', + 'authority', + 'availabilityOracle', + 'pauseGuardian', + 'allocationExchangeOwner', + ] + + const testAccounts = await getTestAccounts() + const namedAccounts = names.reduce((acc, name, i) => { + acc[name] = chainId === '1337' ? testAccounts[i] : getNamedAccount(name) + return acc + }, {} as NamedAccounts) + + return namedAccounts + } + + const getNamedAccount = (name: string): Account => { + const signer = new VoidSigner( + getItemValue(readConfig(graphConfigPath, true), `general/${name}`), + ) + return { signer, address: signer.address } + } + + // Get accounts from the tail end of the signers list + // This is to prevent named accounts them from collisioning with test accounts + const getTestAccounts = async (): Promise => { + return (await hre.ethers.getSigners()).reverse().map((s) => ({ + signer: s, + address: s.address, + })) + } + return { addressBook: lazyObject(() => getAddressBook(addressBookPath, chainId)), graphConfig: lazyObject(() => readConfig(graphConfigPath, true)), contracts: lazyObject(() => loadContracts(getAddressBook(addressBookPath, chainId), hre.ethers.provider), ), + getNamedAccounts: lazyFunction(() => getNamedAccounts), + getAccounts: lazyFunction(() => getAccounts), + getDeployer: lazyFunction(() => async () => { + return (await getAccounts())[0] + }), } } }) diff --git a/tasks/type-extensions.d.ts b/tasks/type-extensions.d.ts index d1d4a848b..7182fb956 100644 --- a/tasks/type-extensions.d.ts +++ b/tasks/type-extensions.d.ts @@ -1,17 +1,35 @@ +import { Signer } from 'ethers' import { AddressBook } from '../cli/address-book' import { NetworkContracts } from '../cli/contracts' -interface GREOptions { +export interface GREOptions { addressBook?: string graphConfig?: string } +export interface Account { + readonly signer: Signer + readonly address: string +} + +export interface NamedAccounts { + arbitrator: Account + governor: Account + authority: Account + availabilityOracle: Account + pauseGuardian: Account + allocationExchangeOwner: Account +} + declare module 'hardhat/types/runtime' { export interface HardhatRuntimeEnvironment { graph: (opts?: GREOptions) => { contracts: NetworkContracts graphConfig: any addressBook: AddressBook + getNamedAccounts: () => Promise + getAccounts: () => Promise + getDeployer: () => Promise } } } From 5604c868507bb82be5e03e845ad888384d240eab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Migone?= Date: Tue, 26 Jul 2022 14:36:57 +0200 Subject: [PATCH 2/5] feat: split e2e tests into config and init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Migone --- .env.example | 1 - .solcover.js | 2 +- README.md | 36 +++++++++++--- cli/defaults.ts | 2 +- .../{ => config}/allocationExchange.test.ts | 11 ++--- .../{ => config}/controller.test.ts | 4 +- e2e/deployment/{ => config}/curation.test.ts | 4 +- .../{ => config}/disputeManager.test.ts | 4 +- .../{ => config}/epochManager.test.ts | 4 +- e2e/deployment/{ => config}/gns.test.ts | 9 +--- .../{ => config}/graphProxyAdmin.test.ts | 4 +- .../{ => config}/graphToken.test.ts | 10 +--- .../{protocol.ts => config/protocol.test.ts} | 2 +- .../{ => config}/rewardsManager.test.ts | 4 +- .../{ => config}/serviceRegistry.test..ts | 2 +- e2e/deployment/{ => config}/staking.test.ts | 4 +- .../{ => config}/subgraphNFT.test.ts | 4 +- .../init/allocationExchange.test.ts | 13 +++++ e2e/deployment/init/gns.test.ts | 13 +++++ e2e/deployment/init/graphToken.test.ts | 16 +++++++ hardhat.config.ts | 11 +++-- package.json | 2 + scripts/e2e | 2 +- tasks/e2e/e2e.ts | 48 +++++++++++++++++++ yarn.lock | 15 +++++- 25 files changed, 169 insertions(+), 58 deletions(-) rename e2e/deployment/{ => config}/allocationExchange.test.ts (65%) rename e2e/deployment/{ => config}/controller.test.ts (93%) rename e2e/deployment/{ => config}/curation.test.ts (94%) rename e2e/deployment/{ => config}/disputeManager.test.ts (94%) rename e2e/deployment/{ => config}/epochManager.test.ts (85%) rename e2e/deployment/{ => config}/gns.test.ts (63%) rename e2e/deployment/{ => config}/graphProxyAdmin.test.ts (78%) rename e2e/deployment/{ => config}/graphToken.test.ts (66%) rename e2e/deployment/{protocol.ts => config/protocol.test.ts} (84%) rename e2e/deployment/{ => config}/rewardsManager.test.ts (90%) rename e2e/deployment/{ => config}/serviceRegistry.test..ts (86%) rename e2e/deployment/{ => config}/staking.test.ts (97%) rename e2e/deployment/{ => config}/subgraphNFT.test.ts (88%) create mode 100644 e2e/deployment/init/allocationExchange.test.ts create mode 100644 e2e/deployment/init/gns.test.ts create mode 100644 e2e/deployment/init/graphToken.test.ts create mode 100644 tasks/e2e/e2e.ts diff --git a/.env.example b/.env.example index e4ff1626f..ae575474d 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,3 @@ -DEFAULT_TEST_MNEMONIC=myth like bonus scare over problem client lizard pioneer submit female collect MNEMONIC= ETHERSCAN_API_KEY= INFURA_KEY= diff --git a/.solcover.js b/.solcover.js index 0eb9b6c9e..747f078e5 100644 --- a/.solcover.js +++ b/.solcover.js @@ -2,7 +2,7 @@ const skipFiles = ['bancor', 'ens', 'erc1056'] module.exports = { providerOptions: { - mnemonic: process.env.DEFAULT_TEST_MNEMONIC, + mnemonic: 'myth like bonus scare over problem client lizard pioneer submit female collect', network_id: 1337, }, skipFiles, diff --git a/README.md b/README.md index 64110ce9a..18c5f7be0 100644 --- a/README.md +++ b/README.md @@ -90,34 +90,58 @@ To test a single file run: `npx hardhat test test/.ts` ## E2E Testing -End to end tests are also available and can be run against a local network or a live network. These can be useful to validate a protocol deployment is configured and working as expected. +End to end tests are also available and can be run against a local network or a live network. These can be useful to validate a protocol deployment is configured and working as expected. + +There are several types of e2e tests which can be run separately: +- **deployment/config** + - Test the configuration of deployed contracts (parameters that don't change over time). + - Can be run against any network at any time and the tests should pass. + - Only read only interactions with the blockchain. + - Example: a test validating the curation default reserve ratio matches the value in the graph config file. +- **deployment/init** + - Test the initialization of deployed contracts (parameters that change with protocol usage). + - Can be run against a "fresh" protocol deployment. Running these tests against a protocol with pre-existing state will probably fail. + - Only read only interactions with the blockchain. + - Example: a test validating that the GRT total supply equals 10B, this is only true on a freshly deployed protocol until the first allocation is closed and protocol issuance kicks in. +- **scenarios** + - Test the execution of common protocol actions. + - Can be run against any network at any time and the tests should pass. + - Read and write interactions with the blockchain. _Requires an account with sufficient balance!_ + - Example: a test validating that a user can add signal to a subgraph. ### Hardhat local node -To run e2e tests against a hardhat local node run: +To run all e2e tests against a hardhat local node run: ```bash yarn test:e2e ``` -The command will invoke several hardhat tasks, including: +The command will perform the following actions: - Start a hardhat node (localhost) - Run `migrate:accounts` hardhat task to create keys for all protocol roles (deployer, governor, arbiter, etc). This currently doesn't support multisig accounts. - Run `migrate` hardhat task to deploy the protocol - Run `migrate:ownership` hardhat task to transfer ownership of governed contracts to the governor - Run `migrate:unpause` to unpause the protocol -- Run e2e tests +- Run `e2e` hardhat task to run all e2e tests ### Other networks To run tests against a live testnet or even mainnet run: ```bash -GRAPH_CONFIG=config/graph..yml ADDRESS_BOOK=addresses.json npx hardhat test e2e/**/*.ts --network +# All e2e tests +npx hardhat e2e --network --graph-config config/graph..yml + +# Only deployment config tests +npx hardhat e2e:config --network --graph-config config/graph..yml + +# Only deployment init tests +npx hardhat e2e:init --network --graph-config config/graph..yml ``` -This command will only run the tests so you need to be sure the protocol is already deployed and the graph config file and address book files are up to date. +Note that this command will only run the tests so you need to be sure the protocol is already deployed and the graph config file and address book files are up to date. # Interacting with the contracts diff --git a/cli/defaults.ts b/cli/defaults.ts index 40496479a..5c0a1dd6a 100644 --- a/cli/defaults.ts +++ b/cli/defaults.ts @@ -2,7 +2,7 @@ import { Options } from 'yargs' import { Overrides } from 'ethers' export const local = { - mnemonic: process.env.DEFAULT_TEST_MNEMONIC, + mnemonic: 'myth like bonus scare over problem client lizard pioneer submit female collect', providerUrl: 'http://localhost:8545', addressBookPath: './addresses.json', graphConfigPath: './config/graph.mainnet.yml', diff --git a/e2e/deployment/allocationExchange.test.ts b/e2e/deployment/config/allocationExchange.test.ts similarity index 65% rename from e2e/deployment/allocationExchange.test.ts rename to e2e/deployment/config/allocationExchange.test.ts index d242e96cd..a8ad948f4 100644 --- a/e2e/deployment/allocationExchange.test.ts +++ b/e2e/deployment/config/allocationExchange.test.ts @@ -1,11 +1,11 @@ import { expect } from 'chai' import hre from 'hardhat' -import { getItemValue } from '../../cli/config' +import { getItemValue } from '../../../cli/config' -describe('AllocationExchange deployment', () => { +describe('AllocationExchange configuration', () => { const { graphConfig, - contracts: { AllocationExchange, GraphToken, Staking }, + contracts: { AllocationExchange }, } = hre.graph() it('should be owned by allocationExchangeOwner', async function () { @@ -23,9 +23,4 @@ describe('AllocationExchange deployment', () => { // graphToken and staking are private variables so we can't verify it.skip('graphToken should match the GraphToken deployment address') it.skip('staking should match the Staking deployment address') - - it('should allow Staking contract to spend MAX_UINT256 tokens on AllocationExchange behalf', async function () { - const allowance = await GraphToken.allowance(AllocationExchange.address, Staking.address) - expect(allowance).eq(hre.ethers.constants.MaxUint256) - }) }) diff --git a/e2e/deployment/controller.test.ts b/e2e/deployment/config/controller.test.ts similarity index 93% rename from e2e/deployment/controller.test.ts rename to e2e/deployment/config/controller.test.ts index 269521e55..07313cfc0 100644 --- a/e2e/deployment/controller.test.ts +++ b/e2e/deployment/config/controller.test.ts @@ -1,8 +1,8 @@ import { expect } from 'chai' import hre, { ethers } from 'hardhat' -import { getItemValue } from '../../cli/config' +import { getItemValue } from '../../../cli/config' -describe('Controller deployment', () => { +describe('Controller configuration', () => { const { contracts, graphConfig } = hre.graph() const { Controller } = contracts diff --git a/e2e/deployment/curation.test.ts b/e2e/deployment/config/curation.test.ts similarity index 94% rename from e2e/deployment/curation.test.ts rename to e2e/deployment/config/curation.test.ts index 64d1b9d8a..6d6a4d1ea 100644 --- a/e2e/deployment/curation.test.ts +++ b/e2e/deployment/config/curation.test.ts @@ -1,8 +1,8 @@ import { expect } from 'chai' import hre from 'hardhat' -import { getItemValue } from '../../cli/config' +import { getItemValue } from '../../../cli/config' -describe('Curation deployment', () => { +describe('Curation configuration', () => { const { graphConfig, contracts: { Controller, Curation, BancorFormula, GraphCurationToken }, diff --git a/e2e/deployment/disputeManager.test.ts b/e2e/deployment/config/disputeManager.test.ts similarity index 94% rename from e2e/deployment/disputeManager.test.ts rename to e2e/deployment/config/disputeManager.test.ts index 247710901..00ceaf176 100644 --- a/e2e/deployment/disputeManager.test.ts +++ b/e2e/deployment/config/disputeManager.test.ts @@ -1,8 +1,8 @@ import { expect } from 'chai' import hre from 'hardhat' -import { getItemValue } from '../../cli/config' +import { getItemValue } from '../../../cli/config' -describe('DisputeManager deployment', () => { +describe('DisputeManager configuration', () => { const { graphConfig, contracts: { Controller, DisputeManager }, diff --git a/e2e/deployment/epochManager.test.ts b/e2e/deployment/config/epochManager.test.ts similarity index 85% rename from e2e/deployment/epochManager.test.ts rename to e2e/deployment/config/epochManager.test.ts index ad09a7857..3f80321ec 100644 --- a/e2e/deployment/epochManager.test.ts +++ b/e2e/deployment/config/epochManager.test.ts @@ -1,8 +1,8 @@ import { expect } from 'chai' import hre from 'hardhat' -import { getItemValue } from '../../cli/config' +import { getItemValue } from '../../../cli/config' -describe('EpochManager deployment', () => { +describe('EpochManager configuration', () => { const { graphConfig, contracts: { EpochManager, Controller }, diff --git a/e2e/deployment/gns.test.ts b/e2e/deployment/config/gns.test.ts similarity index 63% rename from e2e/deployment/gns.test.ts rename to e2e/deployment/config/gns.test.ts index 6c0b17d54..4337dffd0 100644 --- a/e2e/deployment/gns.test.ts +++ b/e2e/deployment/config/gns.test.ts @@ -1,9 +1,9 @@ import { expect } from 'chai' import hre from 'hardhat' -describe('GNS deployment', () => { +describe('GNS configuration', () => { const { - contracts: { Controller, GNS, BancorFormula, SubgraphNFT, GraphToken, Curation }, + contracts: { Controller, GNS, BancorFormula, SubgraphNFT }, } = hre.graph() it('should be controlled by Controller', async function () { @@ -20,9 +20,4 @@ describe('GNS deployment', () => { const subgraphNFT = await GNS.subgraphNFT() expect(subgraphNFT).eq(SubgraphNFT.address) }) - - it('should allow Curation contract to spend MAX_UINT256 tokens on GNS behalf', async function () { - const allowance = await GraphToken.allowance(GNS.address, Curation.address) - expect(allowance).eq(hre.ethers.constants.MaxUint256) - }) }) diff --git a/e2e/deployment/graphProxyAdmin.test.ts b/e2e/deployment/config/graphProxyAdmin.test.ts similarity index 78% rename from e2e/deployment/graphProxyAdmin.test.ts rename to e2e/deployment/config/graphProxyAdmin.test.ts index 08869a1f8..fe781ffcc 100644 --- a/e2e/deployment/graphProxyAdmin.test.ts +++ b/e2e/deployment/config/graphProxyAdmin.test.ts @@ -1,8 +1,8 @@ import { expect } from 'chai' import hre from 'hardhat' -import { getItemValue } from '../../cli/config' +import { getItemValue } from '../../../cli/config' -describe('GraphProxyAdmin deployment', () => { +describe('GraphProxyAdmin configuration', () => { const { contracts: { GraphProxyAdmin }, graphConfig, diff --git a/e2e/deployment/graphToken.test.ts b/e2e/deployment/config/graphToken.test.ts similarity index 66% rename from e2e/deployment/graphToken.test.ts rename to e2e/deployment/config/graphToken.test.ts index fbee3bed5..1b402a987 100644 --- a/e2e/deployment/graphToken.test.ts +++ b/e2e/deployment/config/graphToken.test.ts @@ -1,8 +1,8 @@ import { expect } from 'chai' import hre from 'hardhat' -import { getItemValue } from '../../cli/config' +import { getItemValue } from '../../../cli/config' -describe('GraphToken deployment', () => { +describe('GraphToken configuration', () => { const { graphConfig, contracts: { GraphToken, RewardsManager }, @@ -25,10 +25,4 @@ describe('GraphToken deployment', () => { const deployerIsMinter = await GraphToken.isMinter(RewardsManager.address) expect(deployerIsMinter).eq(true) }) - - it('total supply should match "initialSupply" on the config file', async function () { - const value = await GraphToken.totalSupply() - const expected = getItemValue(graphConfig, 'contracts/GraphToken/init/initialSupply') - hre.network.config.chainId === 1337 ? expect(value).eq(expected) : expect(value).gte(expected) - }) }) diff --git a/e2e/deployment/protocol.ts b/e2e/deployment/config/protocol.test.ts similarity index 84% rename from e2e/deployment/protocol.ts rename to e2e/deployment/config/protocol.test.ts index 6391df8d3..4e12f5088 100644 --- a/e2e/deployment/protocol.ts +++ b/e2e/deployment/config/protocol.test.ts @@ -1,7 +1,7 @@ import { expect } from 'chai' import hre from 'hardhat' -describe('Protocol', () => { +describe('Protocol configuration', () => { const { contracts } = hre.graph() it('should be unpaused', async function () { diff --git a/e2e/deployment/rewardsManager.test.ts b/e2e/deployment/config/rewardsManager.test.ts similarity index 90% rename from e2e/deployment/rewardsManager.test.ts rename to e2e/deployment/config/rewardsManager.test.ts index bec6bee05..e2eefb94e 100644 --- a/e2e/deployment/rewardsManager.test.ts +++ b/e2e/deployment/config/rewardsManager.test.ts @@ -1,8 +1,8 @@ import { expect } from 'chai' import hre from 'hardhat' -import { getItemValue } from '../../cli/config' +import { getItemValue } from '../../../cli/config' -describe('RewardsManager deployment', () => { +describe('RewardsManager configuration', () => { const { graphConfig, contracts: { RewardsManager, Controller }, diff --git a/e2e/deployment/serviceRegistry.test..ts b/e2e/deployment/config/serviceRegistry.test..ts similarity index 86% rename from e2e/deployment/serviceRegistry.test..ts rename to e2e/deployment/config/serviceRegistry.test..ts index c747b2188..c7e953ce9 100644 --- a/e2e/deployment/serviceRegistry.test..ts +++ b/e2e/deployment/config/serviceRegistry.test..ts @@ -1,7 +1,7 @@ import { expect } from 'chai' import hre from 'hardhat' -describe('ServiceRegistry deployment', () => { +describe('ServiceRegistry configuration', () => { const { contracts: { ServiceRegistry, Controller }, } = hre.graph() diff --git a/e2e/deployment/staking.test.ts b/e2e/deployment/config/staking.test.ts similarity index 97% rename from e2e/deployment/staking.test.ts rename to e2e/deployment/config/staking.test.ts index d6ad9f6fb..e2b1fe5e9 100644 --- a/e2e/deployment/staking.test.ts +++ b/e2e/deployment/config/staking.test.ts @@ -1,8 +1,8 @@ import { expect } from 'chai' import hre from 'hardhat' -import { getItemValue } from '../../cli/config' +import { getItemValue } from '../../../cli/config' -describe('Staking deployment', () => { +describe('Staking configuration', () => { const { graphConfig, contracts: { Staking, Controller, DisputeManager, AllocationExchange }, diff --git a/e2e/deployment/subgraphNFT.test.ts b/e2e/deployment/config/subgraphNFT.test.ts similarity index 88% rename from e2e/deployment/subgraphNFT.test.ts rename to e2e/deployment/config/subgraphNFT.test.ts index d43cd15db..2e34eaa54 100644 --- a/e2e/deployment/subgraphNFT.test.ts +++ b/e2e/deployment/config/subgraphNFT.test.ts @@ -1,8 +1,8 @@ import { expect } from 'chai' import hre from 'hardhat' -import { getItemValue } from '../../cli/config' +import { getItemValue } from '../../../cli/config' -describe('SubgraphNFT deployment', () => { +describe('SubgraphNFT configuration', () => { const { graphConfig, contracts: { SubgraphNFT, GNS, SubgraphNFTDescriptor }, diff --git a/e2e/deployment/init/allocationExchange.test.ts b/e2e/deployment/init/allocationExchange.test.ts new file mode 100644 index 000000000..5a759ae56 --- /dev/null +++ b/e2e/deployment/init/allocationExchange.test.ts @@ -0,0 +1,13 @@ +import { expect } from 'chai' +import hre from 'hardhat' + +describe('AllocationExchange initialization', () => { + const { + contracts: { AllocationExchange, GraphToken, Staking }, + } = hre.graph() + + it('should allow Staking contract to spend MAX_UINT256 tokens on AllocationExchange behalf', async function () { + const allowance = await GraphToken.allowance(AllocationExchange.address, Staking.address) + expect(allowance).eq(hre.ethers.constants.MaxUint256) + }) +}) diff --git a/e2e/deployment/init/gns.test.ts b/e2e/deployment/init/gns.test.ts new file mode 100644 index 000000000..ccf5451d9 --- /dev/null +++ b/e2e/deployment/init/gns.test.ts @@ -0,0 +1,13 @@ +import { expect } from 'chai' +import hre from 'hardhat' + +describe('GNS initialization', () => { + const { + contracts: { GNS, GraphToken, Curation }, + } = hre.graph() + + it('should allow Curation contract to spend MAX_UINT256 tokens on GNS behalf', async function () { + const allowance = await GraphToken.allowance(GNS.address, Curation.address) + expect(allowance).eq(hre.ethers.constants.MaxUint256) + }) +}) diff --git a/e2e/deployment/init/graphToken.test.ts b/e2e/deployment/init/graphToken.test.ts new file mode 100644 index 000000000..8c2230adb --- /dev/null +++ b/e2e/deployment/init/graphToken.test.ts @@ -0,0 +1,16 @@ +import { expect } from 'chai' +import hre from 'hardhat' +import { getItemValue } from '../../../cli/config' + +describe('GraphToken initialization', () => { + const { + graphConfig, + contracts: { GraphToken }, + } = hre.graph() + + it('total supply should match "initialSupply" on the config file', async function () { + const value = await GraphToken.totalSupply() + const expected = getItemValue(graphConfig, 'contracts/GraphToken/init/initialSupply') + hre.network.config.chainId === 1337 ? expect(value).eq(expected) : expect(value).gte(expected) + }) +}) diff --git a/hardhat.config.ts b/hardhat.config.ts index a51f2fc17..b2acd6fce 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -28,7 +28,7 @@ const SKIP_LOAD = process.env.SKIP_LOAD === 'true' function loadTasks() { require('./tasks/gre.ts') - ;['contracts', 'misc', 'deployment', 'actions', 'verify'].forEach((folder) => { + ;['contracts', 'misc', 'deployment', 'actions', 'verify', 'e2e'].forEach((folder) => { const tasksPath = path.join(__dirname, 'tasks', folder) fs.readdirSync(tasksPath) .filter((pth) => pth.includes('.ts')) @@ -86,6 +86,9 @@ function setupNetworkProviders(hardhatConfig) { // Config +const DEFAULT_TEST_MNEMONIC = + 'myth like bonus scare over problem client lizard pioneer submit female collect' + const config: HardhatUserConfig = { paths: { sources: './contracts', @@ -123,7 +126,7 @@ const config: HardhatUserConfig = { initialBaseFeePerGas: 0, blockGasLimit: 12000000, accounts: { - mnemonic: process.env.DEFAULT_TEST_MNEMONIC, + mnemonic: DEFAULT_TEST_MNEMONIC, }, mining: { auto: false, @@ -133,9 +136,7 @@ const config: HardhatUserConfig = { }, localhost: { accounts: - process.env.FORK === 'true' - ? getAccountsKeys() - : { mnemonic: process.env.DEFAULT_TEST_MNEMONIC }, + process.env.FORK === 'true' ? getAccountsKeys() : { mnemonic: DEFAULT_TEST_MNEMONIC }, }, }, etherscan: { diff --git a/package.json b/package.json index 914d4173b..aa8055506 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "@typechain/hardhat": "^2.0.0", "@types/bs58": "^4.0.1", "@types/dotenv": "^8.2.0", + "@types/glob": "^7.2.0", "@types/inquirer": "^7.3.1", "@types/minimist": "^1.2.1", "@types/mocha": "^8.2.2", @@ -49,6 +50,7 @@ "eslint-plugin-prettier": "^3.4.0", "ethereum-waffle": "^3.3.0", "form-data": "^4.0.0", + "glob": "^8.0.3", "graphql-tag": "^2.12.4", "hardhat": "^2.9.5", "hardhat-abi-exporter": "^2.2.0", diff --git a/scripts/e2e b/scripts/e2e index 7b90d77dd..0267bfc6b 100755 --- a/scripts/e2e +++ b/scripts/e2e @@ -24,7 +24,7 @@ npx hardhat migrate:unpause --network localhost ### Test # Run tests using the localhost evm instance and the localhost graph config -GRAPH_CONFIG='config/graph.localhost.yml' npx hardhat test e2e/**/*.ts --network localhost +npx hardhat e2e --network localhost --graph-config config/graph.localhost.yml ### Cleanup diff --git a/tasks/e2e/e2e.ts b/tasks/e2e/e2e.ts new file mode 100644 index 000000000..117f5ea50 --- /dev/null +++ b/tasks/e2e/e2e.ts @@ -0,0 +1,48 @@ +import { task } from 'hardhat/config' +import { HardhatRuntimeEnvironment, TaskArguments } from 'hardhat/types' +import { TASK_TEST } from 'hardhat/builtin-tasks/task-names' +import glob from 'glob' +import { cliOpts } from '../../cli/defaults' + +const CONFIG_TESTS = 'e2e/deployment/config/*.test.ts' +const INIT_TESTS = 'e2e/deployment/init/*.test.ts' + +// Built-in test task doesn't support our arguments +// we can pass them to GRE via env vars +const setGraphEnvVars = async (args: TaskArguments) => { + process.env.GRAPH_CONFIG = args.graphConfig + process.env.ADDRESS_BOOK = args.addressBook +} + +task('e2e', 'Run all e2e tests') + .addParam('graphConfig', cliOpts.graphConfig.description, cliOpts.graphConfig.default) + .addParam('addressBook', cliOpts.addressBook.description, cliOpts.addressBook.default) + .setAction(async (args, hre: HardhatRuntimeEnvironment) => { + const files = [...new glob.GlobSync(CONFIG_TESTS).found, ...new glob.GlobSync(INIT_TESTS).found] + setGraphEnvVars(args) + await hre.run(TASK_TEST, { + testFiles: files, + }) + }) + +task('e2e:config', 'Run deployment configuration e2e tests') + .addParam('graphConfig', cliOpts.graphConfig.description, cliOpts.graphConfig.default) + .addParam('addressBook', cliOpts.addressBook.description, cliOpts.addressBook.default) + .setAction(async (args, hre: HardhatRuntimeEnvironment) => { + const files = new glob.GlobSync(CONFIG_TESTS).found + setGraphEnvVars(args) + await hre.run(TASK_TEST, { + testFiles: files, + }) + }) + +task('e2e:init', 'Run deployment initialization e2e tests') + .addParam('graphConfig', cliOpts.graphConfig.description, cliOpts.graphConfig.default) + .addParam('addressBook', cliOpts.addressBook.description, cliOpts.addressBook.default) + .setAction(async (args, hre: HardhatRuntimeEnvironment) => { + const files = new glob.GlobSync(INIT_TESTS).found + setGraphEnvVars(args) + await hre.run(TASK_TEST, { + testFiles: files, + }) + }) diff --git a/yarn.lock b/yarn.lock index 798643bbe..6201843bb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1510,7 +1510,7 @@ dependencies: "@types/node" "*" -"@types/glob@^7.1.1": +"@types/glob@^7.1.1", "@types/glob@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA== @@ -6123,6 +6123,17 @@ glob@^7.0.0, glob@^7.1.2, glob@^7.1.3, glob@^7.1.6, glob@~7.2.0: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^8.0.3: + version "8.0.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-8.0.3.tgz#415c6eb2deed9e502c68fa44a272e6da6eeca42e" + integrity sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^5.0.1" + once "^1.3.0" + global-dirs@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" @@ -8421,7 +8432,7 @@ minimalistic-crypto-utils@^1.0.1: resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== -minimatch@*: +minimatch@*, minimatch@^5.0.1: version "5.1.0" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.0.tgz#1717b464f4971b144f6aabe8f2d0b8e4511e09c7" integrity sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg== From 7085287c16563c732bd625092e588696b40b0620 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Migone?= Date: Tue, 26 Jul 2022 15:06:50 +0200 Subject: [PATCH 3/5] fix: use GRE account methods in e2e tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Migone --- e2e/deployment/config/allocationExchange.test.ts | 16 ++++++++++------ e2e/deployment/config/controller.test.ts | 16 ++++++++++------ e2e/deployment/config/graphProxyAdmin.test.ts | 13 +++++++++---- e2e/deployment/config/graphToken.test.ts | 13 +++++++++---- e2e/deployment/config/rewardsManager.test.ts | 11 +++++++++-- e2e/deployment/config/subgraphNFT.test.ts | 13 +++++++++---- 6 files changed, 56 insertions(+), 26 deletions(-) diff --git a/e2e/deployment/config/allocationExchange.test.ts b/e2e/deployment/config/allocationExchange.test.ts index a8ad948f4..ee023ce58 100644 --- a/e2e/deployment/config/allocationExchange.test.ts +++ b/e2e/deployment/config/allocationExchange.test.ts @@ -1,22 +1,26 @@ import { expect } from 'chai' import hre from 'hardhat' -import { getItemValue } from '../../../cli/config' +import { NamedAccounts } from '../../../tasks/type-extensions' describe('AllocationExchange configuration', () => { const { - graphConfig, contracts: { AllocationExchange }, + getNamedAccounts, } = hre.graph() + let namedAccounts: NamedAccounts + + before(async () => { + namedAccounts = await getNamedAccounts() + }) + it('should be owned by allocationExchangeOwner', async function () { const owner = await AllocationExchange.governor() - const allocationExchangeOwner = getItemValue(graphConfig, 'general/allocationExchangeOwner') - expect(owner).eq(allocationExchangeOwner) + expect(owner).eq(namedAccounts.allocationExchangeOwner.address) }) it('should accept vouchers from authority', async function () { - const authorityAddress = getItemValue(graphConfig, 'general/authority') - const allowed = await AllocationExchange.authority(authorityAddress) + const allowed = await AllocationExchange.authority(namedAccounts.authority.address) expect(allowed).eq(true) }) diff --git a/e2e/deployment/config/controller.test.ts b/e2e/deployment/config/controller.test.ts index 07313cfc0..00caf2130 100644 --- a/e2e/deployment/config/controller.test.ts +++ b/e2e/deployment/config/controller.test.ts @@ -1,9 +1,9 @@ import { expect } from 'chai' import hre, { ethers } from 'hardhat' -import { getItemValue } from '../../../cli/config' +import { NamedAccounts } from '../../../tasks/type-extensions' describe('Controller configuration', () => { - const { contracts, graphConfig } = hre.graph() + const { contracts, getNamedAccounts } = hre.graph() const { Controller } = contracts const proxyContracts = [ @@ -16,6 +16,12 @@ describe('Controller configuration', () => { 'GraphToken', ] + let namedAccounts: NamedAccounts + + before(async () => { + namedAccounts = await getNamedAccounts() + }) + const proxyShouldMatchDeployed = async (contractName: string) => { const curationAddress = await Controller.getContractProxy( ethers.utils.solidityKeccak256(['string'], [contractName]), @@ -25,14 +31,12 @@ describe('Controller configuration', () => { it('should be owned by governor', async function () { const owner = await Controller.governor() - const governorAddress = getItemValue(graphConfig, 'general/governor') - expect(owner).eq(governorAddress) + expect(owner).eq(namedAccounts.governor.address) }) it('pause guardian should be able to pause protocol', async function () { - const pauseGuardianAddress = getItemValue(graphConfig, 'general/pauseGuardian') const pauseGuardian = await Controller.pauseGuardian() - expect(pauseGuardian).eq(pauseGuardianAddress) + expect(pauseGuardian).eq(namedAccounts.pauseGuardian.address) }) describe('proxy contract', async function () { diff --git a/e2e/deployment/config/graphProxyAdmin.test.ts b/e2e/deployment/config/graphProxyAdmin.test.ts index fe781ffcc..0d43984de 100644 --- a/e2e/deployment/config/graphProxyAdmin.test.ts +++ b/e2e/deployment/config/graphProxyAdmin.test.ts @@ -1,16 +1,21 @@ import { expect } from 'chai' import hre from 'hardhat' -import { getItemValue } from '../../../cli/config' +import { NamedAccounts } from '../../../tasks/type-extensions' describe('GraphProxyAdmin configuration', () => { const { contracts: { GraphProxyAdmin }, - graphConfig, + getNamedAccounts, } = hre.graph() + let namedAccounts: NamedAccounts + + before(async () => { + namedAccounts = await getNamedAccounts() + }) + it('should be owned by governor', async function () { const owner = await GraphProxyAdmin.governor() - const governorAddress = getItemValue(graphConfig, 'general/governor') - expect(owner).eq(governorAddress) + expect(owner).eq(namedAccounts.governor.address) }) }) diff --git a/e2e/deployment/config/graphToken.test.ts b/e2e/deployment/config/graphToken.test.ts index 1b402a987..b0e9a53c8 100644 --- a/e2e/deployment/config/graphToken.test.ts +++ b/e2e/deployment/config/graphToken.test.ts @@ -1,18 +1,23 @@ import { expect } from 'chai' import hre from 'hardhat' -import { getItemValue } from '../../../cli/config' +import { NamedAccounts } from '../../../tasks/type-extensions' describe('GraphToken configuration', () => { const { - graphConfig, + getNamedAccounts, contracts: { GraphToken, RewardsManager }, getDeployer, } = hre.graph() + let namedAccounts: NamedAccounts + + before(async () => { + namedAccounts = await getNamedAccounts() + }) + it('should be owned by governor', async function () { const owner = await GraphToken.governor() - const governorAddress = getItemValue(graphConfig, 'general/governor') - expect(owner).eq(governorAddress) + expect(owner).eq(namedAccounts.governor.address) }) it('deployer should not be minter', async function () { diff --git a/e2e/deployment/config/rewardsManager.test.ts b/e2e/deployment/config/rewardsManager.test.ts index e2eefb94e..42a8192de 100644 --- a/e2e/deployment/config/rewardsManager.test.ts +++ b/e2e/deployment/config/rewardsManager.test.ts @@ -1,13 +1,21 @@ import { expect } from 'chai' import hre from 'hardhat' import { getItemValue } from '../../../cli/config' +import { NamedAccounts } from '../../../tasks/type-extensions' describe('RewardsManager configuration', () => { const { graphConfig, + getNamedAccounts, contracts: { RewardsManager, Controller }, } = hre.graph() + let namedAccounts: NamedAccounts + + before(async () => { + namedAccounts = await getNamedAccounts() + }) + it('should be controlled by Controller', async function () { const controller = await RewardsManager.controller() expect(controller).eq(Controller.address) @@ -20,8 +28,7 @@ describe('RewardsManager configuration', () => { }) it('should allow subgraph availability oracle to deny rewards', async function () { - const availabilityOracleAddress = getItemValue(graphConfig, 'general/availabilityOracle') const availabilityOracle = await RewardsManager.subgraphAvailabilityOracle() - expect(availabilityOracle).eq(availabilityOracleAddress) + expect(availabilityOracle).eq(namedAccounts.availabilityOracle.address) }) }) diff --git a/e2e/deployment/config/subgraphNFT.test.ts b/e2e/deployment/config/subgraphNFT.test.ts index 2e34eaa54..2220a1e1b 100644 --- a/e2e/deployment/config/subgraphNFT.test.ts +++ b/e2e/deployment/config/subgraphNFT.test.ts @@ -1,17 +1,22 @@ import { expect } from 'chai' import hre from 'hardhat' -import { getItemValue } from '../../../cli/config' +import { NamedAccounts } from '../../../tasks/type-extensions' describe('SubgraphNFT configuration', () => { const { - graphConfig, + getNamedAccounts, contracts: { SubgraphNFT, GNS, SubgraphNFTDescriptor }, } = hre.graph() + let namedAccounts: NamedAccounts + + before(async () => { + namedAccounts = await getNamedAccounts() + }) + it('should be owned by governor', async function () { const owner = await SubgraphNFT.governor() - const governorAddress = getItemValue(graphConfig, 'general/governor') - expect(owner).eq(governorAddress) + expect(owner).eq(namedAccounts.governor.address) }) it('should allow GNS to mint NFTs', async function () { From b5a01c387c580a9f884baf0ff766090b9308ca2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Migone?= Date: Wed, 27 Jul 2022 11:07:28 +0200 Subject: [PATCH 4/5] chore: rework named accounts generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Migone --- config/graph.localhost.yml | 12 ++++++------ tasks/gre.ts | 37 +++++++++++++++++++------------------ 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/config/graph.localhost.yml b/config/graph.localhost.yml index a1d3440bf..03f83682d 100644 --- a/config/graph.localhost.yml +++ b/config/graph.localhost.yml @@ -1,10 +1,10 @@ general: - arbitrator: &arbitrator "0x3fD652C93dFA333979ad762Cf581Df89BaBa6795" # Arbitration Council - governor: &governor "0x325A621DeA613BCFb5B1A69a7aCED0ea4AfBD73A" # Governor Council - authority: &authority "0xF0D5BC18421fa04D0a2A2ef540ba5A9f04014BE3" # Authority that signs payment vouchers - availabilityOracle: &availabilityOracle "0x66FC63C2572bF3ADD0Fe5d44b97c2E614E35e9a3" # Subgraph Availability Oracle - pauseGuardian: &pauseGuardian "0xf408f04F9b7691f7174FA2bb73ad6d45fD5d3CBe" # Protocol pause guardian - allocationExchangeOwner: &allocationExchangeOwner "0x2F560290FEF1B3Ada194b6aA9c40aa71f8e95598" # Allocation Exchange owner + arbitrator: &arbitrator "0xFFcf8FDEE72ac11b5c542428B35EEF5769C409f0" # Arbitration Council + governor: &governor "0x22d491Bde2303f2f43325b2108D26f1eAbA1e32b" # Governor Council + authority: &authority "0xE11BA2b4D45Eaed5996Cd0823791E0C93114882d" # Authority that signs payment vouchers + availabilityOracle: &availabilityOracle "0xd03ea8624C8C5987235048901fB614fDcA89b117" # Subgraph Availability Oracle + pauseGuardian: &pauseGuardian "0x95cED938F7991cd0dFcb48F0a06a40FA1aF46EBC" # Protocol pause guardian + allocationExchangeOwner: &allocationExchangeOwner "0x3E5e9111Ae8eB78Fe1CC3bb8915d5D461F3Ef9A9" # Allocation Exchange owner contracts: Controller: diff --git a/tasks/gre.ts b/tasks/gre.ts index 9e99a2a02..20d9685b5 100644 --- a/tasks/gre.ts +++ b/tasks/gre.ts @@ -24,46 +24,46 @@ extendEnvironment((hre: HardhatRuntimeEnvironment) => { throw new Error(`Graph config not found: ${graphConfigPath}`) } + const namedAccountList = [ + 'arbitrator', + 'governor', + 'authority', + 'availabilityOracle', + 'pauseGuardian', + 'allocationExchangeOwner', + ] + const getAccounts = async (): Promise => { const accounts = [] const signers: Signer[] = await hre.ethers.getSigners() - for (const signer of signers) { - accounts.push({ signer, address: await signer.getAddress() }) + // Skip deployer and named accounts + for (let i = namedAccountList.length + 1; i < signers.length; i++) { + accounts.push({ signer: signers[i], address: await signers[i].getAddress() }) } return accounts } const getNamedAccounts = async (): Promise => { - const names = [ - 'arbitrator', - 'governor', - 'authority', - 'availabilityOracle', - 'pauseGuardian', - 'allocationExchangeOwner', - ] - const testAccounts = await getTestAccounts() - const namedAccounts = names.reduce((acc, name, i) => { - acc[name] = chainId === '1337' ? testAccounts[i] : getNamedAccount(name) + const namedAccounts = namedAccountList.reduce((acc, name, i) => { + acc[name] = chainId === '1337' ? testAccounts[i] : getNamedAccountFromConfig(name) return acc }, {} as NamedAccounts) return namedAccounts } - const getNamedAccount = (name: string): Account => { + const getNamedAccountFromConfig = (name: string): Account => { const signer = new VoidSigner( getItemValue(readConfig(graphConfigPath, true), `general/${name}`), ) return { signer, address: signer.address } } - // Get accounts from the tail end of the signers list - // This is to prevent named accounts them from collisioning with test accounts const getTestAccounts = async (): Promise => { - return (await hre.ethers.getSigners()).reverse().map((s) => ({ + // Skip deployer account + return (await hre.ethers.getSigners()).slice(1).map((s) => ({ signer: s, address: s.address, })) @@ -78,7 +78,8 @@ extendEnvironment((hre: HardhatRuntimeEnvironment) => { getNamedAccounts: lazyFunction(() => getNamedAccounts), getAccounts: lazyFunction(() => getAccounts), getDeployer: lazyFunction(() => async () => { - return (await getAccounts())[0] + const signer = hre.ethers.provider.getSigner(0) + return { signer, address: await signer.getAddress() } }), } } From 6e68b487f89dfc59f44aab6c876777f43bc88c7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Migone?= Date: Wed, 27 Jul 2022 16:03:30 +0200 Subject: [PATCH 5/5] feat: replace getAccounts with getTestAccounts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Migone --- scripts/e2e | 4 ++-- tasks/deployment/accounts.ts | 1 + tasks/deployment/ownership.ts | 6 +++++- tasks/deployment/unpause.ts | 6 +++++- tasks/gre.ts | 34 ++++++++++++++-------------------- tasks/type-extensions.d.ts | 2 +- 6 files changed, 28 insertions(+), 25 deletions(-) diff --git a/scripts/e2e b/scripts/e2e index 0267bfc6b..adf3c2166 100755 --- a/scripts/e2e +++ b/scripts/e2e @@ -19,8 +19,8 @@ npx hardhat migrate:accounts --network localhost --graph-config config/graph.loc npx hardhat migrate --network localhost --skip-confirmation --graph-config config/graph.localhost.yml # Post deploy actions -npx hardhat migrate:ownership --network localhost -npx hardhat migrate:unpause --network localhost +npx hardhat migrate:ownership --network localhost --graph-config config/graph.localhost.yml +npx hardhat migrate:unpause --network localhost --graph-config config/graph.localhost.yml ### Test # Run tests using the localhost evm instance and the localhost graph config diff --git a/tasks/deployment/accounts.ts b/tasks/deployment/accounts.ts index 1ab2bd9c7..da30366b5 100644 --- a/tasks/deployment/accounts.ts +++ b/tasks/deployment/accounts.ts @@ -25,6 +25,7 @@ task('migrate:accounts', '[localhost] Creates protocol accounts and saves them i pauseGuardian, allocationExchangeOwner, } = await getNamedAccounts() + console.log(await getNamedAccounts()) console.log(`- Deployer: ${deployer.address}`) console.log(`- Arbitrator: ${arbitrator.address}`) diff --git a/tasks/deployment/ownership.ts b/tasks/deployment/ownership.ts index e983528e3..c5a872806 100644 --- a/tasks/deployment/ownership.ts +++ b/tasks/deployment/ownership.ts @@ -7,12 +7,16 @@ task( '[localhost] Accepts ownership of protocol contracts on behalf of governor', ) .addParam('addressBook', cliOpts.addressBook.description, cliOpts.addressBook.default) + .addParam('graphConfig', cliOpts.graphConfig.description, cliOpts.graphConfig.default) .setAction(async (taskArgs, hre) => { if (hre.network.name !== 'localhost') { throw new Error('This task can only be run on localhost network') } - const { contracts, getNamedAccounts } = hre.graph({ addressBook: taskArgs.addressBook }) + const { contracts, getNamedAccounts } = hre.graph({ + addressBook: taskArgs.addressBook, + graphConfig: taskArgs.graphConfig, + }) const { governor } = await getNamedAccounts() console.log('> Accepting ownership of contracts') diff --git a/tasks/deployment/unpause.ts b/tasks/deployment/unpause.ts index 2ffa34e3f..fa5767de5 100644 --- a/tasks/deployment/unpause.ts +++ b/tasks/deployment/unpause.ts @@ -3,8 +3,12 @@ import { cliOpts } from '../../cli/defaults' task('migrate:unpause', 'Unpause protocol') .addParam('addressBook', cliOpts.addressBook.description, cliOpts.addressBook.default) + .addParam('graphConfig', cliOpts.graphConfig.description, cliOpts.graphConfig.default) .setAction(async (taskArgs, hre) => { - const { contracts, getNamedAccounts } = hre.graph({ addressBook: taskArgs.addressBook }) + const { contracts, getNamedAccounts } = hre.graph({ + addressBook: taskArgs.addressBook, + graphConfig: taskArgs.graphConfig, + }) const { governor } = await getNamedAccounts() console.log('> Unpausing protocol') diff --git a/tasks/gre.ts b/tasks/gre.ts index 20d9685b5..f2a062747 100644 --- a/tasks/gre.ts +++ b/tasks/gre.ts @@ -33,7 +33,7 @@ extendEnvironment((hre: HardhatRuntimeEnvironment) => { 'allocationExchangeOwner', ] - const getAccounts = async (): Promise => { + const getTestAccounts = async (): Promise => { const accounts = [] const signers: Signer[] = await hre.ethers.getSigners() @@ -44,31 +44,25 @@ extendEnvironment((hre: HardhatRuntimeEnvironment) => { return accounts } + // Returns void signers. Upgrades to signer on loca networks. const getNamedAccounts = async (): Promise => { - const testAccounts = await getTestAccounts() - const namedAccounts = namedAccountList.reduce((acc, name, i) => { - acc[name] = chainId === '1337' ? testAccounts[i] : getNamedAccountFromConfig(name) + const namedAccounts = namedAccountList.reduce((acc, name) => { + const address = getItemValue(readConfig(graphConfigPath, true), `general/${name}`) + + if (chainId === '1337') { + const signer = hre.ethers.provider.getSigner(address) + acc[name] = { signer, address: address } + } else { + const signer = new VoidSigner(address) + acc[name] = { signer, address: signer.address } + } + return acc }, {} as NamedAccounts) return namedAccounts } - const getNamedAccountFromConfig = (name: string): Account => { - const signer = new VoidSigner( - getItemValue(readConfig(graphConfigPath, true), `general/${name}`), - ) - return { signer, address: signer.address } - } - - const getTestAccounts = async (): Promise => { - // Skip deployer account - return (await hre.ethers.getSigners()).slice(1).map((s) => ({ - signer: s, - address: s.address, - })) - } - return { addressBook: lazyObject(() => getAddressBook(addressBookPath, chainId)), graphConfig: lazyObject(() => readConfig(graphConfigPath, true)), @@ -76,7 +70,7 @@ extendEnvironment((hre: HardhatRuntimeEnvironment) => { loadContracts(getAddressBook(addressBookPath, chainId), hre.ethers.provider), ), getNamedAccounts: lazyFunction(() => getNamedAccounts), - getAccounts: lazyFunction(() => getAccounts), + getTestAccounts: lazyFunction(() => getTestAccounts), getDeployer: lazyFunction(() => async () => { const signer = hre.ethers.provider.getSigner(0) return { signer, address: await signer.getAddress() } diff --git a/tasks/type-extensions.d.ts b/tasks/type-extensions.d.ts index 7182fb956..400be724f 100644 --- a/tasks/type-extensions.d.ts +++ b/tasks/type-extensions.d.ts @@ -28,7 +28,7 @@ declare module 'hardhat/types/runtime' { graphConfig: any addressBook: AddressBook getNamedAccounts: () => Promise - getAccounts: () => Promise + getTestAccounts: () => Promise getDeployer: () => Promise } }