diff --git a/.changeset/slimy-snakes-sip.md b/.changeset/slimy-snakes-sip.md new file mode 100644 index 00000000..a845151c --- /dev/null +++ b/.changeset/slimy-snakes-sip.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/data/chain-support.json b/data/chain-support.json index 223853d4..aca17456 100644 --- a/data/chain-support.json +++ b/data/chain-support.json @@ -1,174 +1,4 @@ { - "chainsSupportedByManagerMultisig": [ - "apechain", - "apechain-arbitrum-sepolia-testnet", - "arbitrum", - "arbitrum-sepolia-testnet", - "avalanche", - "avalanche-testnet", - "base", - "base-sepolia-testnet", - "berachain", - "berachain-testnet", - "bitlayer", - "bitlayer-testnet", - "blast", - "blast-sepolia-testnet", - "bob", - "bob-sepolia-testnet", - "bsc", - "bsc-testnet", - "core", - "core-testnet", - "ethereum", - "ethereum-holesky-testnet", - "ethereum-sepolia-testnet", - "fraxtal", - "fraxtal-holesky-testnet", - "gnosis", - "gnosis-testnet", - "ink", - "ink-sepolia-testnet", - "katana", - "kava", - "kava-testnet", - "linea", - "linea-sepolia-testnet", - "lumia", - "lumia-sepolia-testnet", - "manta", - "manta-sepolia-testnet", - "mantle", - "mantle-sepolia-testnet", - "megaeth-testnet", - "merlin", - "merlin-testnet", - "metal", - "metal-sepolia-testnet", - "metis", - "metis-sepolia-testnet", - "mode", - "mode-sepolia-testnet", - "monad-testnet", - "moonbeam", - "moonbeam-testnet", - "moonriver", - "odyssey-sepolia-testnet", - "oev-network", - "opbnb", - "opbnb-testnet", - "optimism", - "optimism-sepolia-testnet", - "polygon", - "polygon-sepolia-testnet", - "polygon-zkevm", - "polygon-zkevm-sepolia-testnet", - "ronin", - "ronin-testnet", - "scroll", - "scroll-sepolia-testnet", - "sei", - "sei-testnet", - "soneium", - "soneium-sepolia-testnet", - "sonic", - "sonic-testnet", - "taiko", - "taiko-holesky-testnet", - "unichain", - "unichain-sepolia-testnet", - "world", - "world-sepolia-testnet", - "x-layer", - "x-layer-sepolia-testnet", - "zircuit", - "zircuit-sepolia-testnet" - ], - "chainsSupportedByDapis": [ - "apechain", - "apechain-arbitrum-sepolia-testnet", - "arbitrum", - "arbitrum-sepolia-testnet", - "avalanche", - "avalanche-testnet", - "base", - "base-sepolia-testnet", - "berachain", - "berachain-testnet", - "bitlayer", - "bitlayer-testnet", - "blast", - "blast-sepolia-testnet", - "bob", - "bob-sepolia-testnet", - "bsc", - "bsc-testnet", - "core", - "core-testnet", - "ethereum", - "ethereum-holesky-testnet", - "ethereum-sepolia-testnet", - "fraxtal", - "fraxtal-holesky-testnet", - "gnosis", - "gnosis-testnet", - "ink", - "ink-sepolia-testnet", - "katana", - "kava", - "kava-testnet", - "linea", - "linea-sepolia-testnet", - "lumia", - "lumia-sepolia-testnet", - "manta", - "manta-sepolia-testnet", - "mantle", - "mantle-sepolia-testnet", - "megaeth-testnet", - "merlin", - "merlin-testnet", - "metal", - "metal-sepolia-testnet", - "metis", - "metis-sepolia-testnet", - "mode", - "mode-sepolia-testnet", - "monad-testnet", - "moonbeam", - "moonbeam-testnet", - "moonriver", - "odyssey-sepolia-testnet", - "oev-network", - "opbnb", - "opbnb-testnet", - "optimism", - "optimism-sepolia-testnet", - "polygon", - "polygon-sepolia-testnet", - "polygon-zkevm", - "polygon-zkevm-sepolia-testnet", - "ronin", - "ronin-testnet", - "scroll", - "scroll-sepolia-testnet", - "sei", - "sei-testnet", - "soneium", - "soneium-sepolia-testnet", - "sonic", - "sonic-testnet", - "taiko", - "taiko-holesky-testnet", - "unichain", - "unichain-sepolia-testnet", - "world", - "world-sepolia-testnet", - "x-layer", - "x-layer-sepolia-testnet", - "zircuit", - "zircuit-sepolia-testnet" - ], "chainsSupportedByMarket": [ "apechain", "apechain-arbitrum-sepolia-testnet", diff --git a/deploy/1_deploy.ts b/deploy/1_deploy.ts index c0f577f8..a952c2a7 100644 --- a/deploy/1_deploy.ts +++ b/deploy/1_deploy.ts @@ -1,11 +1,6 @@ import { deployments, ethers, network } from 'hardhat'; -import { - chainsSupportedByManagerMultisig, - chainsSupportedByDapis, - chainsSupportedByMarket, - chainsSupportedByOevAuctions, -} from '../data/chain-support.json'; +import { chainsSupportedByMarket, chainsSupportedByOevAuctions } from '../data/chain-support.json'; import * as managerMultisigMetadata from '../data/manager-multisig-metadata.json'; import { CHAINS } from '../src/index'; import type { Api3ReaderProxyV1Factory, OwnableCallForwarder } from '../src/index'; @@ -16,141 +11,136 @@ module.exports = async () => { const { deploy, log } = deployments; const [deployer] = await ethers.getSigners(); - if (chainsSupportedByManagerMultisig.includes(network.name)) { - const gnosisSafeWithoutProxy = await deployments.get('GnosisSafeWithoutProxy').catch(async () => { - log(`Deploying GnosisSafeWithoutProxy`); - return deploy('GnosisSafeWithoutProxy', { - args: CHAINS.find((chain) => chain.alias === process.env.NETWORK)?.testnet - ? [managerMultisigMetadata.testnet.owners, managerMultisigMetadata.testnet.threshold] - : [managerMultisigMetadata.mainnet.owners, managerMultisigMetadata.mainnet.threshold], + if (!chainsSupportedByMarket.includes(network.name)) { + throw new Error(`${network.name} is not supported`); + } + const gnosisSafeWithoutProxy = await deployments.get('GnosisSafeWithoutProxy').catch(async () => { + log(`Deploying GnosisSafeWithoutProxy`); + return deploy('GnosisSafeWithoutProxy', { + args: CHAINS.find((chain) => chain.alias === process.env.NETWORK)?.testnet + ? [managerMultisigMetadata.testnet.owners, managerMultisigMetadata.testnet.threshold] + : [managerMultisigMetadata.mainnet.owners, managerMultisigMetadata.mainnet.threshold], + from: deployer!.address, + log: true, + deterministicDeployment: process.env.DETERMINISTIC ? ethers.ZeroHash : '', + }); + }); + + const { address: ownableCallForwarderAddress, abi: ownableCallForwarderAbi } = await deployments + .get('OwnableCallForwarder') + .catch(async () => { + log(`Deploying OwnableCallForwarder`); + return deploy('OwnableCallForwarder', { from: deployer!.address, + args: [gnosisSafeWithoutProxy.address], log: true, deterministicDeployment: process.env.DETERMINISTIC ? ethers.ZeroHash : '', }); }); + const ownableCallForwarder = new ethers.Contract( + ownableCallForwarderAddress, + ownableCallForwarderAbi, + deployer + ) as unknown as OwnableCallForwarder; - const { address: ownableCallForwarderAddress, abi: ownableCallForwarderAbi } = await deployments - .get('OwnableCallForwarder') - .catch(async () => { - log(`Deploying OwnableCallForwarder`); - return deploy('OwnableCallForwarder', { - from: deployer!.address, - args: [gnosisSafeWithoutProxy.address], - log: true, - deterministicDeployment: process.env.DETERMINISTIC ? ethers.ZeroHash : '', - }); - }); - const ownableCallForwarder = new ethers.Contract( - ownableCallForwarderAddress, - ownableCallForwarderAbi, - deployer - ) as unknown as OwnableCallForwarder; + const accessControlRegistry = await deployments.get('AccessControlRegistry').catch(async () => { + log(`Deploying AccessControlRegistry`); + return deploy('AccessControlRegistry', { + from: deployer!.address, + log: true, + deterministicDeployment: process.env.DETERMINISTIC ? ethers.ZeroHash : '', + }); + }); - if (chainsSupportedByDapis.includes(network.name)) { - const accessControlRegistry = await deployments.get('AccessControlRegistry').catch(async () => { - log(`Deploying AccessControlRegistry`); - return deploy('AccessControlRegistry', { - from: deployer!.address, - log: true, - deterministicDeployment: process.env.DETERMINISTIC ? ethers.ZeroHash : '', - }); - }); + const api3ServerV1 = await deployments.get('Api3ServerV1').catch(async () => { + log(`Deploying Api3ServerV1`); + return deploy('Api3ServerV1', { + from: deployer!.address, + args: [accessControlRegistry.address, 'Api3ServerV1 admin', await ownableCallForwarder.getAddress()], + log: true, + deterministicDeployment: process.env.DETERMINISTIC ? ethers.ZeroHash : '', + }); + }); - const api3ServerV1 = await deployments.get('Api3ServerV1').catch(async () => { - log(`Deploying Api3ServerV1`); - return deploy('Api3ServerV1', { - from: deployer!.address, - args: [accessControlRegistry.address, 'Api3ServerV1 admin', await ownableCallForwarder.getAddress()], - log: true, - deterministicDeployment: process.env.DETERMINISTIC ? ethers.ZeroHash : '', - }); - }); + const api3ServerV1OevExtension = await deployments.get('Api3ServerV1OevExtension').catch(async () => { + log(`Deploying Api3ServerV1OevExtension`); + return deploy('Api3ServerV1OevExtension', { + from: deployer!.address, + args: [ + accessControlRegistry.address, + 'Api3ServerV1OevExtension admin', + await ownableCallForwarder.getAddress(), + api3ServerV1.address, + ], + log: true, + deterministicDeployment: process.env.DETERMINISTIC ? ethers.ZeroHash : '', + }); + }); - const api3ServerV1OevExtension = await deployments.get('Api3ServerV1OevExtension').catch(async () => { - log(`Deploying Api3ServerV1OevExtension`); - return deploy('Api3ServerV1OevExtension', { - from: deployer!.address, - args: [ - accessControlRegistry.address, - 'Api3ServerV1OevExtension admin', - await ownableCallForwarder.getAddress(), - api3ServerV1.address, - ], - log: true, - deterministicDeployment: process.env.DETERMINISTIC ? ethers.ZeroHash : '', - }); + const { address: api3ReaderProxyV1FactoryAddress, abi: api3ReaderProxyV1FactoryAbi } = await deployments + .get('Api3ReaderProxyV1Factory') + .catch(async () => { + log(`Deploying Api3ReaderProxyV1Factory`); + return deploy('Api3ReaderProxyV1Factory', { + from: deployer!.address, + args: [await ownableCallForwarder.getAddress(), api3ServerV1OevExtension.address], + log: true, + deterministicDeployment: process.env.DETERMINISTIC ? ethers.ZeroHash : '', }); + }); + const api3ReaderProxyV1Factory = new ethers.Contract( + api3ReaderProxyV1FactoryAddress, + api3ReaderProxyV1FactoryAbi, + deployer + ) as unknown as Api3ReaderProxyV1Factory; - const { address: api3ReaderProxyV1FactoryAddress, abi: api3ReaderProxyV1FactoryAbi } = await deployments - .get('Api3ReaderProxyV1Factory') - .catch(async () => { - log(`Deploying Api3ReaderProxyV1Factory`); - return deploy('Api3ReaderProxyV1Factory', { - from: deployer!.address, - args: [await ownableCallForwarder.getAddress(), api3ServerV1OevExtension.address], - log: true, - deterministicDeployment: process.env.DETERMINISTIC ? ethers.ZeroHash : '', - }); - }); - const api3ReaderProxyV1Factory = new ethers.Contract( - api3ReaderProxyV1FactoryAddress, - api3ReaderProxyV1FactoryAbi, - deployer - ) as unknown as Api3ReaderProxyV1Factory; - - const dapiName = ethers.encodeBytes32String('ETH/USD'); - const dappId = 1; - const api3ReaderProxyV1Metadata = '0x'; - const expectedApi3ReaderProxyV1Address = await api3ReaderProxyV1Factory.computeApi3ReaderProxyV1Address( - dapiName, - dappId, - api3ReaderProxyV1Metadata - ); - if ((await ethers.provider.getCode(expectedApi3ReaderProxyV1Address)) === '0x') { - await api3ReaderProxyV1Factory.deployApi3ReaderProxyV1(dapiName, dappId, api3ReaderProxyV1Metadata); - log(`Deployed example Api3ReaderProxyV1 at ${expectedApi3ReaderProxyV1Address}`); - } + const dapiName = ethers.encodeBytes32String('ETH/USD'); + const dappId = 1; + const api3ReaderProxyV1Metadata = '0x'; + const expectedApi3ReaderProxyV1Address = await api3ReaderProxyV1Factory.computeApi3ReaderProxyV1Address( + dapiName, + dappId, + api3ReaderProxyV1Metadata + ); + if ((await ethers.provider.getCode(expectedApi3ReaderProxyV1Address)) === '0x') { + await api3ReaderProxyV1Factory.deployApi3ReaderProxyV1(dapiName, dappId, api3ReaderProxyV1Metadata); + log(`Deployed example Api3ReaderProxyV1 at ${expectedApi3ReaderProxyV1Address}`); + } - if (chainsSupportedByMarket.includes(network.name)) { - const api3MarketV2 = await deployments.get('Api3MarketV2').catch(async () => { - log(`Deploying Api3MarketV2`); - return deploy('Api3MarketV2', { - from: deployer!.address, - args: [ - await ownableCallForwarder.getAddress(), - api3ReaderProxyV1FactoryAddress, - MAXIMUM_SUBSCRIPTION_QUEUE_LENGTH, - ], - log: true, - deterministicDeployment: process.env.DETERMINISTIC ? ethers.ZeroHash : '', - }); - }); + const api3MarketV2 = await deployments.get('Api3MarketV2').catch(async () => { + log(`Deploying Api3MarketV2`); + return deploy('Api3MarketV2', { + from: deployer!.address, + args: [ + await ownableCallForwarder.getAddress(), + api3ReaderProxyV1FactoryAddress, + MAXIMUM_SUBSCRIPTION_QUEUE_LENGTH, + ], + log: true, + deterministicDeployment: process.env.DETERMINISTIC ? ethers.ZeroHash : '', + }); + }); - await deployments.get('AirseekerRegistry').catch(async () => { - log(`Deploying AirseekerRegistry`); - return deploy('AirseekerRegistry', { - from: deployer!.address, - args: [api3MarketV2.address, api3ServerV1.address], - log: true, - deterministicDeployment: process.env.DETERMINISTIC ? ethers.ZeroHash : '', - }); - }); - } + await deployments.get('AirseekerRegistry').catch(async () => { + log(`Deploying AirseekerRegistry`); + return deploy('AirseekerRegistry', { + from: deployer!.address, + args: [api3MarketV2.address, api3ServerV1.address], + log: true, + deterministicDeployment: process.env.DETERMINISTIC ? ethers.ZeroHash : '', + }); + }); - if (chainsSupportedByOevAuctions.includes(network.name)) { - await deployments.get('OevAuctionHouse').catch(async () => { - log(`Deploying OevAuctionHouse`); - return deploy('OevAuctionHouse', { - from: deployer!.address, - args: [accessControlRegistry.address, 'OevAuctionHouse admin', await ownableCallForwarder.getAddress()], - log: true, - deterministicDeployment: process.env.DETERMINISTIC ? ethers.ZeroHash : '', - }); - }); - } - } - } else { - throw new Error(`${network.name} is not supported`); + if (chainsSupportedByOevAuctions.includes(network.name)) { + await deployments.get('OevAuctionHouse').catch(async () => { + log(`Deploying OevAuctionHouse`); + return deploy('OevAuctionHouse', { + from: deployer!.address, + args: [accessControlRegistry.address, 'OevAuctionHouse admin', await ownableCallForwarder.getAddress()], + log: true, + deterministicDeployment: process.env.DETERMINISTIC ? ethers.ZeroHash : '', + }); + }); } }; module.exports.tags = ['deploy']; diff --git a/deploy/2_update_beacon_set.ts b/deploy/2_update_beacon_set.ts index 79fc4bad..6698090d 100644 --- a/deploy/2_update_beacon_set.ts +++ b/deploy/2_update_beacon_set.ts @@ -2,7 +2,7 @@ import { type HardhatEthersSigner } from '@nomicfoundation/hardhat-ethers/signer import type { BytesLike } from 'ethers'; import { deployments, ethers, network } from 'hardhat'; -import { chainsSupportedByDapis } from '../data/chain-support.json'; +import { chainsSupportedByMarket } from '../data/chain-support.json'; import { Api3ServerV1__factory } from '../src/index'; const EXPECTED_DEPLOYER_ADDRESS = ethers.getAddress('0x07b589f06bD0A5324c4E2376d66d2F4F25921DE1'); @@ -45,7 +45,7 @@ module.exports = async () => { // If the first signer returned by ethers is the expected deployer address, it will do both (1) and (2). // Otherwise, it will only do (1). In both cases, (1) is done using hardcoded signatures by the expected // deployer address. - if (!chainsSupportedByDapis.includes(network.name)) { + if (!chainsSupportedByMarket.includes(network.name)) { log(`Skipping Beacon set update for ${network.name}`); return; } diff --git a/deploy/3_verify.ts b/deploy/3_verify.ts index b5b4bd32..be60c40f 100644 --- a/deploy/3_verify.ts +++ b/deploy/3_verify.ts @@ -1,130 +1,121 @@ import { deployments, ethers, network, run } from 'hardhat'; -import { - chainsSupportedByManagerMultisig, - chainsSupportedByDapis, - chainsSupportedByMarket, - chainsSupportedByOevAuctions, -} from '../data/chain-support.json'; +import { chainsSupportedByMarket, chainsSupportedByOevAuctions } from '../data/chain-support.json'; import { Api3ReaderProxyV1__factory, ERC1967Proxy__factory } from '../src/index'; const EXPECTED_DEPLOYER_ADDRESS = ethers.getAddress('0x07b589f06bD0A5324c4E2376d66d2F4F25921DE1'); const MAXIMUM_SUBSCRIPTION_QUEUE_LENGTH = 10; module.exports = async () => { - if (chainsSupportedByManagerMultisig.includes(network.name)) { - const GnosisSafeWithoutProxy = await deployments.get('GnosisSafeWithoutProxy'); - await run('verify:verify', { - address: GnosisSafeWithoutProxy.address, - constructorArguments: GnosisSafeWithoutProxy.args, - }); + if (!chainsSupportedByMarket.includes(network.name)) { + throw new Error(`${network.name} is not supported`); + } - const OwnableCallForwarder = await deployments.get('OwnableCallForwarder'); - await run('verify:verify', { - address: OwnableCallForwarder.address, - constructorArguments: [EXPECTED_DEPLOYER_ADDRESS], - }); + const GnosisSafeWithoutProxy = await deployments.get('GnosisSafeWithoutProxy'); + await run('verify:verify', { + address: GnosisSafeWithoutProxy.address, + constructorArguments: GnosisSafeWithoutProxy.args, + }); - if (chainsSupportedByDapis.includes(network.name)) { - const AccessControlRegistry = await deployments.get('AccessControlRegistry'); - await run('verify:verify', { - address: AccessControlRegistry.address, - }); + const OwnableCallForwarder = await deployments.get('OwnableCallForwarder'); + await run('verify:verify', { + address: OwnableCallForwarder.address, + constructorArguments: [EXPECTED_DEPLOYER_ADDRESS], + }); - const Api3ServerV1 = await deployments.get('Api3ServerV1'); - await run('verify:verify', { - address: Api3ServerV1.address, - constructorArguments: [AccessControlRegistry.address, 'Api3ServerV1 admin', OwnableCallForwarder.address], - }); + const AccessControlRegistry = await deployments.get('AccessControlRegistry'); + await run('verify:verify', { + address: AccessControlRegistry.address, + }); - const Api3ServerV1OevExtension = await deployments.get('Api3ServerV1OevExtension'); - await run('verify:verify', { - address: Api3ServerV1OevExtension.address, - constructorArguments: [ - AccessControlRegistry.address, - 'Api3ServerV1OevExtension admin', - OwnableCallForwarder.address, - Api3ServerV1.address, - ], - }); + const Api3ServerV1 = await deployments.get('Api3ServerV1'); + await run('verify:verify', { + address: Api3ServerV1.address, + constructorArguments: [AccessControlRegistry.address, 'Api3ServerV1 admin', OwnableCallForwarder.address], + }); - const Api3ReaderProxyV1Factory = await deployments.get('Api3ReaderProxyV1Factory'); - await run('verify:verify', { - address: Api3ReaderProxyV1Factory.address, - constructorArguments: [OwnableCallForwarder.address, Api3ServerV1OevExtension.address], - }); + const Api3ServerV1OevExtension = await deployments.get('Api3ServerV1OevExtension'); + await run('verify:verify', { + address: Api3ServerV1OevExtension.address, + constructorArguments: [ + AccessControlRegistry.address, + 'Api3ServerV1OevExtension admin', + OwnableCallForwarder.address, + Api3ServerV1.address, + ], + }); - const dapiName = ethers.encodeBytes32String('ETH/USD'); - const dappId = 1; - const api3ReaderProxyV1Metadata = '0x'; - const api3ReaderProxyV1ImplementationInitcode = ethers.solidityPacked( - ['bytes', 'bytes'], - [ - Api3ReaderProxyV1__factory.bytecode, - ethers.AbiCoder.defaultAbiCoder().encode( - ['address', 'bytes32', 'uint256'], - [Api3ServerV1OevExtension.address, dapiName, dappId] - ), - ] - ); - const api3ReaderProxyV1ImplementationAddress = ethers.getCreate2Address( - Api3ReaderProxyV1Factory.address, - ethers.keccak256(api3ReaderProxyV1Metadata), - ethers.keccak256(api3ReaderProxyV1ImplementationInitcode) - ); - await run('verify:verify', { - address: api3ReaderProxyV1ImplementationAddress, - constructorArguments: [Api3ServerV1OevExtension.address, dapiName, dappId], - }); + const Api3ReaderProxyV1Factory = await deployments.get('Api3ReaderProxyV1Factory'); + await run('verify:verify', { + address: Api3ReaderProxyV1Factory.address, + constructorArguments: [OwnableCallForwarder.address, Api3ServerV1OevExtension.address], + }); - const api3ReaderProxyV1Initcode = ethers.solidityPacked( - ['bytes', 'bytes'], - [ - ERC1967Proxy__factory.bytecode, - ethers.AbiCoder.defaultAbiCoder().encode( - ['address', 'bytes'], - [api3ReaderProxyV1ImplementationAddress, api3ReaderProxyV1Metadata] - ), - ] - ); - const api3ReaderProxyV1Address = ethers.getCreate2Address( - Api3ReaderProxyV1Factory.address, - ethers.keccak256(api3ReaderProxyV1Metadata), - ethers.keccak256(api3ReaderProxyV1Initcode) - ); - await run('verify:verify', { - address: api3ReaderProxyV1Address, - constructorArguments: [api3ReaderProxyV1ImplementationAddress, api3ReaderProxyV1Metadata], - }); + const dapiName = ethers.encodeBytes32String('ETH/USD'); + const dappId = 1; + const api3ReaderProxyV1Metadata = '0x'; + const api3ReaderProxyV1ImplementationInitcode = ethers.solidityPacked( + ['bytes', 'bytes'], + [ + Api3ReaderProxyV1__factory.bytecode, + ethers.AbiCoder.defaultAbiCoder().encode( + ['address', 'bytes32', 'uint256'], + [Api3ServerV1OevExtension.address, dapiName, dappId] + ), + ] + ); + const api3ReaderProxyV1ImplementationAddress = ethers.getCreate2Address( + Api3ReaderProxyV1Factory.address, + ethers.keccak256(api3ReaderProxyV1Metadata), + ethers.keccak256(api3ReaderProxyV1ImplementationInitcode) + ); + await run('verify:verify', { + address: api3ReaderProxyV1ImplementationAddress, + constructorArguments: [Api3ServerV1OevExtension.address, dapiName, dappId], + }); - if (chainsSupportedByMarket.includes(network.name)) { - const Api3MarketV2 = await deployments.get('Api3MarketV2'); - await run('verify:verify', { - address: Api3MarketV2.address, - constructorArguments: [ - OwnableCallForwarder.address, - Api3ReaderProxyV1Factory.address, - MAXIMUM_SUBSCRIPTION_QUEUE_LENGTH, - ], - }); + const api3ReaderProxyV1Initcode = ethers.solidityPacked( + ['bytes', 'bytes'], + [ + ERC1967Proxy__factory.bytecode, + ethers.AbiCoder.defaultAbiCoder().encode( + ['address', 'bytes'], + [api3ReaderProxyV1ImplementationAddress, api3ReaderProxyV1Metadata] + ), + ] + ); + const api3ReaderProxyV1Address = ethers.getCreate2Address( + Api3ReaderProxyV1Factory.address, + ethers.keccak256(api3ReaderProxyV1Metadata), + ethers.keccak256(api3ReaderProxyV1Initcode) + ); + await run('verify:verify', { + address: api3ReaderProxyV1Address, + constructorArguments: [api3ReaderProxyV1ImplementationAddress, api3ReaderProxyV1Metadata], + }); - const AirseekerRegistry = await deployments.get('AirseekerRegistry'); - await run('verify:verify', { - address: AirseekerRegistry.address, - constructorArguments: [Api3MarketV2.address, Api3ServerV1.address], - }); - } + const Api3MarketV2 = await deployments.get('Api3MarketV2'); + await run('verify:verify', { + address: Api3MarketV2.address, + constructorArguments: [ + OwnableCallForwarder.address, + Api3ReaderProxyV1Factory.address, + MAXIMUM_SUBSCRIPTION_QUEUE_LENGTH, + ], + }); - if (chainsSupportedByOevAuctions.includes(network.name)) { - const OevAuctionHouse = await deployments.get('OevAuctionHouse'); - await run('verify:verify', { - address: OevAuctionHouse.address, - constructorArguments: [AccessControlRegistry.address, 'OevAuctionHouse admin', OwnableCallForwarder.address], - }); - } - } - } else { - throw new Error(`${network.name} is not supported`); + const AirseekerRegistry = await deployments.get('AirseekerRegistry'); + await run('verify:verify', { + address: AirseekerRegistry.address, + constructorArguments: [Api3MarketV2.address, Api3ServerV1.address], + }); + + if (chainsSupportedByOevAuctions.includes(network.name)) { + const OevAuctionHouse = await deployments.get('OevAuctionHouse'); + await run('verify:verify', { + address: OevAuctionHouse.address, + constructorArguments: [AccessControlRegistry.address, 'OevAuctionHouse admin', OwnableCallForwarder.address], + }); } }; module.exports.tags = ['verify']; diff --git a/scripts/check-deployment-config.ts b/scripts/check-deployment-config.ts index 38bb7398..5ca55b38 100644 --- a/scripts/check-deployment-config.ts +++ b/scripts/check-deployment-config.ts @@ -1,35 +1,18 @@ -import { - chainsSupportedByManagerMultisig, - chainsSupportedByDapis, - chainsSupportedByMarket, - chainsSupportedByOevAuctions, -} from '../data/chain-support.json'; +import { chainsSupportedByMarket, chainsSupportedByOevAuctions } from '../data/chain-support.json'; import { CHAINS } from '../src/generated/chains'; function main() { const chainAliases = new Set(CHAINS.map((chain) => chain.alias)); - [chainsSupportedByManagerMultisig, chainsSupportedByDapis, chainsSupportedByMarket, chainsSupportedByOevAuctions].map( - (supportedChainAliases) => { - supportedChainAliases.map((supportedChainAlias) => { - if (!chainAliases.has(supportedChainAlias)) { - throw new Error(`Supported chain with alias ${supportedChainAlias} does not exist`); - } - }); - } - ); - chainsSupportedByDapis.map((chainSupportedByDapis) => { - if (!chainsSupportedByManagerMultisig.includes(chainSupportedByDapis)) { - throw new Error(`dAPI-supported chain with alias ${chainSupportedByDapis} is not manager multisig-supported`); - } - }); - chainsSupportedByMarket.map((chainSupportedByMarket) => { - if (!chainsSupportedByDapis.includes(chainSupportedByMarket)) { - throw new Error(`Market-supported chain with alias ${chainSupportedByMarket} is not dAPI-supported`); - } + [chainsSupportedByMarket, chainsSupportedByOevAuctions].forEach((supportedChainAliases) => { + supportedChainAliases.forEach((supportedChainAlias) => { + if (!chainAliases.has(supportedChainAlias)) { + throw new Error(`Supported chain with alias ${supportedChainAlias} does not exist`); + } + }); }); - chainsSupportedByOevAuctions.map((chainSupportedByOevAuctions) => { - if (!chainsSupportedByDapis.includes(chainSupportedByOevAuctions)) { - throw new Error(`OEV auction-supported chain with alias ${chainSupportedByOevAuctions} is not dAPI-supported`); + chainsSupportedByOevAuctions.forEach((chainAlias) => { + if (!chainsSupportedByMarket.includes(chainAlias)) { + throw new Error(`OEV auction-supported chain with alias ${chainAlias} is not market-supported`); } }); } diff --git a/scripts/constants.ts b/scripts/constants.ts index 86df759b..740fd274 100644 --- a/scripts/constants.ts +++ b/scripts/constants.ts @@ -11,7 +11,7 @@ export const goAsyncOptions: GoAsyncOptions = { }, }; -export const skippedChainAliasesInOevAuctionHouseNativeCurrencyRateValidation = []; +export const skippedChainAliasesInOevAuctionHouseNativeCurrencyRateValidation: string[] = []; export const skippedChainAliasesInOwnableCallForwarderConstructorArgumentVerification = [ 'apechain', diff --git a/scripts/src/deployment-addresses.ts b/scripts/src/deployment-addresses.ts index 03d9f8f8..331bd35d 100644 --- a/scripts/src/deployment-addresses.ts +++ b/scripts/src/deployment-addresses.ts @@ -3,12 +3,7 @@ import { join } from 'node:path'; import type { AddressLike } from 'ethers'; -import { - chainsSupportedByManagerMultisig, - chainsSupportedByDapis, - chainsSupportedByMarket, - chainsSupportedByOevAuctions, -} from '../../data/chain-support.json'; +import { chainsSupportedByMarket, chainsSupportedByOevAuctions } from '../../data/chain-support.json'; import { CHAINS } from '../../src/generated/chains'; function getDeploymentAddresses() { @@ -23,21 +18,23 @@ function getDeploymentAddresses() { OevAuctionHouse: {}, }; - const networks = new Set([ - ...chainsSupportedByManagerMultisig, - ...chainsSupportedByDapis, - ...chainsSupportedByMarket, - ...chainsSupportedByOevAuctions, - ]); + const networks = new Set([...chainsSupportedByMarket, ...chainsSupportedByOevAuctions]); for (const network of networks) { const chainId = CHAINS.find((chain) => chain.alias === network)?.id; const contractNames = [ - ...(chainsSupportedByManagerMultisig.includes(network) ? ['GnosisSafeWithoutProxy', 'OwnableCallForwarder'] : []), - ...(chainsSupportedByDapis.includes(network) - ? ['AccessControlRegistry', 'Api3ServerV1', 'Api3ServerV1OevExtension', 'Api3ReaderProxyV1Factory'] + ...(chainsSupportedByMarket.includes(network) + ? [ + 'GnosisSafeWithoutProxy', + 'OwnableCallForwarder', + 'AccessControlRegistry', + 'Api3ServerV1', + 'Api3ServerV1OevExtension', + 'Api3ReaderProxyV1Factory', + 'AirseekerRegistry', + 'Api3MarketV2', + ] : []), - ...(chainsSupportedByMarket.includes(network) ? ['AirseekerRegistry', 'Api3MarketV2'] : []), ...(chainsSupportedByOevAuctions.includes(network) ? ['OevAuctionHouse'] : []), ]; for (const contractName of contractNames) { diff --git a/scripts/survey-roles.ts b/scripts/survey-roles.ts index 354100b7..f2f7947f 100644 --- a/scripts/survey-roles.ts +++ b/scripts/survey-roles.ts @@ -8,7 +8,7 @@ import { join } from 'node:path'; import { go } from '@api3/promise-utils'; import { config, ethers } from 'hardhat'; -import { chainsSupportedByManagerMultisig, chainsSupportedByDapis } from '../data/chain-support.json'; +import { chainsSupportedByMarket } from '../data/chain-support.json'; import { CHAINS } from '../src/index'; import { goAsyncOptions } from './constants'; @@ -16,7 +16,7 @@ import { goAsyncOptions } from './constants'; const MAXIMUM_GETLOGS_BLOCK_RANGE = 50_000; async function surveyRoles(network: string) { - if (!chainsSupportedByDapis.includes(network)) { + if (!chainsSupportedByMarket.includes(network)) { return; } const provider = new ethers.JsonRpcProvider((config.networks[network] as any).url); @@ -82,7 +82,7 @@ async function surveyRoles(network: string) { } async function main() { - const networks = process.env.NETWORK ? [process.env.NETWORK] : chainsSupportedByManagerMultisig; + const networks = process.env.NETWORK ? [process.env.NETWORK] : chainsSupportedByMarket; const erroredMainnets: string[] = []; const erroredTestnets: string[] = []; diff --git a/scripts/validate-deployments.ts b/scripts/validate-deployments.ts index 1264875c..b9363b0f 100644 --- a/scripts/validate-deployments.ts +++ b/scripts/validate-deployments.ts @@ -5,12 +5,7 @@ import { go } from '@api3/promise-utils'; import { config, ethers } from 'hardhat'; import * as auctioneerMetadata from '../data/auctioneer-metadata.json'; -import { - chainsSupportedByManagerMultisig, - chainsSupportedByDapis, - chainsSupportedByMarket, - chainsSupportedByOevAuctions, -} from '../data/chain-support.json'; +import { chainsSupportedByMarket, chainsSupportedByOevAuctions } from '../data/chain-support.json'; import { dapiManagementMerkleRootSigners, dapiPricingMerkleRootSigners, @@ -21,6 +16,7 @@ import type { AccessControlRegistry, Api3MarketV2, Api3ReaderProxyV1Factory, + Chain, GnosisSafeWithoutProxy, IApi3ReaderProxy, OevAuctionHouse, @@ -37,7 +33,7 @@ const dappId = 1; const api3ReaderProxyV1Metadata = '0x'; async function validateDeployments(network: string) { - if (!chainsSupportedByManagerMultisig.includes(network)) { + if (!chainsSupportedByMarket.includes(network)) { return; } const provider = new ethers.JsonRpcProvider((config.networks[network] as any).url); @@ -103,363 +99,341 @@ async function validateDeployments(network: string) { `${network} OwnableCallForwarder owner ${ethers.getAddress(goFetchOwnableCallForwarderOwner.data)} is not the same as the manager multisig address ${ethers.getAddress(gnosisSafeWithoutProxyAddress)}` ); } - if (chainsSupportedByDapis.includes(network)) { - // Validate that the Api3ReaderProxyV1Factory owner is OwnableCallForwarder - const { address: api3ReaderProxyV1FactoryAddress, abi: api3ReaderProxyV1FactoryAbi } = JSON.parse( - fs.readFileSync(join('deployments', network, `Api3ReaderProxyV1Factory.json`), 'utf8') + // Validate that the Api3ReaderProxyV1Factory owner is OwnableCallForwarder + const { address: api3ReaderProxyV1FactoryAddress, abi: api3ReaderProxyV1FactoryAbi } = JSON.parse( + fs.readFileSync(join('deployments', network, `Api3ReaderProxyV1Factory.json`), 'utf8') + ); + const api3ReaderProxyV1Factory = new ethers.Contract( + api3ReaderProxyV1FactoryAddress, + api3ReaderProxyV1FactoryAbi, + provider + ) as unknown as Api3ReaderProxyV1Factory; + const goFetchApi3ReaderProxyV1FactoryOwner = await go(async () => api3ReaderProxyV1Factory.owner(), goAsyncOptions); + if (!goFetchApi3ReaderProxyV1FactoryOwner.success || !goFetchApi3ReaderProxyV1FactoryOwner.data) { + throw new Error(`${network} Api3ReaderProxyV1Factory owner could not be fetched`); + } + if (ethers.getAddress(goFetchApi3ReaderProxyV1FactoryOwner.data) !== ethers.getAddress(ownableCallForwarderAddress)) { + throw new Error( + `${network} Api3ReaderProxyV1Factory owner ${ethers.getAddress(goFetchApi3ReaderProxyV1FactoryOwner.data)} is not the same as the OwnableCallForwarder address ${ethers.getAddress(ownableCallForwarderAddress)}` ); - const api3ReaderProxyV1Factory = new ethers.Contract( - api3ReaderProxyV1FactoryAddress, - api3ReaderProxyV1FactoryAbi, - provider - ) as unknown as Api3ReaderProxyV1Factory; - const goFetchApi3ReaderProxyV1FactoryOwner = await go(async () => api3ReaderProxyV1Factory.owner(), goAsyncOptions); - if (!goFetchApi3ReaderProxyV1FactoryOwner.success || !goFetchApi3ReaderProxyV1FactoryOwner.data) { - throw new Error(`${network} Api3ReaderProxyV1Factory owner could not be fetched`); - } - if ( - ethers.getAddress(goFetchApi3ReaderProxyV1FactoryOwner.data) !== ethers.getAddress(ownableCallForwarderAddress) - ) { - throw new Error( - `${network} Api3ReaderProxyV1Factory owner ${ethers.getAddress(goFetchApi3ReaderProxyV1FactoryOwner.data)} is not the same as the OwnableCallForwarder address ${ethers.getAddress(ownableCallForwarderAddress)}` - ); - } + } - if (chainsSupportedByMarket.includes(network)) { - // Validate that the Api3MarketV2 AirseekerRegistry address belongs to AirseekerRegistry - const { address: api3MarketV2Address, abi: api3MarketV2Abi } = JSON.parse( - fs.readFileSync(join('deployments', network, `Api3MarketV2.json`), 'utf8') - ); - const api3MarketV2 = new ethers.Contract( - api3MarketV2Address, - api3MarketV2Abi, - provider - ) as unknown as Api3MarketV2; - const goFetchApi3MarketV2AirseekerRegistry = await go( - async () => api3MarketV2.airseekerRegistry(), - goAsyncOptions - ); - if (!goFetchApi3MarketV2AirseekerRegistry.success || !goFetchApi3MarketV2AirseekerRegistry.data) { - throw new Error(`${network} Api3MarketV2 AirseekerRegistry address could not be fetched`); - } - const { address: airseekerRegistryAddress } = JSON.parse( - fs.readFileSync(join('deployments', network, `AirseekerRegistry.json`), 'utf8') - ); - if ( - ethers.getAddress(goFetchApi3MarketV2AirseekerRegistry.data) !== ethers.getAddress(airseekerRegistryAddress) - ) { - throw new Error( - `${network} Api3MarketV2 AirseekerRegistry address ${ethers.getAddress(goFetchApi3MarketV2AirseekerRegistry.data)} is not the same as the AirseekerRegistry address ${airseekerRegistryAddress}` - ); - } + // Validate that the Api3MarketV2 AirseekerRegistry address belongs to AirseekerRegistry + const { address: api3MarketV2Address, abi: api3MarketV2Abi } = JSON.parse( + fs.readFileSync(join('deployments', network, `Api3MarketV2.json`), 'utf8') + ); + const api3MarketV2 = new ethers.Contract(api3MarketV2Address, api3MarketV2Abi, provider) as unknown as Api3MarketV2; + const goFetchApi3MarketV2AirseekerRegistry = await go(async () => api3MarketV2.airseekerRegistry(), goAsyncOptions); + if (!goFetchApi3MarketV2AirseekerRegistry.success || !goFetchApi3MarketV2AirseekerRegistry.data) { + throw new Error(`${network} Api3MarketV2 AirseekerRegistry address could not be fetched`); + } + const { address: airseekerRegistryAddress } = JSON.parse( + fs.readFileSync(join('deployments', network, `AirseekerRegistry.json`), 'utf8') + ); + if (ethers.getAddress(goFetchApi3MarketV2AirseekerRegistry.data) !== ethers.getAddress(airseekerRegistryAddress)) { + throw new Error( + `${network} Api3MarketV2 AirseekerRegistry address ${ethers.getAddress(goFetchApi3MarketV2AirseekerRegistry.data)} is not the same as the AirseekerRegistry address ${airseekerRegistryAddress}` + ); + } - // Validate that Api3MarketV2 dAPI management, dAPI pricing and Signed API URL MT hash signers are set - const goFetchApi3MarketV2DapiManagementMerkleRootSignersHash = await go( - async () => - api3MarketV2.hashTypeToSignersHash( - ethers.solidityPackedKeccak256(['string'], ['dAPI management Merkle root']) - ), - goAsyncOptions - ); - if ( - !goFetchApi3MarketV2DapiManagementMerkleRootSignersHash.success || - !goFetchApi3MarketV2DapiManagementMerkleRootSignersHash.data - ) { - throw new Error(`${network} Api3MarketV2 dAPI management Merkle root signers hash could not be fetched`); - } - if (goFetchApi3MarketV2DapiManagementMerkleRootSignersHash.data === ethers.ZeroHash) { - throw new Error(`${network} Api3MarketV2 dAPI management Merkle root signers are not set`); - } - if ( - goFetchApi3MarketV2DapiManagementMerkleRootSignersHash.data !== - ethers.solidityPackedKeccak256(['address[]'], [dapiManagementMerkleRootSigners]) - ) { - throw new Error(`${network} Api3MarketV2 dAPI management Merkle root signers are set incorrectly`); - } - const goFetchApi3MarketV2DapiPricingMerkleRootSignersHash = await go( - async () => - api3MarketV2.hashTypeToSignersHash(ethers.solidityPackedKeccak256(['string'], ['dAPI pricing Merkle root'])), - goAsyncOptions - ); - if ( - !goFetchApi3MarketV2DapiPricingMerkleRootSignersHash.success || - !goFetchApi3MarketV2DapiPricingMerkleRootSignersHash.data - ) { - throw new Error(`${network} Api3MarketV2 dAPI pricing Merkle root signers hash could not be fetched`); - } - if (goFetchApi3MarketV2DapiPricingMerkleRootSignersHash.data === ethers.ZeroHash) { - throw new Error(`${network} Api3MarketV2 dAPI pricing Merkle root signers are not set`); - } - if ( - goFetchApi3MarketV2DapiPricingMerkleRootSignersHash.data !== - ethers.solidityPackedKeccak256(['address[]'], [dapiPricingMerkleRootSigners]) - ) { - throw new Error(`${network} Api3MarketV2 dAPI pricing Merkle root signers are set incorrectly`); - } - const goFetchApi3MarketV2SignedApiUrlMerkleRootSignersHash = await go( - async () => - api3MarketV2.hashTypeToSignersHash( - ethers.solidityPackedKeccak256(['string'], ['Signed API URL Merkle root']) - ), - goAsyncOptions - ); - if ( - !goFetchApi3MarketV2SignedApiUrlMerkleRootSignersHash.success || - !goFetchApi3MarketV2SignedApiUrlMerkleRootSignersHash.data - ) { - throw new Error(`${network} Api3MarketV2 Signed API URL Merkle root signers hash could not be fetched`); - } - if (goFetchApi3MarketV2SignedApiUrlMerkleRootSignersHash.data === ethers.ZeroHash) { - throw new Error(`${network} Api3MarketV2 Signed API URL Merkle root signers are not set`); - } - if ( - goFetchApi3MarketV2SignedApiUrlMerkleRootSignersHash.data !== - ethers.solidityPackedKeccak256(['address[]'], [signedApiUrlMerkleRootSigners]) - ) { - throw new Error(`${network} Api3MarketV2 Signed API URL Merkle root signers are set incorrectly`); - } + // Validate that Api3MarketV2 dAPI management, dAPI pricing and Signed API URL MT hash signers are set + const goFetchApi3MarketV2DapiManagementMerkleRootSignersHash = await go( + async () => + api3MarketV2.hashTypeToSignersHash(ethers.solidityPackedKeccak256(['string'], ['dAPI management Merkle root'])), + goAsyncOptions + ); + if ( + !goFetchApi3MarketV2DapiManagementMerkleRootSignersHash.success || + !goFetchApi3MarketV2DapiManagementMerkleRootSignersHash.data + ) { + throw new Error(`${network} Api3MarketV2 dAPI management Merkle root signers hash could not be fetched`); + } + if (goFetchApi3MarketV2DapiManagementMerkleRootSignersHash.data === ethers.ZeroHash) { + throw new Error(`${network} Api3MarketV2 dAPI management Merkle root signers are not set`); + } + if ( + goFetchApi3MarketV2DapiManagementMerkleRootSignersHash.data !== + ethers.solidityPackedKeccak256(['address[]'], [dapiManagementMerkleRootSigners]) + ) { + throw new Error(`${network} Api3MarketV2 dAPI management Merkle root signers are set incorrectly`); + } + const goFetchApi3MarketV2DapiPricingMerkleRootSignersHash = await go( + async () => + api3MarketV2.hashTypeToSignersHash(ethers.solidityPackedKeccak256(['string'], ['dAPI pricing Merkle root'])), + goAsyncOptions + ); + if ( + !goFetchApi3MarketV2DapiPricingMerkleRootSignersHash.success || + !goFetchApi3MarketV2DapiPricingMerkleRootSignersHash.data + ) { + throw new Error(`${network} Api3MarketV2 dAPI pricing Merkle root signers hash could not be fetched`); + } + if (goFetchApi3MarketV2DapiPricingMerkleRootSignersHash.data === ethers.ZeroHash) { + throw new Error(`${network} Api3MarketV2 dAPI pricing Merkle root signers are not set`); + } + if ( + goFetchApi3MarketV2DapiPricingMerkleRootSignersHash.data !== + ethers.solidityPackedKeccak256(['address[]'], [dapiPricingMerkleRootSigners]) + ) { + throw new Error(`${network} Api3MarketV2 dAPI pricing Merkle root signers are set incorrectly`); + } + const goFetchApi3MarketV2SignedApiUrlMerkleRootSignersHash = await go( + async () => + api3MarketV2.hashTypeToSignersHash(ethers.solidityPackedKeccak256(['string'], ['Signed API URL Merkle root'])), + goAsyncOptions + ); + if ( + !goFetchApi3MarketV2SignedApiUrlMerkleRootSignersHash.success || + !goFetchApi3MarketV2SignedApiUrlMerkleRootSignersHash.data + ) { + throw new Error(`${network} Api3MarketV2 Signed API URL Merkle root signers hash could not be fetched`); + } + if (goFetchApi3MarketV2SignedApiUrlMerkleRootSignersHash.data === ethers.ZeroHash) { + throw new Error(`${network} Api3MarketV2 Signed API URL Merkle root signers are not set`); + } + if ( + goFetchApi3MarketV2SignedApiUrlMerkleRootSignersHash.data !== + ethers.solidityPackedKeccak256(['address[]'], [signedApiUrlMerkleRootSigners]) + ) { + throw new Error(`${network} Api3MarketV2 Signed API URL Merkle root signers are set incorrectly`); + } - // Validate that Api3MarketV2 is a dAPI name setter - const rootRole = ethers.solidityPackedKeccak256(['address'], [ownableCallForwarderAddress]); - const api3ServerV1AdminRole = ethers.solidityPackedKeccak256( - ['bytes32', 'bytes32'], - [rootRole, ethers.solidityPackedKeccak256(['string'], ['Api3ServerV1 admin'])] - ); - const dapiNameSetterRole = ethers.solidityPackedKeccak256( - ['bytes32', 'bytes32'], - [api3ServerV1AdminRole, ethers.solidityPackedKeccak256(['string'], ['dAPI name setter'])] - ); - const { address: accessControlRegistryAddress, abi: accessControlRegistryAbi } = JSON.parse( - fs.readFileSync(join('deployments', network, `AccessControlRegistry.json`), 'utf8') - ); - const accessControlRegistry = new ethers.Contract( - accessControlRegistryAddress, - accessControlRegistryAbi, - provider - ) as unknown as AccessControlRegistry; - const goFetchApi3MarketV2DapiNameSetterRoleStatus = await go( - async () => accessControlRegistry.hasRole(dapiNameSetterRole, api3MarketV2Address), - goAsyncOptions - ); - if (!goFetchApi3MarketV2DapiNameSetterRoleStatus.success) { - throw new Error(`${network} Api3MarketV2 dAPI name setter role status could not be fetched`); - } - if (!goFetchApi3MarketV2DapiNameSetterRoleStatus.data) { - throw new Error(`${network} Api3MarketV2 does not have the dAPI name setter role`); - } + // Validate that Api3MarketV2 is a dAPI name setter + const rootRole = ethers.solidityPackedKeccak256(['address'], [ownableCallForwarderAddress]); + const api3ServerV1AdminRole = ethers.solidityPackedKeccak256( + ['bytes32', 'bytes32'], + [rootRole, ethers.solidityPackedKeccak256(['string'], ['Api3ServerV1 admin'])] + ); + const dapiNameSetterRole = ethers.solidityPackedKeccak256( + ['bytes32', 'bytes32'], + [api3ServerV1AdminRole, ethers.solidityPackedKeccak256(['string'], ['dAPI name setter'])] + ); + const { address: accessControlRegistryAddress, abi: accessControlRegistryAbi } = JSON.parse( + fs.readFileSync(join('deployments', network, `AccessControlRegistry.json`), 'utf8') + ); + const accessControlRegistry = new ethers.Contract( + accessControlRegistryAddress, + accessControlRegistryAbi, + provider + ) as unknown as AccessControlRegistry; + const goFetchApi3MarketV2DapiNameSetterRoleStatus = await go( + async () => accessControlRegistry.hasRole(dapiNameSetterRole, api3MarketV2Address), + goAsyncOptions + ); + if (!goFetchApi3MarketV2DapiNameSetterRoleStatus.success) { + throw new Error(`${network} Api3MarketV2 dAPI name setter role status could not be fetched`); + } + if (!goFetchApi3MarketV2DapiNameSetterRoleStatus.data) { + throw new Error(`${network} Api3MarketV2 does not have the dAPI name setter role`); + } - // Validate that auction resolvers have the auctioneer role - const api3ServerV1OevExtensionAdminRole = ethers.solidityPackedKeccak256( - ['bytes32', 'bytes32'], - [rootRole, ethers.solidityPackedKeccak256(['string'], ['Api3ServerV1OevExtension admin'])] - ); - const auctioneerRole = ethers.solidityPackedKeccak256( - ['bytes32', 'bytes32'], - [api3ServerV1OevExtensionAdminRole, ethers.solidityPackedKeccak256(['string'], ['Auctioneer'])] - ); + // Validate that auction resolvers have the auctioneer role + const api3ServerV1OevExtensionAdminRole = ethers.solidityPackedKeccak256( + ['bytes32', 'bytes32'], + [rootRole, ethers.solidityPackedKeccak256(['string'], ['Api3ServerV1OevExtension admin'])] + ); + const auctioneerRole = ethers.solidityPackedKeccak256( + ['bytes32', 'bytes32'], + [api3ServerV1OevExtensionAdminRole, ethers.solidityPackedKeccak256(['string'], ['Auctioneer'])] + ); - const goFetchApi3ServerV1OevExtensionAuctioneerRoleStatus = await go( - async () => - accessControlRegistry.multicall.staticCall( - auctioneerMetadata['auction-resolvers'].map((auctioneerResolverAddress) => - accessControlRegistry.interface.encodeFunctionData('hasRole', [auctioneerRole, auctioneerResolverAddress]) - ) - ), - goAsyncOptions - ); - if (!goFetchApi3ServerV1OevExtensionAuctioneerRoleStatus.success) { - throw new Error(`${network} Api3ServerV1OevExtension auctioneer role status could not be fetched`); - } - if ( - !goFetchApi3ServerV1OevExtensionAuctioneerRoleStatus.data.every( - (auctioneerRoleStatus) => auctioneerRoleStatus !== ethers.ZeroHash + const goFetchApi3ServerV1OevExtensionAuctioneerRoleStatus = await go( + async () => + accessControlRegistry.multicall.staticCall( + auctioneerMetadata['auction-resolvers'].map((auctioneerResolverAddress) => + accessControlRegistry.interface.encodeFunctionData('hasRole', [auctioneerRole, auctioneerResolverAddress]) ) - ) { - throw new Error( - `${network} (${auctioneerMetadata['auction-resolvers']}) Api3ServerV1OevExtension auctioneer role statuses are (${goFetchApi3ServerV1OevExtensionAuctioneerRoleStatus.data.map((auctioneerRoleStatus) => (auctioneerRoleStatus === ethers.ZeroHash ? false : true))})` - ); - } - } + ), + goAsyncOptions + ); + if (!goFetchApi3ServerV1OevExtensionAuctioneerRoleStatus.success) { + throw new Error(`${network} Api3ServerV1OevExtension auctioneer role status could not be fetched`); + } + if ( + !goFetchApi3ServerV1OevExtensionAuctioneerRoleStatus.data.every( + (auctioneerRoleStatus) => auctioneerRoleStatus !== ethers.ZeroHash + ) + ) { + throw new Error( + `${network} (${auctioneerMetadata['auction-resolvers']}) Api3ServerV1OevExtension auctioneer role statuses are (${goFetchApi3ServerV1OevExtensionAuctioneerRoleStatus.data.map((auctioneerRoleStatus) => (auctioneerRoleStatus === ethers.ZeroHash ? false : true))})` + ); + } - if (chainsSupportedByOevAuctions.includes(network)) { - // Validate that auction resolvers and auction cops have the auctioneer role - const { address: accessControlRegistryAddress, abi: accessControlRegistryAbi } = JSON.parse( - fs.readFileSync(join('deployments', network, `AccessControlRegistry.json`), 'utf8') - ); - const accessControlRegistry = new ethers.Contract( - accessControlRegistryAddress, - accessControlRegistryAbi, - provider - ) as unknown as AccessControlRegistry; - const rootRole = ethers.solidityPackedKeccak256(['address'], [ownableCallForwarderAddress]); - const api3ServerV1OevExtensionAdminRole = ethers.solidityPackedKeccak256( - ['bytes32', 'bytes32'], - [rootRole, ethers.solidityPackedKeccak256(['string'], ['Api3ServerV1OevExtension admin'])] - ); - const auctioneerRole = ethers.solidityPackedKeccak256( - ['bytes32', 'bytes32'], - [api3ServerV1OevExtensionAdminRole, ethers.solidityPackedKeccak256(['string'], ['Auctioneer'])] - ); + if (chainsSupportedByOevAuctions.includes(network)) { + // Validate that auction resolvers and auction cops have the auctioneer role + const { address: accessControlRegistryAddress, abi: accessControlRegistryAbi } = JSON.parse( + fs.readFileSync(join('deployments', network, `AccessControlRegistry.json`), 'utf8') + ); + const accessControlRegistry = new ethers.Contract( + accessControlRegistryAddress, + accessControlRegistryAbi, + provider + ) as unknown as AccessControlRegistry; + const rootRole = ethers.solidityPackedKeccak256(['address'], [ownableCallForwarderAddress]); + const api3ServerV1OevExtensionAdminRole = ethers.solidityPackedKeccak256( + ['bytes32', 'bytes32'], + [rootRole, ethers.solidityPackedKeccak256(['string'], ['Api3ServerV1OevExtension admin'])] + ); + const auctioneerRole = ethers.solidityPackedKeccak256( + ['bytes32', 'bytes32'], + [api3ServerV1OevExtensionAdminRole, ethers.solidityPackedKeccak256(['string'], ['Auctioneer'])] + ); - const goFetchApi3ServerV1OevExtensionAuctioneerRoleStatus = await go( - async () => - accessControlRegistry.multicall.staticCall( - [...auctioneerMetadata['auction-resolvers'], ...auctioneerMetadata['auction-cops']].map( - (auctioneerResolverAddress) => - accessControlRegistry.interface.encodeFunctionData('hasRole', [ - auctioneerRole, - auctioneerResolverAddress, - ]) - ) - ), - goAsyncOptions + const goFetchApi3ServerV1OevExtensionAuctioneerRoleStatus = await go( + async () => + accessControlRegistry.multicall.staticCall( + [...auctioneerMetadata['auction-resolvers'], ...auctioneerMetadata['auction-cops']].map( + (auctioneerResolverAddress) => + accessControlRegistry.interface.encodeFunctionData('hasRole', [auctioneerRole, auctioneerResolverAddress]) + ) + ), + goAsyncOptions + ); + if (!goFetchApi3ServerV1OevExtensionAuctioneerRoleStatus.success) { + throw new Error(`${network} Api3ServerV1OevExtension auctioneer role status could not be fetched`); + } + if ( + !goFetchApi3ServerV1OevExtensionAuctioneerRoleStatus.data.every( + (auctioneerRoleStatus) => auctioneerRoleStatus !== ethers.ZeroHash + ) + ) { + throw new Error( + `${network} (${[...auctioneerMetadata['auction-resolvers'], ...auctioneerMetadata['auction-cops']]}) Api3ServerV1OevExtension auctioneer role statuses are (${goFetchApi3ServerV1OevExtensionAuctioneerRoleStatus.data.map((auctioneerRoleStatus) => (auctioneerRoleStatus === ethers.ZeroHash ? false : true))})` ); - if (!goFetchApi3ServerV1OevExtensionAuctioneerRoleStatus.success) { - throw new Error(`${network} Api3ServerV1OevExtension auctioneer role status could not be fetched`); - } - if ( - !goFetchApi3ServerV1OevExtensionAuctioneerRoleStatus.data.every( - (auctioneerRoleStatus) => auctioneerRoleStatus !== ethers.ZeroHash - ) - ) { - throw new Error( - `${network} (${[...auctioneerMetadata['auction-resolvers'], ...auctioneerMetadata['auction-cops']]}) Api3ServerV1OevExtension auctioneer role statuses are (${goFetchApi3ServerV1OevExtensionAuctioneerRoleStatus.data.map((auctioneerRoleStatus) => (auctioneerRoleStatus === ethers.ZeroHash ? false : true))})` - ); - } + } - // Validate that collateral rate proxy is set - const { address: oevAuctionHouseAddress, abi: oevAuctionHouseAbi } = JSON.parse( - fs.readFileSync(join('deployments', network, `OevAuctionHouse.json`), 'utf8') - ); - const oevAuctionHouse = new ethers.Contract( - oevAuctionHouseAddress, - oevAuctionHouseAbi, - provider - ) as unknown as OevAuctionHouse; + // Validate that collateral rate proxy is set + const { address: oevAuctionHouseAddress, abi: oevAuctionHouseAbi } = JSON.parse( + fs.readFileSync(join('deployments', network, `OevAuctionHouse.json`), 'utf8') + ); + const oevAuctionHouse = new ethers.Contract( + oevAuctionHouseAddress, + oevAuctionHouseAbi, + provider + ) as unknown as OevAuctionHouse; - const goFetchCollateralRateProxyAddress = await go( - async () => oevAuctionHouse.collateralRateProxy(), - goAsyncOptions + const goFetchCollateralRateProxyAddress = await go( + async () => oevAuctionHouse.collateralRateProxy(), + goAsyncOptions + ); + if (!goFetchCollateralRateProxyAddress.success) { + throw new Error('OevAuctionHouse collateral rate proxy address could not be fetched'); + } + const oevAuctionChainId = CHAINS.find((chain) => chain.alias === network)!.id; + const ethUsdRateReaderProxyV1Address = computeApi3ReaderProxyV1Address( + oevAuctionChainId, + 'ETH/USD', + dappId, + api3ReaderProxyV1Metadata + ); + if (goFetchCollateralRateProxyAddress.data !== ethUsdRateReaderProxyV1Address) { + throw new Error( + `OevAuctionHouse collateral rate proxy address is ${goFetchCollateralRateProxyAddress.data} while it should have been ${ethUsdRateReaderProxyV1Address}` ); - if (!goFetchCollateralRateProxyAddress.success) { - throw new Error('OevAuctionHouse collateral rate proxy address could not be fetched'); + } + + // Validate that native currency rate proxies are set + const chainsWithNativeRateProxies = chainsSupportedByMarket.reduce((acc, chainAlias) => { + const chain = CHAINS.find((chain) => chain.alias === chainAlias)!; + if (!chain.testnet) { + acc.push(chain); } - const oevAuctionChainId = CHAINS.find((chain) => chain.alias === network)!.id; - const ethUsdRateReaderProxyV1Address = computeApi3ReaderProxyV1Address( + return acc; + }, [] as Chain[]); + const goFetchNativeCurrencyRateProxyAddresses = await go( + async () => + oevAuctionHouse.multicall.staticCall( + chainsWithNativeRateProxies.map((chain) => + oevAuctionHouse.interface.encodeFunctionData('chainIdToNativeCurrencyRateProxy', [chain.id]) + ) + ), + goAsyncOptions + ); + if (!goFetchNativeCurrencyRateProxyAddresses.success) { + throw new Error('OevAuctionHouse native currency rate proxy addresses could not be fetched'); + } + const nativeCurrencyRateProxyAddresses = goFetchNativeCurrencyRateProxyAddresses.data.map((returndata) => + ethers.AbiCoder.defaultAbiCoder().decode(['address'], returndata) + ); + const errorMessages = chainsWithNativeRateProxies.reduce((acc, chain, ind) => { + const dapiName = `${chainSymbolToTicker[chain.symbol] ?? chain.symbol}/USD`; + const api3ReaderProxyV1Address = computeApi3ReaderProxyV1Address( oevAuctionChainId, - 'ETH/USD', + dapiName, dappId, api3ReaderProxyV1Metadata ); - if (goFetchCollateralRateProxyAddress.data !== ethUsdRateReaderProxyV1Address) { - throw new Error( - `OevAuctionHouse collateral rate proxy address is ${goFetchCollateralRateProxyAddress.data} while it should have been ${ethUsdRateReaderProxyV1Address}` - ); - } - - // Validate that native currency rate proxies are set - const chainsWithNativeRateProxies = chainsSupportedByMarket.reduce((acc, chainAlias) => { - const chain = CHAINS.find((chain) => chain.alias === chainAlias)!; - if (!chain.testnet) { - acc.push(chain); - } - return acc; - }, [] as any[]); - const goFetchNativeCurrencyRateProxyAddresses = await go( - async () => - oevAuctionHouse.multicall.staticCall( - chainsWithNativeRateProxies.map((chain) => - oevAuctionHouse.interface.encodeFunctionData('chainIdToNativeCurrencyRateProxy', [chain.id]) - ) - ), - goAsyncOptions - ); - if (!goFetchNativeCurrencyRateProxyAddresses.success) { - throw new Error('OevAuctionHouse native currency rate proxy addresses could not be fetched'); - } - const nativeCurrencyRateProxyAddresses = goFetchNativeCurrencyRateProxyAddresses.data.map((returndata) => - ethers.AbiCoder.defaultAbiCoder().decode(['address'], returndata) - ); - const errorMessages = chainsWithNativeRateProxies.reduce((acc, chain, ind) => { - const dapiName = `${chainSymbolToTicker[chain.symbol] ?? chain.symbol}/USD`; - const api3ReaderProxyV1Address = computeApi3ReaderProxyV1Address( - oevAuctionChainId, - dapiName, - dappId, - api3ReaderProxyV1Metadata + if (nativeCurrencyRateProxyAddresses[ind]!.toString() !== api3ReaderProxyV1Address) { + acc.push( + `${chain.alias} OevAuctionHouse native currency rate proxy address is ${nativeCurrencyRateProxyAddresses[ind]} while it should have been ${api3ReaderProxyV1Address}` ); - if (nativeCurrencyRateProxyAddresses[ind]!.toString() !== api3ReaderProxyV1Address) { - acc.push( - `${chain.alias} OevAuctionHouse native currency rate proxy address is ${nativeCurrencyRateProxyAddresses[ind]} while it should have been ${api3ReaderProxyV1Address}` - ); - } - return acc; - }, [] as string[]); - if (errorMessages.length > 0) { - // eslint-disable-next-line unicorn/error-message - throw new Error(errorMessages.join('\n')); } + return acc; + }, [] as string[]); + if (errorMessages.length > 0) { + // eslint-disable-next-line unicorn/error-message + throw new Error(errorMessages.join('\n')); + } - // Validate that used proxies all serve fresh values - const { abi: api3ReaderProxyAbi } = JSON.parse( - fs.readFileSync( - join('artifacts', 'contracts', 'interfaces', 'IApi3ReaderProxy.sol', 'IApi3ReaderProxy.json'), - 'utf8' - ) + // Validate that used proxies all serve fresh values + const { abi: api3ReaderProxyAbi } = JSON.parse( + fs.readFileSync( + join('artifacts', 'contracts', 'interfaces', 'IApi3ReaderProxy.sol', 'IApi3ReaderProxy.json'), + 'utf8' + ) + ); + const ethUsdRateReaderProxy = new ethers.Contract( + ethUsdRateReaderProxyV1Address, + api3ReaderProxyAbi, + provider + ) as unknown as IApi3ReaderProxy; + const goReadEthUsdRateProxy = await go(async () => ethUsdRateReaderProxy.read(), goAsyncOptions); + if (!goReadEthUsdRateProxy.success) { + throw new Error('OevAuctionHouse collateral rate proxy could not be read from'); + } + if (goReadEthUsdRateProxy.data.timestamp < Date.now() / 1000 - 24 * 60 * 60) { + throw new Error( + `OevAuctionHouse collateral rate timestamp is ${new Date(Number(goReadEthUsdRateProxy.data.timestamp) * 1000).toISOString()}` ); - const ethUsdRateReaderProxy = new ethers.Contract( - ethUsdRateReaderProxyV1Address, - api3ReaderProxyAbi, - provider - ) as unknown as IApi3ReaderProxy; - const goReadEthUsdRateProxy = await go(async () => ethUsdRateReaderProxy.read(), goAsyncOptions); - if (!goReadEthUsdRateProxy.success) { - throw new Error('OevAuctionHouse collateral rate proxy could not be read from'); - } - if (goReadEthUsdRateProxy.data.timestamp < Date.now() / 1000 - 24 * 60 * 60) { - throw new Error( - `OevAuctionHouse collateral rate timestamp is ${new Date(Number(goReadEthUsdRateProxy.data.timestamp) * 1000).toISOString()}` - ); - } + } - const proxyReadErrorMessages = await Promise.all( - chainsWithNativeRateProxies.map(async (chain, ind) => { - if (skippedChainAliasesInOevAuctionHouseNativeCurrencyRateValidation.includes(chain.alias)) { - return null; - } + const proxyReadErrorMessages = await Promise.all( + chainsWithNativeRateProxies.map(async (chain, ind) => { + if (skippedChainAliasesInOevAuctionHouseNativeCurrencyRateValidation.includes(chain.alias)) { + return null; + } - const nativeCurrencyRateReaderProxy = new ethers.Contract( - nativeCurrencyRateProxyAddresses[ind]!.toString(), - api3ReaderProxyAbi, - provider - ) as unknown as IApi3ReaderProxy; + const nativeCurrencyRateReaderProxy = new ethers.Contract( + nativeCurrencyRateProxyAddresses[ind]!.toString(), + api3ReaderProxyAbi, + provider + ) as unknown as IApi3ReaderProxy; - const goReadNativeCurrencyRateProxy = await go( - async () => nativeCurrencyRateReaderProxy.read(), - goAsyncOptions - ); + const goReadNativeCurrencyRateProxy = await go( + async () => nativeCurrencyRateReaderProxy.read(), + goAsyncOptions + ); - if (!goReadNativeCurrencyRateProxy.success) { - return `OevAuctionHouse native currency rate proxy of ${chain.alias} with address ${nativeCurrencyRateProxyAddresses[ind]!.toString()} could not be read from`; - } + if (!goReadNativeCurrencyRateProxy.success) { + return `OevAuctionHouse native currency rate proxy of ${chain.alias} with address ${nativeCurrencyRateProxyAddresses[ind]!.toString()} could not be read from`; + } - if (goReadNativeCurrencyRateProxy.data.timestamp < Date.now() / 1000 - 24 * 60 * 60) { - return `The timestamp read from OevAuctionHouse native currency rate proxy of ${chain.alias} with address ${nativeCurrencyRateProxyAddresses[ind]!.toString()} is too old (${new Date(Number(goReadNativeCurrencyRateProxy.data.timestamp) * 1000).toISOString()})`; - } + if (goReadNativeCurrencyRateProxy.data.timestamp < Date.now() / 1000 - 24 * 60 * 60) { + return `The timestamp read from OevAuctionHouse native currency rate proxy of ${chain.alias} with address ${nativeCurrencyRateProxyAddresses[ind]!.toString()} is too old (${new Date(Number(goReadNativeCurrencyRateProxy.data.timestamp) * 1000).toISOString()})`; + } - return null; - }) - ).then((messages) => messages.filter((message) => message !== null)); - if (proxyReadErrorMessages.length > 0) { - // eslint-disable-next-line unicorn/error-message - throw new Error(proxyReadErrorMessages.join('\n')); - } + return null; + }) + ).then((messages) => messages.filter((message) => message !== null)); + if (proxyReadErrorMessages.length > 0) { + // eslint-disable-next-line unicorn/error-message + throw new Error(proxyReadErrorMessages.join('\n')); } } } async function main() { - const networks = process.env.NETWORK ? [process.env.NETWORK] : chainsSupportedByManagerMultisig; + const networks = process.env.NETWORK ? [process.env.NETWORK] : chainsSupportedByMarket; const erroredMainnets: string[] = []; const erroredTestnets: string[] = []; diff --git a/scripts/verify-deployments.ts b/scripts/verify-deployments.ts index f401467d..164d0310 100644 --- a/scripts/verify-deployments.ts +++ b/scripts/verify-deployments.ts @@ -11,12 +11,7 @@ import { go } from '@api3/promise-utils'; import { config, deployments, ethers } from 'hardhat'; import type { Deployment } from 'hardhat-deploy/dist/types'; -import { - chainsSupportedByManagerMultisig, - chainsSupportedByDapis, - chainsSupportedByMarket, - chainsSupportedByOevAuctions, -} from '../data/chain-support.json'; +import { chainsSupportedByMarket, chainsSupportedByOevAuctions } from '../data/chain-support.json'; import { CHAINS } from '../src/index'; import { goAsyncOptions, skippedChainAliasesInOwnableCallForwarderConstructorArgumentVerification } from './constants'; @@ -130,11 +125,17 @@ function validateDeploymentArguments(network: string, deployment: Deployment, co async function verifyDeployments(network: string) { const provider = new ethers.JsonRpcProvider((config.networks[network] as any).url); const contractNames = [ - ...(chainsSupportedByManagerMultisig.includes(network) ? ['GnosisSafeWithoutProxy', 'OwnableCallForwarder'] : []), - ...(chainsSupportedByDapis.includes(network) - ? ['AccessControlRegistry', 'Api3ServerV1', 'Api3ServerV1OevExtension', 'Api3ReaderProxyV1Factory'] + ...(chainsSupportedByMarket.includes(network) + ? [ + 'GnosisSafeWithoutProxy', + 'OwnableCallForwarder', + 'AccessControlRegistry', + 'Api3ServerV1', + 'Api3ServerV1OevExtension', + 'Api3ReaderProxyV1Factory', + 'Api3MarketV2', + ] : []), - ...(chainsSupportedByMarket.includes(network) ? ['Api3MarketV2'] : []), ...(chainsSupportedByOevAuctions.includes(network) ? ['OevAuctionHouse'] : []), ]; @@ -204,7 +205,7 @@ async function verifyDeployments(network: string) { } async function main() { - const networks = process.env.NETWORK ? [process.env.NETWORK] : chainsSupportedByManagerMultisig; + const networks = process.env.NETWORK ? [process.env.NETWORK] : chainsSupportedByMarket; const erroredMainnets: string[] = []; const erroredTestnets: string[] = [];