From 4b6fbfce43517441ce3f3e75cd6dd738788809a4 Mon Sep 17 00:00:00 2001 From: Paul <108695806+pxrl@users.noreply.github.com> Date: Fri, 9 Aug 2024 13:32:55 +0200 Subject: [PATCH 1/4] improve(deploy): Improve SpokePool deployment UX The majority of SpokePool deployment scripts have been updated to support deploying only implementation contracts. This is done with the knowledge that there are already pre-existing deployments on these chains, but it introduces a risk that using one of these scripts as the template for a new chain will inadvertently result in skipping deployment of the proxy contact. Instead, whether to deploy a new proxy or not can be inferred by whether the contract exists in deployments.json. Signed-off-by: Paul <108695806+pxrl@users.noreply.github.com> --- deploy/003_deploy_optimism_spokepool.ts | 2 +- deploy/005_deploy_arbitrum_spokepool.ts | 2 +- deploy/007_deploy_ethereum_spokepool.ts | 14 ++++++-------- deploy/011_deploy_polygon_spokepool.ts | 2 +- deploy/016_deploy_zksync_spokepool.ts | 6 ++++-- deploy/025_deploy_base_spokepool.ts | 2 +- deploy/029_deploy_linea_spokepool.ts | 2 +- deploy/036_deploy_blast_spokepool.ts | 2 +- deploy/039_deploy_mode_spokepool.ts | 5 ++--- deploy/043_deploy_lisk_spokepool.ts | 4 ++-- deploy/047_deploy_redstone_spokepool.ts | 7 ++----- deploy/049_deploy_zora_spokepool.ts | 7 ++----- deployments/deployments.json | 1 - src/DeploymentUtils.ts | 10 ++++++---- utils/utils.hre.ts | 11 +++++++++-- 15 files changed, 39 insertions(+), 38 deletions(-) diff --git a/deploy/003_deploy_optimism_spokepool.ts b/deploy/003_deploy_optimism_spokepool.ts index 54403cbc5..6c7397fa4 100644 --- a/deploy/003_deploy_optimism_spokepool.ts +++ b/deploy/003_deploy_optimism_spokepool.ts @@ -28,7 +28,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { L2_ADDRESS_MAP[spokeChainId].l2Usdc, L2_ADDRESS_MAP[spokeChainId].cctpTokenMessenger, ]; - await deployNewProxy("Optimism_SpokePool", constructorArgs, initArgs, spokeChainId === 10); + await deployNewProxy("Optimism_SpokePool", constructorArgs, initArgs); }; module.exports = func; func.tags = ["OptimismSpokePool", "optimism"]; diff --git a/deploy/005_deploy_arbitrum_spokepool.ts b/deploy/005_deploy_arbitrum_spokepool.ts index 2dfc2810a..538f43522 100644 --- a/deploy/005_deploy_arbitrum_spokepool.ts +++ b/deploy/005_deploy_arbitrum_spokepool.ts @@ -29,7 +29,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { L2_ADDRESS_MAP[spokeChainId].l2Usdc, L2_ADDRESS_MAP[spokeChainId].cctpTokenMessenger, ]; - await deployNewProxy("Arbitrum_SpokePool", constructorArgs, initArgs, spokeChainId === 42161); + await deployNewProxy("Arbitrum_SpokePool", constructorArgs, initArgs); }; module.exports = func; func.tags = ["ArbitrumSpokePool", "arbitrum"]; diff --git a/deploy/007_deploy_ethereum_spokepool.ts b/deploy/007_deploy_ethereum_spokepool.ts index c74f2da85..8b27157af 100644 --- a/deploy/007_deploy_ethereum_spokepool.ts +++ b/deploy/007_deploy_ethereum_spokepool.ts @@ -1,13 +1,11 @@ +import { HardhatRuntimeEnvironment } from "hardhat/types"; import { DeployFunction } from "hardhat-deploy/types"; -import { deployNewProxy } from "../utils/utils.hre"; +import { deployNewProxy, getSpokePoolDeploymentInfo } from "../utils/utils.hre"; import { L1_ADDRESS_MAP } from "./consts"; -import { HardhatRuntimeEnvironment } from "hardhat/types"; const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { - const { deployments, getChainId } = hre; - const chainId = await getChainId(); - const hubPool = await deployments.get("HubPool"); - console.log(`Using chain ${chainId} HubPool @ ${hubPool.address}`); + const { hubPool, spokeChainId } = await getSpokePoolDeploymentInfo(hre); + console.log(`Using HubPool @ ${hubPool.address}`); // Initialize deposit counter to very high number of deposits to avoid duplicate deposit ID's // with deprecated spoke pool. @@ -17,8 +15,8 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { // * A WETH address of the WETH address // * A depositQuoteTimeBuffer of 1 hour // * A fillDeadlineBuffer of 6 hours - const constructorArgs = [L1_ADDRESS_MAP[chainId].weth, 3600, 21600]; - await deployNewProxy("Ethereum_SpokePool", constructorArgs, initArgs, chainId === "1"); + const constructorArgs = [L1_ADDRESS_MAP[spokeChainId].weth, 3600, 21600]; + await deployNewProxy("Ethereum_SpokePool", constructorArgs, initArgs); // Transfer ownership to hub pool. }; diff --git a/deploy/011_deploy_polygon_spokepool.ts b/deploy/011_deploy_polygon_spokepool.ts index 68ee86eaf..b49633295 100644 --- a/deploy/011_deploy_polygon_spokepool.ts +++ b/deploy/011_deploy_polygon_spokepool.ts @@ -32,7 +32,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { L2_ADDRESS_MAP[spokeChainId].l2Usdc, L2_ADDRESS_MAP[spokeChainId].cctpTokenMessenger, ]; - await deployNewProxy("Polygon_SpokePool", constructorArgs, initArgs, spokeChainId === 137); + await deployNewProxy("Polygon_SpokePool", constructorArgs, initArgs); }; module.exports = func; diff --git a/deploy/016_deploy_zksync_spokepool.ts b/deploy/016_deploy_zksync_spokepool.ts index 0d8fc7790..0f81648df 100644 --- a/deploy/016_deploy_zksync_spokepool.ts +++ b/deploy/016_deploy_zksync_spokepool.ts @@ -29,10 +29,12 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { // * A fillDeadlineBuffer of 6 hours const constructorArgs = [L2_ADDRESS_MAP[spokeChainId].l2Weth, 3600, 21600]; - let newAddress; + let newAddress: string; // On production, we'll rarely want to deploy a new proxy contract so we'll default to deploying a new implementation // contract. - if (spokeChainId === 324) { + // If SKIP_PROXY is defined, only deploy an implementation contract. + const implementationOnly = process.env.SKIP_PROXY !== undefined; + if (implementationOnly) { const _deployment = await deployer.deploy(artifact, constructorArgs); newAddress = _deployment.address; console.log(`New ${contractName} implementation deployed @ ${newAddress}`); diff --git a/deploy/025_deploy_base_spokepool.ts b/deploy/025_deploy_base_spokepool.ts index 59b29cefa..82b90c7f3 100644 --- a/deploy/025_deploy_base_spokepool.ts +++ b/deploy/025_deploy_base_spokepool.ts @@ -27,7 +27,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { L2_ADDRESS_MAP[spokeChainId].l2Usdc, L2_ADDRESS_MAP[spokeChainId].cctpTokenMessenger, ]; - await deployNewProxy("Base_SpokePool", constructorArgs, initArgs, spokeChainId === 8453); + await deployNewProxy("Base_SpokePool", constructorArgs, initArgs); }; module.exports = func; func.tags = ["BaseSpokePool", "base"]; diff --git a/deploy/029_deploy_linea_spokepool.ts b/deploy/029_deploy_linea_spokepool.ts index e7e62e980..165674d02 100644 --- a/deploy/029_deploy_linea_spokepool.ts +++ b/deploy/029_deploy_linea_spokepool.ts @@ -21,7 +21,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { ]; const constructorArgs = [L2_ADDRESS_MAP[chainId].l2Weth, 3600, 21600]; - await deployNewProxy("Linea_SpokePool", constructorArgs, initArgs, chainId === 59144); + await deployNewProxy("Linea_SpokePool", constructorArgs, initArgs); }; module.exports = func; func.tags = ["LineaSpokePool", "linea"]; diff --git a/deploy/036_deploy_blast_spokepool.ts b/deploy/036_deploy_blast_spokepool.ts index 6c9263132..0212b7284 100644 --- a/deploy/036_deploy_blast_spokepool.ts +++ b/deploy/036_deploy_blast_spokepool.ts @@ -35,7 +35,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { "0x8bA929bE3462a809AFB3Bf9e100Ee110D2CFE531", L1_ADDRESS_MAP[hubChainId].blastDaiRetriever, // Address of mainnet retriever contract to facilitate USDB finalizations. ]; - await deployNewProxy("Blast_SpokePool", constructorArgs, initArgs, spokeChainId === 81457); + await deployNewProxy("Blast_SpokePool", constructorArgs, initArgs); }; module.exports = func; func.tags = ["BlastSpokePool", "blast"]; diff --git a/deploy/039_deploy_mode_spokepool.ts b/deploy/039_deploy_mode_spokepool.ts index d46b40570..2c078db27 100644 --- a/deploy/039_deploy_mode_spokepool.ts +++ b/deploy/039_deploy_mode_spokepool.ts @@ -1,11 +1,10 @@ import { deployNewProxy, getSpokePoolDeploymentInfo } from "../utils/utils.hre"; import { DeployFunction } from "hardhat-deploy/types"; import { HardhatRuntimeEnvironment } from "hardhat/types"; -import { L2_ADDRESS_MAP } from "./consts"; import { ZERO_ADDRESS } from "@uma/common"; const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { - const { hubPool, spokeChainId } = await getSpokePoolDeploymentInfo(hre); + const { hubPool } = await getSpokePoolDeploymentInfo(hre); const initArgs = [ 1, @@ -29,7 +28,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { // the cctpTokenMessenger to the zero address. ZERO_ADDRESS, ]; - await deployNewProxy("Mode_SpokePool", constructorArgs, initArgs, spokeChainId === 34443); + await deployNewProxy("Mode_SpokePool", constructorArgs, initArgs); }; module.exports = func; func.tags = ["ModeSpokePool", "mode"]; diff --git a/deploy/043_deploy_lisk_spokepool.ts b/deploy/043_deploy_lisk_spokepool.ts index 6972e41ca..a54687806 100644 --- a/deploy/043_deploy_lisk_spokepool.ts +++ b/deploy/043_deploy_lisk_spokepool.ts @@ -4,7 +4,7 @@ import { HardhatRuntimeEnvironment } from "hardhat/types"; import { ZERO_ADDRESS } from "@uma/common"; const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { - const { hubPool, spokeChainId } = await getSpokePoolDeploymentInfo(hre); + const { hubPool } = await getSpokePoolDeploymentInfo(hre); const initArgs = [ 1, @@ -28,7 +28,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { // the cctpTokenMessenger to the zero address. ZERO_ADDRESS, ]; - await deployNewProxy("Lisk_SpokePool", constructorArgs, initArgs, spokeChainId === 1135); + await deployNewProxy("Lisk_SpokePool", constructorArgs, initArgs); }; module.exports = func; func.tags = ["LiskSpokePool", "lisk"]; diff --git a/deploy/047_deploy_redstone_spokepool.ts b/deploy/047_deploy_redstone_spokepool.ts index bda67c13f..4d45aacf2 100644 --- a/deploy/047_deploy_redstone_spokepool.ts +++ b/deploy/047_deploy_redstone_spokepool.ts @@ -2,11 +2,8 @@ import { DeployFunction } from "hardhat-deploy/types"; import { HardhatRuntimeEnvironment } from "hardhat/types"; import { ZERO_ADDRESS } from "@uma/common"; import { deployNewProxy, getSpokePoolDeploymentInfo } from "../utils/utils.hre"; -import { CHAIN_IDs } from "../utils"; import { WETH } from "./consts"; -const { REDSTONE } = CHAIN_IDs; - const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { const { hubPool, spokeChainId } = await getSpokePoolDeploymentInfo(hre); @@ -32,7 +29,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { // the cctpTokenMessenger to the zero address. ZERO_ADDRESS, ]; - await deployNewProxy("Redstone_SpokePool", constructorArgs, initArgs, spokeChainId === REDSTONE); + await deployNewProxy("Redstone_SpokePool", constructorArgs, initArgs); }; module.exports = func; -func.tags = ["spokepool", "redstone"]; +func.tags = ["RedstoneSpokePool", "redstone"]; diff --git a/deploy/049_deploy_zora_spokepool.ts b/deploy/049_deploy_zora_spokepool.ts index d71856fc6..2a7208dd4 100644 --- a/deploy/049_deploy_zora_spokepool.ts +++ b/deploy/049_deploy_zora_spokepool.ts @@ -2,11 +2,8 @@ import { DeployFunction } from "hardhat-deploy/types"; import { HardhatRuntimeEnvironment } from "hardhat/types"; import { ZERO_ADDRESS } from "@uma/common"; import { deployNewProxy, getSpokePoolDeploymentInfo } from "../utils/utils.hre"; -import { CHAIN_IDs } from "../utils"; import { WETH } from "./consts"; -const { ZORA } = CHAIN_IDs; - const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { const { hubPool, spokeChainId } = await getSpokePoolDeploymentInfo(hre); @@ -32,7 +29,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { // the cctpTokenMessenger to the zero address. ZERO_ADDRESS, ]; - await deployNewProxy("Zora_SpokePool", constructorArgs, initArgs, spokeChainId === ZORA); + await deployNewProxy("Zora_SpokePool", constructorArgs, initArgs); }; module.exports = func; -func.tags = ["spokepool", "zora"]; +func.tags = ["ZoraSpokePool", "zora"]; diff --git a/deployments/deployments.json b/deployments/deployments.json index c3b15d0c4..7051df9f0 100644 --- a/deployments/deployments.json +++ b/deployments/deployments.json @@ -175,7 +175,6 @@ "MulticallHandler": { "address": "0x924a9f036260DdD5808007E1AA95f08eD08aA569", "blockNumber": 7489978 } }, "7777777": { - "SpokePool": { "address": "0x09aea4b2242abC8bb4BB78D537A67a245A7bEC64", "blockNumber": 18119425 }, "SpokePoolVerifier": { "address": "0xB4A8d45647445EA9FC3E1058096142390683dBC2", "blockNumber": 18120222 }, "MulticallHandler": { "address": "0x924a9f036260DdD5808007E1AA95f08eD08aA569", "blockNumber": 18119854 } }, diff --git a/src/DeploymentUtils.ts b/src/DeploymentUtils.ts index 053eb106f..58844ac45 100644 --- a/src/DeploymentUtils.ts +++ b/src/DeploymentUtils.ts @@ -1,16 +1,18 @@ import * as deployments_ from "../deployments/deployments.json"; + interface DeploymentExport { [chainId: string]: { [contractName: string]: { address: string; blockNumber: number } }; } const deployments: DeploymentExport = deployments_ as any; // Returns the deployed address of any contract on any network. -export function getDeployedAddress(contractName: string, networkId: number): string { - try { - return deployments[networkId.toString()][contractName].address; - } catch (_) { +export function getDeployedAddress(contractName: string, networkId: number, throwOnError = true): string | undefined { + const address = deployments[networkId.toString()]?.[contractName]?.address; + if (!address && throwOnError) { throw new Error(`Contract ${contractName} not found on ${networkId} in deployments.json`); } + + return address; } // Returns the deployment block number of any contract on any network. diff --git a/utils/utils.hre.ts b/utils/utils.hre.ts index 116a66d33..9c91f0529 100644 --- a/utils/utils.hre.ts +++ b/utils/utils.hre.ts @@ -1,8 +1,9 @@ import hre from "hardhat"; import { HardhatRuntimeEnvironment } from "hardhat/types"; import { Deployment, DeploymentSubmission } from "hardhat-deploy/types"; -import { getContractFactory } from "./utils"; import { CHAIN_IDs } from "@across-protocol/constants"; +import { getDeployedAddress } from "../src/DeploymentUtils"; +import { getContractFactory, toBN } from "./utils"; type unsafeAllowTypes = ( | "delegatecall" @@ -15,6 +16,7 @@ type unsafeAllowTypes = ( | "enum-definition" | "missing-public-upgradeto" )[]; + /** * @description Resolve the HubPool deployment, as well as the HubPool and SpokePool chain IDs for a new deployment. * @dev This function relies on having companionNetworks defined in the HardhatUserConfig. @@ -40,7 +42,7 @@ export async function deployNewProxy( name: string, constructorArgs: FnArgs[], initArgs: FnArgs[], - implementationOnly = false + implementationOnly?: boolean ): Promise { const { deployments, run, upgrades, getChainId } = hre; let chainId = Number(await getChainId()); @@ -50,7 +52,12 @@ export async function deployNewProxy( if ([CHAIN_IDs.BLAST, CHAIN_IDs.BLAST_SEPOLIA].includes(chainId)) { unsafeAllowArgs.push("state-variable-immutable"); } + + // If a SpokePool can be found in deployments/deployments.json, then only deploy an implementation contract. + const proxy = getDeployedAddress("SpokePool", chainId, false); + implementationOnly ??= proxy !== undefined; if (implementationOnly) { + console.log(`${name} deployment already detected @ ${proxy}, deploying new implementation.`); instance = (await upgrades.deployImplementation(await getContractFactory(name, {}), { constructorArgs, kind: "uups", From d611f4e644c729c2ee4addf647af1f7e5ff92412 Mon Sep 17 00:00:00 2001 From: Paul <108695806+pxrl@users.noreply.github.com> Date: Fri, 9 Aug 2024 15:50:51 +0200 Subject: [PATCH 2/4] Update zkSync deployment script --- deploy/016_deploy_zksync_spokepool.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/deploy/016_deploy_zksync_spokepool.ts b/deploy/016_deploy_zksync_spokepool.ts index 0f81648df..5fda2d7a7 100644 --- a/deploy/016_deploy_zksync_spokepool.ts +++ b/deploy/016_deploy_zksync_spokepool.ts @@ -1,9 +1,10 @@ import * as zk from "zksync-web3"; import { Deployer as zkDeployer } from "@matterlabs/hardhat-zksync-deploy"; import { DeployFunction, DeploymentSubmission } from "hardhat-deploy/types"; -import { L2_ADDRESS_MAP } from "./consts"; import { HardhatRuntimeEnvironment } from "hardhat/types"; +import { getDeployedAddress } from "../src/DeploymentUtils"; import { getSpokePoolDeploymentInfo } from "../utils/utils.hre"; +import { L2_ADDRESS_MAP } from "./consts"; const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { const contractName = "ZkSync_SpokePool"; @@ -33,8 +34,10 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { // On production, we'll rarely want to deploy a new proxy contract so we'll default to deploying a new implementation // contract. // If SKIP_PROXY is defined, only deploy an implementation contract. - const implementationOnly = process.env.SKIP_PROXY !== undefined; + const proxy = getDeployedAddress("SpokePool", spokeChainId, false); + const implementationOnly = proxy !== undefined; if (implementationOnly) { + console.log(`${name} deployment already detected @ ${proxy}, deploying new implementation.`); const _deployment = await deployer.deploy(artifact, constructorArgs); newAddress = _deployment.address; console.log(`New ${contractName} implementation deployed @ ${newAddress}`); From e3a06e54e94b72898629c681026ffe776e307b78 Mon Sep 17 00:00:00 2001 From: Paul <108695806+pxrl@users.noreply.github.com> Date: Fri, 9 Aug 2024 17:47:58 +0200 Subject: [PATCH 3/4] Update deploy/016_deploy_zksync_spokepool.ts --- deploy/016_deploy_zksync_spokepool.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/016_deploy_zksync_spokepool.ts b/deploy/016_deploy_zksync_spokepool.ts index 5fda2d7a7..6d3072315 100644 --- a/deploy/016_deploy_zksync_spokepool.ts +++ b/deploy/016_deploy_zksync_spokepool.ts @@ -33,7 +33,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { let newAddress: string; // On production, we'll rarely want to deploy a new proxy contract so we'll default to deploying a new implementation // contract. - // If SKIP_PROXY is defined, only deploy an implementation contract. +// If a SpokePool can be found in deployments/deployments.json, then only deploy an implementation contract. const proxy = getDeployedAddress("SpokePool", spokeChainId, false); const implementationOnly = proxy !== undefined; if (implementationOnly) { From e1ff65b5506a7eff1a139dbae5fd7c62612e2a38 Mon Sep 17 00:00:00 2001 From: Paul <108695806+pxrl@users.noreply.github.com> Date: Fri, 9 Aug 2024 17:54:40 +0200 Subject: [PATCH 4/4] Update deploy/016_deploy_zksync_spokepool.ts --- deploy/016_deploy_zksync_spokepool.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/016_deploy_zksync_spokepool.ts b/deploy/016_deploy_zksync_spokepool.ts index 6d3072315..f58f0ac47 100644 --- a/deploy/016_deploy_zksync_spokepool.ts +++ b/deploy/016_deploy_zksync_spokepool.ts @@ -33,7 +33,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { let newAddress: string; // On production, we'll rarely want to deploy a new proxy contract so we'll default to deploying a new implementation // contract. -// If a SpokePool can be found in deployments/deployments.json, then only deploy an implementation contract. + // If a SpokePool can be found in deployments/deployments.json, then only deploy an implementation contract. const proxy = getDeployedAddress("SpokePool", spokeChainId, false); const implementationOnly = proxy !== undefined; if (implementationOnly) {