/** * @type import('hardhat/config').HardhatUserConfig */ import { HardhatUserConfig } from "hardhat/types"; import "@typechain/hardhat"; import "@nomicfoundation/hardhat-chai-matchers"; //Added for revertWithCustomErrors import "@nomicfoundation/hardhat-verify"; import "@openzeppelin/hardhat-upgrades"; import "solidity-coverage"; import "hardhat-gas-reporter"; import "hardhat-contract-sizer"; import "hardhat-storage-layout"; import "hardhat-deploy"; import { task, types } from "hardhat/config"; import { sha3 } from "web3-utils"; import { config } from "dotenv"; import { airdrop } from "./scripts/governance/airdropCalculationSorted"; import { airdrop as repAirdropRecover } from "./scripts/governance/airdropCalculationRecover"; import { airdrop as goodCheckpoint } from "./scripts/governance/goodCheckpointSorted"; import { airdrop as gdxAirdrop, airdropRecover as gdxAirdropRecover } from "./scripts/gdx/gdxAirdropCalculation"; import { sumStakersGdRewards } from "./scripts/staking/stakersGdRewardsCalculation"; import { verify } from "./scripts/verify"; import { ethers } from "ethers"; import { fstat, readFileSync, writeFileSync } from "fs"; import * as envEnc from "@chainlink/env-enc"; envEnc.config(); config(); const mnemonic = process.env.MNEMONIC || "test test test test test test test test test test test junk"; const deployerPrivateKey = process.env.PRIVATE_KEY || ethers.utils.hexZeroPad("0x11", 32); const infura_api = process.env.INFURA_API; const alchemy_key = process.env.ALCHEMY_KEY; const etherscan_key = process.env.ETHERSCAN_KEY; const celoscan_key = process.env.CELOSCAN_KEY; const basescan_key = process.env.BASESCAN_KEY; const ethplorer_key = process.env.ETHPLORER_KEY; const MAINNET_URL = "https://mainnet.infura.io/v3/" + infura_api; const xdc = { accounts: { mnemonic }, url: "https://rpc.ankr.com/xdc/ef07ba6590dc46db9275bba237aed203ed6d5fb3e3203ff237a82a841f75b2ce", gas: 3000000, gasPrice: 12.5e9, chainId: 50 }; // console.log({ mnemonic: sha3(mnemonic) }); const hhconfig: HardhatUserConfig = { solidity: { version: "0.8.19", settings: { optimizer: { enabled: true, runs: 0 } } }, typechain: { outDir: "types" }, sourcify: { enabled: true }, etherscan: { apiKey: { mainnet: etherscan_key, txdc: etherscan_key, xdc: etherscan_key, celo: etherscan_key, alfajores: celoscan_key, base: basescan_key, fuse: etherscan_key }, customChains: [ { network: "fuse", chainId: 122, urls: { apiURL: "https://explorer.fuse.io/api", browserURL: "https://explorer.fuse.io/" } }, { network: "celo", chainId: 42220, urls: { apiURL: "https://api.etherscan.io/v2/api?chainid=42220", browserURL: "https://celoscan.io/" } }, { network: "alfajores", chainId: 44787, urls: { apiURL: "https://alfajores.celoscan.io/api", browserURL: "https://alfajores.celoscan.io/" } }, { network: "txdc", chainId: 51, urls: { apiURL: "https://api.etherscan.io/v2/api?chainid=51", browserURL: "https://testnet.xdcscan.com/" } }, { network: "xdc", chainId: 50, urls: { apiURL: "https://api.etherscan.io/v2/api?chainid=50", browserURL: "https://xdcscan.com/" } } ] }, contractSizer: { alphaSort: false, runOnCompile: true, disambiguatePaths: false }, networks: { hardhat: { chainId: process.env.FORK_CHAIN_ID ? Number(process.env.FORK_CHAIN_ID) : 4447, allowUnlimitedContractSize: true, accounts: { accountsBalance: "10000000000000000000000000" }, initialDate: "2021-12-01", //required for DAO tests like guardian forking: process.env.FORK_CHAIN_ID && { url: "https://eth-mainnet.alchemyapi.io/v2/" + process.env.ALCHEMY_KEY } }, fork: { chainId: 1, url: "https://rpc.vnet.tenderly.co/devnet/reserve-ujpgrade/b4c1e3d8-c03e-49a5-b3ef-eac8499c9f0d" }, test: { allowUnlimitedContractSize: true, url: "http://127.0.0.1:8545/" }, develop: { gasPrice: 1000000000, //1 gwei url: "http://127.0.0.1:8545/", chainId: 4447 }, "develop-mainnet": { gasPrice: 1000000000, //1 gwei url: "http://127.0.0.1:8545/", chainId: 4447 }, dapptest: { gasPrice: 1000000000, //1 gwei url: "http://127.0.0.1:8545/" }, "dapptest-mainnet": { gasPrice: 1000000000, //1 gwei url: "http://127.0.0.1:8545/" }, fuse: { accounts: { mnemonic }, url: "https://rpc.fuse.io/", chainId: 122, gas: 6000000, gasPrice: 11e9 }, fuseexplorer: { accounts: { mnemonic }, url: "https://explorer-node.fuse.io/", chainId: 122, gas: 6000000, gasPrice: 10000000000 }, fusespark: { accounts: { mnemonic }, url: "https://rpc.fusespark.io/", gas: 3000000, gasPrice: 10000000000, chainId: 123 }, "fuse-mainnet": { accounts: { mnemonic }, url: "https://ropsten.infura.io/v3/" + infura_api, gasPrice: 20000000000, gas: 5000000, chainId: 3 }, staging: { accounts: { mnemonic }, url: "https://rpc.fuse.io/", chainId: 122, gas: 6000000, gasPrice: 11e9 }, "staging-mainnet": { accounts: { mnemonic }, url: "https://ropsten.infura.io/v3/" + infura_api, gasPrice: 20000000000, gas: 5000000, chainId: 3 }, production: { accounts: [deployerPrivateKey], url: "https://rpc.fuse.io/", gas: 3000000, gasPrice: 11e9, chainId: 122 }, "production-mainnet": { accounts: [deployerPrivateKey], url: MAINNET_URL, // gas: 3000000, gasPrice: 15000000000, chainId: 1 }, "production-celo": { accounts: [deployerPrivateKey], url: "https://forno.celo.org", gas: 8000000, gasPrice: 26e9, chainId: 42220 }, celo: { accounts: { mnemonic }, url: "https://forno.celo.org", gas: 3000000, gasPrice: 26e9, chainId: 42220 }, alfajores: { accounts: { mnemonic }, chainId: 44787, url: `https://alfajores-forno.celo-testnet.org`, gasPrice: 5000000000 }, "alfajores-fork": { accounts: { mnemonic }, chainId: 44787, url: `http://127.0.0.1:8545`, gasPrice: 5000000000 }, "staging-celo": { accounts: { mnemonic }, url: "https://forno.celo.org", gas: 3000000, gasPrice: 26e9, chainId: 42220 }, "development-celo": { accounts: { mnemonic }, url: "https://forno.celo.org", gas: 3000000, gasPrice: 26e9, chainId: 42220 }, "development-base": { accounts: { mnemonic }, url: "https://mainnet.base.org", initialBaseFeePerGas: 0, gasPrice: 8e6 }, "production-base": { accounts: [deployerPrivateKey], url: "https://mainnet.base.org", initialBaseFeePerGas: 0, gasPrice: 8e6 }, gnosis: { accounts: [deployerPrivateKey], url: "https://rpc.gnosischain.com", gas: 3000000, gasPrice: 500000000, chainId: 100 }, txdc: { accounts: [deployerPrivateKey], url: "https://rpc.apothem.network", chainId: 51 }, xdc: { ...xdc }, "production-xdc": { ...xdc, accounts: [deployerPrivateKey] }, "development-xdc": { ...xdc // url: "http://localhost:8545" } }, mocha: { timeout: 6000000 } }; task("repAirdrop", "Calculates airdrop data and merkle tree") .addParam("action", "calculate/tree/proof") .addOptionalParam("fusesnapshotblock", "fuse block for calculate") .addOptionalParam("ethsnapshotblock", "eth block for calculate") .addOptionalPositionalParam("address", "proof for address") .setAction(async (taskArgs, hre) => { const actions = airdrop(hre.ethers, ethplorer_key, etherscan_key); switch (taskArgs.action) { case "calculate": return actions.collectAirdropData(taskArgs.fusesnapshotblock, taskArgs.ethsnapshotblock); case "tree": return actions.buildMerkleTree(); case "proof": return actions.getProof(taskArgs.address); default: console.log("unknown action use calculate or tree"); } }); task("repAirdropRecover", "Calculates airdrop data and merkle tree after critical bug") .addParam("action", "calculate/tree/proof") .addOptionalPositionalParam("address", "proof for address") .setAction(async (taskArgs, hre) => { const actions = repAirdropRecover(hre.ethers, ethplorer_key, etherscan_key); switch (taskArgs.action) { case "calculate": return actions.collectAirdropData(); case "tree": return actions.buildMerkleTree(); case "proof": return actions.getProof(taskArgs.address); default: console.log("unknown action use calculate or tree"); } }); task("gdxAirdrop", "Calculates airdrop data") .addParam("action", "calculate/tree/proof") .addOptionalPositionalParam("address", "proof for address") .addOptionalParam("ethsnapshotblock", "eth block for calculate") .setAction(async (taskArgs, hre) => { const actions = gdxAirdrop(hre.ethers, taskArgs.ethsnapshotblock); switch (taskArgs.action) { case "calculate": return actions.collectAirdropData(); case "tree": return actions.buildMerkleTree(); case "proof": return actions.getProof(taskArgs.address); default: console.log("unknown action use calculate or tree"); } }); task("gdxAirdropRecover", "Calculates new airdrop data for recovery") .addParam("action", "addition/tree") .setAction(async (taskArgs, hre) => { const actions = gdxAirdropRecover(hre.ethers); switch (taskArgs.action) { case "addition": return actions.addCalculationsToPreviousData(); case "tree": return actions.buildMerkleTree(); default: console.log("unknown action use addition or tree"); } }); task("goodCheckpoint", "Calculates good checkpoint data and merkle tree for GOOD sync") .addParam("action", "calculate/tree/proof") .addOptionalPositionalParam("address", "proof for address") .setAction(async (taskArgs, hre) => { const actions = goodCheckpoint(hre.ethers, ethplorer_key, etherscan_key); switch (taskArgs.action) { case "calculate": return actions.collectAirdropData(); case "tree": return actions.buildMerkleTree(); case "proof": return actions.getProof(taskArgs.address); default: console.log("unknown action use calculate or tree"); } }); task("verifyjson", "verify contracts on etherscan").setAction(async (taskArgs, hre) => { return verify(hre); }); export default hhconfig; task("sumStakersGdRewards", "Sums the GoodDollar reward for each staker").setAction(async (taskArgs, hre) => { const actions = sumStakersGdRewards(hre.ethers); return actions.getStakersGdRewards(); }); task("cleanflat", "Cleans multiple SPDX and Pragma from flattened file") .addPositionalParam("file", "flattened sol file") .setAction(async ({ file }, { run }) => { let flattened = await run("flatten:get-flattened-sources", { files: [file] }); // Remove every line started with "// SPDX-License-Identifier:" flattened = flattened.replace(/SPDX-License-Identifier:/gm, "License-Identifier:"); flattened = `// SPDX-License-Identifier: MIXED\n\n${flattened}`; // Remove every line started with "pragma experimental ABIEncoderV2;" except the first one flattened = flattened.replace( /pragma experimental ABIEncoderV2;\n/gm, ( i => m => !i++ ? m : "" )(0) ); flattened = flattened.replace( /pragma solidity.*\n/gm, ( i => m => !i++ ? m : "" )(0) ); flattened = flattened.trim(); writeFileSync("flat.sol", flattened); });