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
pull/3069/merge
Yorke Rhodes 8 months ago committed by GitHub
parent 18d1d0d54e
commit 3ff8eb3c3d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 6
      .changeset/wild-horses-burn.md
  2. 1
      .github/workflows/test.yml
  3. 6
      typescript/infra/config/environments/mainnet3/core.ts
  4. 15
      typescript/infra/config/environments/mainnet3/igp.ts
  5. 8
      typescript/infra/config/environments/mainnet3/owners.ts
  6. 3
      typescript/infra/fork.sh
  7. 3
      typescript/infra/scripts/check-deploy.ts
  8. 9
      typescript/infra/scripts/deploy.ts
  9. 4
      typescript/infra/src/utils/fork.ts
  10. 8
      typescript/sdk/src/consts/multisigIsm.ts
  11. 2
      typescript/sdk/src/deploy/HyperlaneDeployer.ts
  12. 20
      typescript/sdk/src/hook/HyperlaneHookDeployer.ts
  13. 14
      typescript/sdk/src/ism/HyperlaneIsmFactory.ts

@ -0,0 +1,6 @@
---
'@hyperlane-xyz/infra': patch
'@hyperlane-xyz/sdk': patch
---
Patch transfer ownership in hook deployer

@ -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]

@ -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<CoreConfig> = objMap(owners, (local, owner) => {
const originMultisigs: ChainMap<MultisigConfig> = Object.fromEntries(
@ -56,7 +56,7 @@ export const core: ChainMap<CoreConfig> = 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<CoreConfig> = objMap(owners, (local, owner) => {
const pausableHook: PausableHookConfig = {
type: HookType.PAUSABLE,
...owner,
owner: DEPLOYER, // keep pausable hot
};
const aggregationHooks = objMap(
originMultisigs,

@ -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<IgpConfig> = 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,

@ -18,18 +18,20 @@ export const safes: ChainMap<Address | undefined> = {
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<OwnableConfig> = 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,
},
},
]),

@ -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

@ -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);
}
}

@ -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);
}

@ -15,9 +15,13 @@ export const resetFork = async (url: string) => {
export const impersonateAccount = async (
account: string,
spoofBalance?: number,
): Promise<JsonRpcSigner> => {
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);
};

@ -138,8 +138,8 @@ export const defaultMultisigConfigs: ChainMap<MultisigConfig> = {
threshold: 2,
validators: [
'0xf9e35ee88e4448a3673b4676a4e153e3584a08eb',
'0xae3e6bb6b3ece1c425aa6f47adc8cb0453c1f9a2',
'0xd98c9522cd9d3e3e00bee05ff76c34b91b266ec3',
'0x6B1d09A97b813D53e9D4b7523DA36604C0B52242', // caldera
'0x9ab11f38a609940153850df611c9a2175dcffe0f', // imperator
],
},
@ -147,8 +147,8 @@ export const defaultMultisigConfigs: ChainMap<MultisigConfig> = {
threshold: 2,
validators: [
'0xbfb8911b72cfb138c7ce517c57d9c691535dc517',
'0x6faa139c33a7e6f53cb101f6b2ae392298283ed2',
'0x0115e3a66820fb99da30d30e2ce52a453ba99d92',
'0x6B1d09A97b813D53e9D4b7523DA36604C0B52242', // caldera
'0x9e551b6694bbd295d7d6e6a2540c7d41ce70a3b9', // imperator
],
},

@ -640,7 +640,7 @@ export abstract class HyperlaneDeployer<
return ret;
}
protected async transferOwnershipOfContracts<K extends keyof Factories>(
async transferOwnershipOfContracts<K extends keyof Factories>(
chain: ChainName,
config: OwnableConfig<K>,
ownables: Partial<Record<K, Ownable>>,

@ -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;
}
}

@ -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<ProxyFactoryFactories> {
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<ProxyFactoryFactories> {
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<ProxyFactoryFactories> {
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(

Loading…
Cancel
Save