From 482c8e77f5c497d59865532b3ccd2c5196d02d8b Mon Sep 17 00:00:00 2001 From: Nam Chu Hoai Date: Wed, 3 May 2023 15:21:37 -0400 Subject: [PATCH] Minor fixes to get LL deploys running smoothly (#2125) ### Description This PR makes some minor modifications to the deployment structure for the Liquidity Layer. The most important thing is the embedding of the `proxyAdmin` addresses in the LL addresses file which is not pretty, but I did not want to put it in the SDK right now either, but could be convinced. In the process of running this, the LL router IGPs have been updated which is non-material, but otherwise the deploy script runs as a no-op now. --- .../config/environments/testnet3/index.ts | 6 +- .../{test => testnet3}/liquidityLayer.ts | 0 .../middleware/liquidity-layer/addresses.json | 15 ++-- typescript/infra/scripts/deploy.ts | 16 ++-- .../scripts/middleware/circle-relayer.ts | 19 ++++- typescript/infra/src/config/environment.ts | 6 +- .../src/middleware/liquidity-layer-relayer.ts | 2 +- .../sdk/src/deploy/HyperlaneDeployer.ts | 4 +- .../LiquidityLayerRouterDeployer.ts | 83 ++++++++++++------- .../sdk/src/router/HyperlaneRouterDeployer.ts | 2 +- .../sdk/src/router/ProxiedRouterDeployer.ts | 20 +++-- 11 files changed, 118 insertions(+), 55 deletions(-) rename typescript/infra/config/environments/{test => testnet3}/liquidityLayer.ts (100%) diff --git a/typescript/infra/config/environments/testnet3/index.ts b/typescript/infra/config/environments/testnet3/index.ts index 37c8dc175..6eec70952 100644 --- a/typescript/infra/config/environments/testnet3/index.ts +++ b/typescript/infra/config/environments/testnet3/index.ts @@ -13,6 +13,7 @@ import { storageGasOracleConfig } from './gas-oracle'; import { helloWorld } from './helloworld'; import { igp } from './igp'; import { infrastructure } from './infrastructure'; +import { bridgeAdapterConfigs } from './liquidityLayer'; import { liquidityLayerRelayerConfig } from './middleware'; import { owners } from './owners'; @@ -39,6 +40,9 @@ export const environment: EnvironmentConfig = { helloWorld, owners, keyFunderConfig, - liquidityLayerRelayerConfig, + liquidityLayerConfig: { + bridgeAdapters: bridgeAdapterConfigs, + relayer: liquidityLayerRelayerConfig, + }, storageGasOracleConfig, }; diff --git a/typescript/infra/config/environments/test/liquidityLayer.ts b/typescript/infra/config/environments/testnet3/liquidityLayer.ts similarity index 100% rename from typescript/infra/config/environments/test/liquidityLayer.ts rename to typescript/infra/config/environments/testnet3/liquidityLayer.ts diff --git a/typescript/infra/config/environments/testnet3/middleware/liquidity-layer/addresses.json b/typescript/infra/config/environments/testnet3/middleware/liquidity-layer/addresses.json index 786d5183d..2497ed4a7 100644 --- a/typescript/infra/config/environments/testnet3/middleware/liquidity-layer/addresses.json +++ b/typescript/infra/config/environments/testnet3/middleware/liquidity-layer/addresses.json @@ -2,23 +2,28 @@ "goerli": { "circleBridgeAdapter": "0xfe9d88aA85c5917822C804b949BcEDE832C02ce2", "portalAdapter": "0x68D753982e89CC083917863F6dc9738448B91ef9", - "router": "0x2abe0860D81FB4242C748132bD69D125D88eaE26" + "proxyAdmin": "0x8f919348F9C4619A196Acb5e377f49E5E2C0B569", + "liquidityLayerRouter": "0x2abe0860D81FB4242C748132bD69D125D88eaE26" }, "fuji": { "circleBridgeAdapter": "0xfe9d88aA85c5917822C804b949BcEDE832C02ce2", "portalAdapter": "0x68D753982e89CC083917863F6dc9738448B91ef9", - "router": "0x2abe0860D81FB4242C748132bD69D125D88eaE26" + "proxyAdmin": "0x13474f85b808034C911B7697dee60B7d8d50ee36", + "liquidityLayerRouter": "0x2abe0860D81FB4242C748132bD69D125D88eaE26" }, "mumbai": { "portalAdapter": "0x68D753982e89CC083917863F6dc9738448B91ef9", - "router": "0x2abe0860D81FB4242C748132bD69D125D88eaE26" + "proxyAdmin": "0x96b49e136581f8dfF370aDB3015D48465572a318", + "liquidityLayerRouter": "0x2abe0860D81FB4242C748132bD69D125D88eaE26" }, "bsctestnet": { "portalAdapter": "0x68D753982e89CC083917863F6dc9738448B91ef9", - "router": "0x2abe0860D81FB4242C748132bD69D125D88eaE26" + "proxyAdmin": "0xfB149BC17dD3FE858fA64D678bA0c706DEac61eE", + "liquidityLayerRouter": "0x2abe0860D81FB4242C748132bD69D125D88eaE26" }, "alfajores": { "portalAdapter": "0x68D753982e89CC083917863F6dc9738448B91ef9", - "router": "0x2abe0860D81FB4242C748132bD69D125D88eaE26" + "liquidityLayerRouter": "0x2abe0860D81FB4242C748132bD69D125D88eaE26", + "proxyAdmin": "0x4e4D563e2cBFC35c4BC16003685443Fae2FA702f" } } diff --git a/typescript/infra/scripts/deploy.ts b/typescript/infra/scripts/deploy.ts index a19bb57e2..7003906bb 100644 --- a/typescript/infra/scripts/deploy.ts +++ b/typescript/infra/scripts/deploy.ts @@ -14,7 +14,6 @@ import { objMap, } from '@hyperlane-xyz/sdk'; -import { bridgeAdapterConfigs } from '../config/environments/test/liquidityLayer'; import { deployEnvToSdkEnv } from '../src/config/environment'; import { deployWithArtifacts } from '../src/deploy'; import { TestQuerySenderDeployer } from '../src/testcontracts/testquerysender'; @@ -73,12 +72,17 @@ async function main() { config = await getRouterConfig(environment, multiProvider); deployer = new InterchainQueryDeployer(multiProvider); } else if (module === Modules.LIQUIDITY_LAYER) { - deployer = new LiquidityLayerDeployer(multiProvider); const routerConfig = await getRouterConfig(environment, multiProvider); - config = objMap(bridgeAdapterConfigs, (chain, conf) => ({ - ...conf, - ...routerConfig[chain], - })); + if (!envConfig.liquidityLayerConfig) { + throw new Error(`No liquidity layer config for ${environment}`); + } + config = objMap( + envConfig.liquidityLayerConfig.bridgeAdapters, + (chain, conf) => ({ + ...conf, + ...routerConfig[chain], + }), + ); deployer = new LiquidityLayerDeployer(multiProvider); } else if (module === Modules.TEST_RECIPIENT) { deployer = new TestRecipientDeployer(multiProvider); diff --git a/typescript/infra/scripts/middleware/circle-relayer.ts b/typescript/infra/scripts/middleware/circle-relayer.ts index 595d2f1ed..2817bd105 100644 --- a/typescript/infra/scripts/middleware/circle-relayer.ts +++ b/typescript/infra/scripts/middleware/circle-relayer.ts @@ -1,13 +1,13 @@ import path from 'path'; import { - Chains, LiquidityLayerApp, attachContractsMap, liquidityLayerFactories, + objFilter, } from '@hyperlane-xyz/sdk'; +import { LiquidityLayerConfig } from '@hyperlane-xyz/sdk/dist/middleware/liquidity-layer/LiquidityLayerRouterDeployer'; -import { bridgeAdapterConfigs } from '../../config/environments/testnet3/token-bridge'; import { readJSON, sleep } from '../../src/utils/utils'; import { getEnvironment, @@ -18,6 +18,11 @@ import { async function check() { const environment = await getEnvironment(); const config = getEnvironmentConfig(environment); + + if (config.liquidityLayerConfig === undefined) { + throw new Error(`No liquidity layer config found for ${environment}`); + } + const multiProvider = await config.getMultiProvider(); const dir = path.join( __dirname, @@ -27,14 +32,20 @@ async function check() { ); const addresses = readJSON(dir, 'addresses.json'); const contracts = attachContractsMap(addresses, liquidityLayerFactories); + const app = new LiquidityLayerApp( contracts, multiProvider, - bridgeAdapterConfigs, + config.liquidityLayerConfig.bridgeAdapters, ); while (true) { - for (const chain of [Chains.goerli, Chains.fuji]) { + for (const chain of Object.keys( + objFilter( + config.liquidityLayerConfig.bridgeAdapters, + (_, config): config is LiquidityLayerConfig => !!config.circle, + ), + )) { const txHashes = await app.fetchCircleMessageTransactions(chain); const circleDispatches = ( diff --git a/typescript/infra/src/config/environment.ts b/typescript/infra/src/config/environment.ts index 00bfd9ec2..6665e4ac8 100644 --- a/typescript/infra/src/config/environment.ts +++ b/typescript/infra/src/config/environment.ts @@ -1,5 +1,6 @@ import { AgentConnectionType, + BridgeAdapterConfig, ChainMap, ChainMetadata, ChainName, @@ -44,7 +45,10 @@ export type EnvironmentConfig = { ) => Promise; helloWorld?: Partial>; keyFunderConfig?: KeyFunderConfig; - liquidityLayerRelayerConfig?: LiquidityLayerRelayerConfig; + liquidityLayerConfig?: { + bridgeAdapters: ChainMap; + relayer: LiquidityLayerRelayerConfig; + }; storageGasOracleConfig?: AllStorageGasOracleConfigs; }; diff --git a/typescript/infra/src/middleware/liquidity-layer-relayer.ts b/typescript/infra/src/middleware/liquidity-layer-relayer.ts index 6c4a3fc2a..79e0c7864 100644 --- a/typescript/infra/src/middleware/liquidity-layer-relayer.ts +++ b/typescript/infra/src/middleware/liquidity-layer-relayer.ts @@ -59,7 +59,7 @@ function getLiquidityLayerRelayerHelmValues( export function getLiquidityLayerRelayerConfig( coreConfig: EnvironmentConfig, ): LiquidityLayerRelayerConfig { - const relayerConfig = coreConfig.liquidityLayerRelayerConfig; + const relayerConfig = coreConfig.liquidityLayerConfig?.relayer; if (!relayerConfig) { throw new Error( `Environment ${coreConfig.environment} does not have a LiquidityLayerRelayerConfig config`, diff --git a/typescript/sdk/src/deploy/HyperlaneDeployer.ts b/typescript/sdk/src/deploy/HyperlaneDeployer.ts index 15b50afb5..ccd219e03 100644 --- a/typescript/sdk/src/deploy/HyperlaneDeployer.ts +++ b/typescript/sdk/src/deploy/HyperlaneDeployer.ts @@ -148,7 +148,9 @@ export abstract class HyperlaneDeployer< connectionClient: HyperlaneConnectionClient, config: ConnectionClientConfig, ): Promise { - this.logger(`Initializing connection client on ${local}...`); + this.logger( + `Initializing connection client (if not already) on ${local}...`, + ); await this.runIfOwner(local, connectionClient, async () => { // set mailbox if not already set (and configured) if (config.mailbox !== (await connectionClient.mailbox())) { diff --git a/typescript/sdk/src/middleware/liquidity-layer/LiquidityLayerRouterDeployer.ts b/typescript/sdk/src/middleware/liquidity-layer/LiquidityLayerRouterDeployer.ts index 90398d1d4..18d49a0f1 100644 --- a/typescript/sdk/src/middleware/liquidity-layer/LiquidityLayerRouterDeployer.ts +++ b/typescript/sdk/src/middleware/liquidity-layer/LiquidityLayerRouterDeployer.ts @@ -12,7 +12,7 @@ import { MultiProvider } from '../../providers/MultiProvider'; import { ProxiedRouterDeployer } from '../../router/ProxiedRouterDeployer'; import { RouterConfig } from '../../router/types'; import { ChainMap, ChainName } from '../../types'; -import { objMap } from '../../utils/objects'; +import { objFilter, objMap } from '../../utils/objects'; import { LiquidityLayerFactories, liquidityLayerFactories } from './contracts'; @@ -93,18 +93,32 @@ export class LiquidityLayerDeployer extends ProxiedRouterDeployer< this.logger(`Enroll CircleBridgeAdapters with each other`); // Hack to allow use of super.enrollRemoteRouters await super.enrollRemoteRouters( - objMap(contractsMap, (_, contracts) => ({ - liquidityLayerRouter: contracts.circleBridgeAdapter, - })) as unknown as HyperlaneContractsMap, + objMap( + objFilter( + contractsMap, + (_, c): c is HyperlaneContracts => + !!c.circleBridgeAdapter, + ), + (_, contracts) => ({ + liquidityLayerRouter: contracts.circleBridgeAdapter, + }), + ) as unknown as HyperlaneContractsMap, configMap, ); this.logger(`Enroll PortalAdapters with each other`); // Hack to allow use of super.enrollRemoteRouters await super.enrollRemoteRouters( - objMap(contractsMap, (_, contracts) => ({ - liquidityLayerRouter: contracts.portalAdapter, - })) as unknown as HyperlaneContractsMap, + objMap( + objFilter( + contractsMap, + (_, c): c is HyperlaneContracts => + !!c.portalAdapter, + ), + (_, contracts) => ({ + liquidityLayerRouter: contracts.portalAdapter, + }), + ) as unknown as HyperlaneContractsMap, configMap, ); } @@ -115,6 +129,9 @@ export class LiquidityLayerDeployer extends ProxiedRouterDeployer< chain: ChainName, config: LiquidityLayerConfig, ): Promise> { + // This is just the temp owner for contracts, and HyperlaneRouterDeployer#transferOwnership actually sets the configured owner + const deployer = await this.multiProvider.getSignerAddress(chain); + const routerContracts = await super.deployContracts(chain, config); const bridgeAdapters: Partial< @@ -125,7 +142,7 @@ export class LiquidityLayerDeployer extends ProxiedRouterDeployer< bridgeAdapters.circleBridgeAdapter = await this.deployCircleBridgeAdapter( chain, config.circle, - config.owner, + deployer, routerContracts.liquidityLayerRouter, ); } @@ -133,7 +150,7 @@ export class LiquidityLayerDeployer extends ProxiedRouterDeployer< bridgeAdapters.portalAdapter = await this.deployPortalAdapter( chain, config.portal, - config.owner, + deployer, routerContracts.liquidityLayerRouter, ); } @@ -173,9 +190,11 @@ export class LiquidityLayerDeployer extends ProxiedRouterDeployer< this.logger( `Set wormhole domain ${wormholeDomain} for hyperlane domain ${hyperlaneDomain}`, ); - await this.multiProvider.handleTx( - chain, - portalAdapter.addDomain(hyperlaneDomain, wormholeDomain), + await this.runIfOwner(chain, portalAdapter, () => + this.multiProvider.handleTx( + chain, + portalAdapter.addDomain(hyperlaneDomain, wormholeDomain), + ), ); } @@ -186,11 +205,13 @@ export class LiquidityLayerDeployer extends ProxiedRouterDeployer< ) ) { this.logger('Set Portal as LiquidityLayerAdapter on Router'); - await this.multiProvider.handleTx( - chain, - router.setLiquidityLayerAdapter( - adapterConfig.type, - portalAdapter.address, + await this.runIfOwner(chain, portalAdapter, () => + this.multiProvider.handleTx( + chain, + router.setLiquidityLayerAdapter( + adapterConfig.type, + portalAdapter.address, + ), ), ); } @@ -223,9 +244,11 @@ export class LiquidityLayerDeployer extends ProxiedRouterDeployer< ) ) { this.logger(`Set USDC token contract`); - await this.multiProvider.handleTx( - chain, - circleBridgeAdapter.addToken(adapterConfig.usdcAddress, 'USDC'), + await this.runIfOwner(chain, circleBridgeAdapter, () => + this.multiProvider.handleTx( + chain, + circleBridgeAdapter.addToken(adapterConfig.usdcAddress, 'USDC'), + ), ); } // Set domain mappings @@ -242,9 +265,11 @@ export class LiquidityLayerDeployer extends ProxiedRouterDeployer< this.logger( `Set circle domain ${circleDomain} for hyperlane domain ${hyperlaneDomain}`, ); - await this.multiProvider.handleTx( - chain, - circleBridgeAdapter.addDomain(hyperlaneDomain, circleDomain), + await this.runIfOwner(chain, circleBridgeAdapter, () => + this.multiProvider.handleTx( + chain, + circleBridgeAdapter.addDomain(hyperlaneDomain, circleDomain), + ), ); } @@ -255,11 +280,13 @@ export class LiquidityLayerDeployer extends ProxiedRouterDeployer< ) ) { this.logger('Set Circle as LiquidityLayerAdapter on Router'); - await this.multiProvider.handleTx( - chain, - router.setLiquidityLayerAdapter( - adapterConfig.type, - circleBridgeAdapter.address, + await this.runIfOwner(chain, circleBridgeAdapter, () => + this.multiProvider.handleTx( + chain, + router.setLiquidityLayerAdapter( + adapterConfig.type, + circleBridgeAdapter.address, + ), ), ); } diff --git a/typescript/sdk/src/router/HyperlaneRouterDeployer.ts b/typescript/sdk/src/router/HyperlaneRouterDeployer.ts index 88426eddd..62a4b2601 100644 --- a/typescript/sdk/src/router/HyperlaneRouterDeployer.ts +++ b/typescript/sdk/src/router/HyperlaneRouterDeployer.ts @@ -115,7 +115,7 @@ export abstract class HyperlaneRouterDeployer< // skip if no enrollments are needed if (domains.length === 0) { - return; + continue; } await super.runIfOwner(chain, this.router(contracts), async () => { diff --git a/typescript/sdk/src/router/ProxiedRouterDeployer.ts b/typescript/sdk/src/router/ProxiedRouterDeployer.ts index f3e3dcddf..88a90d6e8 100644 --- a/typescript/sdk/src/router/ProxiedRouterDeployer.ts +++ b/typescript/sdk/src/router/ProxiedRouterDeployer.ts @@ -1,4 +1,5 @@ import { Router } from '@hyperlane-xyz/core'; +import { eqAddress } from '@hyperlane-xyz/utils/dist/src/utils'; import { HyperlaneContracts } from '../contracts'; import { ChainName } from '../types'; @@ -50,13 +51,18 @@ export abstract class ProxiedRouterDeployer< await this.initializeArgs(chain, config), ); - this.logger(`Transferring ownership of proxy admin to ${config.owner}`); - await super.runIfOwner(chain, proxyAdmin, () => - this.multiProvider.handleTx( - chain, - proxyAdmin.transferOwnership(config.owner), - ), - ); + await super.runIfOwner(chain, proxyAdmin, async () => { + this.logger(`Checking ownership of proxy admin to ${config.owner}`); + + if (!eqAddress(await proxyAdmin.owner(), config.owner)) { + this.logger(`Transferring ownership of proxy admin to ${config.owner}`); + return this.multiProvider.handleTx( + chain, + proxyAdmin.transferOwnership(config.owner), + ); + } + return; + }); return { [this.routerContractName]: proxiedRouter,