From 3ff8eb3c3d435e98a52631d8c14eca0dc1d063c5 Mon Sep 17 00:00:00 2001 From: Yorke Rhodes Date: Mon, 4 Mar 2024 09:08:33 -0700 Subject: [PATCH] Update mainnet3 governance and validator configurations (#3315) ### Description - Transfer inEVM and injective contracts to multisig - Configure safes as owners on mainnet3 ### Drive-by changes - Support foreign domains in ISM factory - Fix transfer ownership bugs in deployers and ISM factory ### Related issues - Fixes https://github.com/hyperlane-xyz/issues/issues/813 - Fixes https://github.com/hyperlane-xyz/issues/issues/973 - Fixes https://github.com/hyperlane-xyz/issues/issues/1028 ### Backward compatibility - Yes ### Testing - Env tests --- .changeset/wild-horses-burn.md | 6 ++++++ .github/workflows/test.yml | 1 + .../config/environments/mainnet3/core.ts | 6 +++--- .../infra/config/environments/mainnet3/igp.ts | 15 +++++++------- .../config/environments/mainnet3/owners.ts | 8 +++++--- typescript/infra/fork.sh | 3 --- typescript/infra/scripts/check-deploy.ts | 3 ++- typescript/infra/scripts/deploy.ts | 9 ++++++++- typescript/infra/src/utils/fork.ts | 4 ++++ typescript/sdk/src/consts/multisigIsm.ts | 8 ++++---- .../sdk/src/deploy/HyperlaneDeployer.ts | 2 +- .../sdk/src/hook/HyperlaneHookDeployer.ts | 20 ++++++++++++------- typescript/sdk/src/ism/HyperlaneIsmFactory.ts | 14 ++++++++++--- 13 files changed, 66 insertions(+), 33 deletions(-) create mode 100644 .changeset/wild-horses-burn.md diff --git a/.changeset/wild-horses-burn.md b/.changeset/wild-horses-burn.md new file mode 100644 index 000000000..44922d288 --- /dev/null +++ b/.changeset/wild-horses-burn.md @@ -0,0 +1,6 @@ +--- +'@hyperlane-xyz/infra': patch +'@hyperlane-xyz/sdk': patch +--- + +Patch transfer ownership in hook deployer diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 868b037db..0431e5b38 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -296,6 +296,7 @@ jobs: runs-on: ubuntu-latest needs: [yarn-build] strategy: + fail-fast: false matrix: environment: [mainnet3] chain: [ethereum, arbitrum, optimism, inevm, viction] diff --git a/typescript/infra/config/environments/mainnet3/core.ts b/typescript/infra/config/environments/mainnet3/core.ts index 8dc23b6a3..8332de925 100644 --- a/typescript/infra/config/environments/mainnet3/core.ts +++ b/typescript/infra/config/environments/mainnet3/core.ts @@ -22,7 +22,7 @@ import { objMap } from '@hyperlane-xyz/utils'; import { supportedChainNames } from './chains'; import { igp } from './igp'; -import { owners } from './owners'; +import { DEPLOYER, owners } from './owners'; export const core: ChainMap = objMap(owners, (local, owner) => { const originMultisigs: ChainMap = Object.fromEntries( @@ -56,7 +56,7 @@ export const core: ChainMap = objMap(owners, (local, owner) => { const pausableIsm: PausableIsmConfig = { type: IsmType.PAUSABLE, - ...owner, + owner: DEPLOYER, // keep pausable hot }; const defaultIsm: AggregationIsmConfig = { @@ -76,7 +76,7 @@ export const core: ChainMap = objMap(owners, (local, owner) => { const pausableHook: PausableHookConfig = { type: HookType.PAUSABLE, - ...owner, + owner: DEPLOYER, // keep pausable hot }; const aggregationHooks = objMap( originMultisigs, diff --git a/typescript/infra/config/environments/mainnet3/igp.ts b/typescript/infra/config/environments/mainnet3/igp.ts index 5e58d39bc..c6b66f7c2 100644 --- a/typescript/infra/config/environments/mainnet3/igp.ts +++ b/typescript/infra/config/environments/mainnet3/igp.ts @@ -12,11 +12,7 @@ import { supportedChainNames, } from './chains'; import { storageGasOracleConfig } from './gas-oracle'; -import { owners } from './owners'; - -// TODO: make this generic -const KEY_FUNDER_ADDRESS = '0xa7ECcdb9Be08178f896c26b7BbD8C3D4E844d9Ba'; -const DEPLOYER_ADDRESS = '0xa7ECcdb9Be08178f896c26b7BbD8C3D4E844d9Ba'; +import { DEPLOYER, owners } from './owners'; const FOREIGN_DEFAULT_OVERHEAD = 600_000; // cosmwasm warp route somewhat arbitrarily chosen @@ -30,8 +26,13 @@ const remoteOverhead = (remote: MainnetChains) => export const igp: ChainMap = objMap(owners, (local, owner) => ({ ...owner, - oracleKey: DEPLOYER_ADDRESS, - beneficiary: KEY_FUNDER_ADDRESS, + ownerOverrides: { + ...owner.ownerOverrides, + interchainGasPaymaster: DEPLOYER, + storageGasOracle: DEPLOYER, + }, + oracleKey: DEPLOYER, + beneficiary: DEPLOYER, overhead: Object.fromEntries( exclude(local, supportedChainNames).map((remote) => [ remote, diff --git a/typescript/infra/config/environments/mainnet3/owners.ts b/typescript/infra/config/environments/mainnet3/owners.ts index 1a1a87a7a..8f9c21615 100644 --- a/typescript/infra/config/environments/mainnet3/owners.ts +++ b/typescript/infra/config/environments/mainnet3/owners.ts @@ -18,18 +18,20 @@ export const safes: ChainMap
= { optimism: '0xb523CFAf45AACF472859f8B793CB0BFDB16bD257', moonbeam: '0xF0cb1f968Df01fc789762fddBfA704AE0F952197', gnosis: '0x36b0AA0e7d04e7b825D7E409FEa3c9A3d57E4C22', + inevm: '0x77F3863ea99F2360D84d4BA1A2E441857D0357fa', // caldera + injective + // injective: 'inj1632x8j35kenryam3mkrsez064sqg2y2fr0frzt', // solana: 'EzppBFV2taxWw8kEjxNYvby6q7W1biJEqwP3iC7YgRe3', }; -const deployer = '0xa7ECcdb9Be08178f896c26b7BbD8C3D4E844d9Ba'; +export const DEPLOYER = '0xa7ECcdb9Be08178f896c26b7BbD8C3D4E844d9Ba'; export const owners: ChainMap = Object.fromEntries( ethereumChainNames.map((local) => [ local, { - owner: deployer, // TODO: change this to the safe + owner: safes[local] ?? DEPLOYER, ownerOverrides: { - proxyAdmin: timelocks[local] ?? safes[local] ?? deployer, + proxyAdmin: timelocks[local] ?? safes[local] ?? DEPLOYER, }, }, ]), diff --git a/typescript/infra/fork.sh b/typescript/infra/fork.sh index 13ed5a9a9..1e29e4dd5 100755 --- a/typescript/infra/fork.sh +++ b/typescript/infra/fork.sh @@ -36,9 +36,6 @@ yarn ts-node ./scripts/deploy.ts -e $ENVIRONMENT -f $CHAIN -m $MODULE AFTER=$(cast balance $DEPLOYER --rpc-url http://localhost:8545) DEPLOY_DELTA="$((BEFORE-AFTER))" -# build SDK to get the latest addresses -yarn --cwd ../sdk build - BEFORE=$(cast balance $DEPLOYER --rpc-url http://localhost:8545) yarn ts-node ./scripts/check-deploy.ts -e $ENVIRONMENT -f $CHAIN --govern -m $MODULE diff --git a/typescript/infra/scripts/check-deploy.ts b/typescript/infra/scripts/check-deploy.ts index 52b73c34b..81902dc4f 100644 --- a/typescript/infra/scripts/check-deploy.ts +++ b/typescript/infra/scripts/check-deploy.ts @@ -51,7 +51,8 @@ async function check() { }); const owner = config.core[fork].owner; - const signer = await impersonateAccount(owner); + const signer = await impersonateAccount(owner, 1e18); + multiProvider.setSigner(fork, signer); } } diff --git a/typescript/infra/scripts/deploy.ts b/typescript/infra/scripts/deploy.ts index b83d1019b..8026a306a 100644 --- a/typescript/infra/scripts/deploy.ts +++ b/typescript/infra/scripts/deploy.ts @@ -69,7 +69,14 @@ async function main() { }); await useLocalProvider(multiProvider, fork); - const signer = await impersonateAccount(envConfig.owners[fork].owner); + // const deployers = await envConfig.getKeys( + // Contexts.Hyperlane, + // Role.Deployer, + // ); + // const deployer = deployers[fork].address; + const deployer = '0xa7ECcdb9Be08178f896c26b7BbD8C3D4E844d9Ba'; + const signer = await impersonateAccount(deployer); + multiProvider.setSharedSigner(signer); } diff --git a/typescript/infra/src/utils/fork.ts b/typescript/infra/src/utils/fork.ts index 3d50f8eac..c51d40a8b 100644 --- a/typescript/infra/src/utils/fork.ts +++ b/typescript/infra/src/utils/fork.ts @@ -15,9 +15,13 @@ export const resetFork = async (url: string) => { export const impersonateAccount = async ( account: string, + spoofBalance?: number, ): Promise => { const provider = new JsonRpcProvider('http://127.0.0.1:8545'); await provider.send('hardhat_impersonateAccount', [account]); + if (spoofBalance) { + await provider.send('hardhat_setBalance', [account, spoofBalance]); + } return provider.getSigner(account); }; diff --git a/typescript/sdk/src/consts/multisigIsm.ts b/typescript/sdk/src/consts/multisigIsm.ts index 22059db95..74de5c62f 100644 --- a/typescript/sdk/src/consts/multisigIsm.ts +++ b/typescript/sdk/src/consts/multisigIsm.ts @@ -138,8 +138,8 @@ export const defaultMultisigConfigs: ChainMap = { threshold: 2, validators: [ '0xf9e35ee88e4448a3673b4676a4e153e3584a08eb', - '0xae3e6bb6b3ece1c425aa6f47adc8cb0453c1f9a2', - '0xd98c9522cd9d3e3e00bee05ff76c34b91b266ec3', + '0x6B1d09A97b813D53e9D4b7523DA36604C0B52242', // caldera + '0x9ab11f38a609940153850df611c9a2175dcffe0f', // imperator ], }, @@ -147,8 +147,8 @@ export const defaultMultisigConfigs: ChainMap = { threshold: 2, validators: [ '0xbfb8911b72cfb138c7ce517c57d9c691535dc517', - '0x6faa139c33a7e6f53cb101f6b2ae392298283ed2', - '0x0115e3a66820fb99da30d30e2ce52a453ba99d92', + '0x6B1d09A97b813D53e9D4b7523DA36604C0B52242', // caldera + '0x9e551b6694bbd295d7d6e6a2540c7d41ce70a3b9', // imperator ], }, diff --git a/typescript/sdk/src/deploy/HyperlaneDeployer.ts b/typescript/sdk/src/deploy/HyperlaneDeployer.ts index c0370701f..471465761 100644 --- a/typescript/sdk/src/deploy/HyperlaneDeployer.ts +++ b/typescript/sdk/src/deploy/HyperlaneDeployer.ts @@ -640,7 +640,7 @@ export abstract class HyperlaneDeployer< return ret; } - protected async transferOwnershipOfContracts( + async transferOwnershipOfContracts( chain: ChainName, config: OwnableConfig, ownables: Partial>, diff --git a/typescript/sdk/src/hook/HyperlaneHookDeployer.ts b/typescript/sdk/src/hook/HyperlaneHookDeployer.ts index c87d8777b..0af7d4fd3 100644 --- a/typescript/sdk/src/hook/HyperlaneHookDeployer.ts +++ b/typescript/sdk/src/hook/HyperlaneHookDeployer.ts @@ -258,13 +258,15 @@ export class HyperlaneHookDeployer extends HyperlaneDeployer< throw new Error(`Mailbox address is required for ${config.type}`); } + const deployer = await this.multiProvider.getSigner(chain).getAddress(); + let routingHook: DomainRoutingHook | FallbackDomainRoutingHook; switch (config.type) { case HookType.ROUTING: { this.logger('Deploying DomainRoutingHook for %s', chain); routingHook = await this.deployContract(chain, HookType.ROUTING, [ mailbox, - config.owner, + deployer, ]); break; } @@ -278,7 +280,7 @@ export class HyperlaneHookDeployer extends HyperlaneDeployer< routingHook = await this.deployContract( chain, HookType.FALLBACK_ROUTING, - [mailbox, config.owner, fallbackHook[config.fallback.type].address], + [mailbox, deployer, fallbackHook[config.fallback.type].address], ); break; } @@ -309,13 +311,17 @@ export class HyperlaneHookDeployer extends HyperlaneDeployer< } const overrides = this.multiProvider.getTransactionOverrides(chain); - await this.multiProvider.handleTx( - chain, - routingHook.setHooks(routingConfigs, { - ...overrides, - }), + await this.runIfOwner(chain, routingHook, async () => + this.multiProvider.handleTx( + chain, + routingHook.setHooks(routingConfigs, overrides), + ), ); + await this.transferOwnershipOfContracts(chain, config, { + [config.type]: routingHook, + }); + return routingHook; } } diff --git a/typescript/sdk/src/ism/HyperlaneIsmFactory.ts b/typescript/sdk/src/ism/HyperlaneIsmFactory.ts index b51c1131f..ae0dd6d8b 100644 --- a/typescript/sdk/src/ism/HyperlaneIsmFactory.ts +++ b/typescript/sdk/src/ism/HyperlaneIsmFactory.ts @@ -27,6 +27,7 @@ import { } from '@hyperlane-xyz/utils'; import { HyperlaneApp } from '../app/HyperlaneApp'; +import { chainMetadata } from '../consts/chainMetadata'; import { HyperlaneEnvironment, hyperlaneEnvironments, @@ -164,6 +165,9 @@ export class HyperlaneIsmFactory extends HyperlaneApp { IsmType.PAUSABLE, [config.owner], ); + await this.deployer?.transferOwnershipOfContracts(destination, config, { + [IsmType.PAUSABLE]: contract, + }); break; case IsmType.TEST_ISM: if (!this.deployer) { @@ -236,7 +240,9 @@ export class HyperlaneIsmFactory extends HyperlaneApp { config.domains = objFilter( config.domains, (domain, config): config is IsmConfig => { - const domainId = this.multiProvider.tryGetDomainId(domain); + const domainId = + chainMetadata[domain]?.domainId ?? + this.multiProvider.tryGetDomainId(domain); if (domainId === null) { warn( `Domain ${domain} doesn't have chain metadata provided, skipping ...`, @@ -245,8 +251,10 @@ export class HyperlaneIsmFactory extends HyperlaneApp { return domainId !== null; }, ); - const safeConfigDomains = Object.keys(config.domains).map((domain) => - this.multiProvider.getDomainId(domain), + const safeConfigDomains = Object.keys(config.domains).map( + (domain) => + chainMetadata[domain]?.domainId ?? + this.multiProvider.getDomainId(domain), ); const delta: RoutingIsmDelta = existingIsmAddress ? await routingModuleDelta(