Configure additional onchain governance safeguards (#3360)

### Description

- Set validator announce owner to deployer to minimize effective
governance changes following
https://github.com/hyperlane-xyz/hyperlane-monorepo/pull/3315

### Drive-by changes

- Remove special case hack in the core checker for proxy admin timelock
ownership

### Related issues

- Followup on https://github.com/hyperlane-xyz/issues/issues/813

### Backward compatibility

Yes

### Testing

Env Tests
cosmos-gas-prices
Yorke Rhodes 8 months ago committed by GitHub
parent d535e66297
commit 77de7abdd4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 23
      typescript/infra/config/environments/mainnet3/owners.ts
  2. 8
      typescript/sdk/src/consts/environments/mainnet.json
  3. 3
      typescript/sdk/src/core/CoreDeployer.hardhat-test.ts
  4. 11
      typescript/sdk/src/core/HyperlaneCoreChecker.ts
  5. 25
      typescript/sdk/src/core/HyperlaneCoreDeployer.ts
  6. 61
      typescript/sdk/src/core/TestRecipientDeployer.ts
  7. 2
      typescript/sdk/src/deploy/HyperlaneDeployer.ts

@ -9,16 +9,19 @@ export const timelocks: ChainMap<Address | undefined> = {
export const safes: ChainMap<Address | undefined> = {
mantapacific: '0x03ed2D65f2742193CeD99D48EbF1F1D6F12345B6', // does not have a UI
celo: '0x1DE69322B55AC7E0999F8e7738a1428C8b130E4d',
ethereum: '0x12C5AB61Fe17dF9c65739DBa73dF294708f78d23',
avalanche: '0xDF9B28B76877f1b1B4B8a11526Eb7D8D7C49f4f3',
polygon: '0x0D195469f76146F6ae3De8fc887e0f0DFBA691e7',
bsc: '0xA0d3dcB9d61Fba32cc02Ad63983e101b29E2f28a',
arbitrum: '0xbA47E1b575980B7D1b1508cc48bE1Df4EE508111',
optimism: '0xb523CFAf45AACF472859f8B793CB0BFDB16bD257',
moonbeam: '0xF0cb1f968Df01fc789762fddBfA704AE0F952197',
gnosis: '0x36b0AA0e7d04e7b825D7E409FEa3c9A3d57E4C22',
celo: '0x879038d6Fc9F6D5e2BA73188bd078486d77e1156',
ethereum: '0x3965AC3D295641E452E0ea896a086A9cD7C6C5b6',
avalanche: '0x5bE94B17112B8F18eA9Ac8e559377B467556a3c3',
polygon: '0xf9cFD440CfBCfAB8473cc156485B7eE753b2913E',
bsc: '0x7bB2ADeDdC342ffb611dDC073095cc4B8C547170',
arbitrum: '0x03fD5BE9DF85F0017dC7F4DC3068dDF64fffF25e',
optimism: '0xbd7db3821806bc72D223F0AE521Bf82FcBd6Ef4d',
moonbeam: '0x594203849E52BF6ee0E511cD807Ca2D658893e37',
gnosis: '0x0Ac72fBc82c9c39F81242229631dfC38aA13031B',
inevm: '0x77F3863ea99F2360D84d4BA1A2E441857D0357fa', // caldera + injective
base: '0x3949eD0CD036D9FF662d97BD7aC1686051c4aeBF',
scroll: '0x6EeEbB9F7FB18DD5E59F82658c59B846715eD4F7',
polygonzkevm: '0x1610f578D4d77Fc4ae7ce2DD9AA0b98A5Cd0a9b2',
// injective: 'inj1632x8j35kenryam3mkrsez064sqg2y2fr0frzt',
// solana: 'EzppBFV2taxWw8kEjxNYvby6q7W1biJEqwP3iC7YgRe3',
};
@ -32,6 +35,8 @@ export const owners: ChainMap<OwnableConfig> = Object.fromEntries(
owner: safes[local] ?? DEPLOYER,
ownerOverrides: {
proxyAdmin: timelocks[local] ?? safes[local] ?? DEPLOYER,
validatorAnnounce: DEPLOYER, // unused
testRecipient: DEPLOYER,
},
},
]),

@ -214,7 +214,7 @@
"domainRoutingIsmFactory": "0x28fA9552F19039b450498B0d8e5DEAe0d0aAc559",
"pausableHook": "0x3A66Dc852e56d3748838b3C27CF381105b83705b",
"fallbackRoutingHook": "0x571f1435613381208477ac5d6974310d88AC7cB7",
"interchainSecurityModule": "0x43Ce4Eb4aE3585dDe9Ac6967Db5b06f7f6764C8a"
"interchainSecurityModule": "0x4fA1005f770F719771de78830E98E1096cFFe561"
},
"avalanche": {
"storageGasOracle": "0x175821F30AdCAA4bbB72Ce98eF76C2E0De2C3f21",
@ -272,10 +272,12 @@
"protocolFee": "0x0D63128D887159d63De29497dfa45AFc7C699AE4",
"mailbox": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7",
"validatorAnnounce": "0x15ab173bDB6832f9b64276bA128659b0eD77730B",
"interchainSecurityModule": "0x3052aD50De54aAAc5D364d80bBE681d29e924597",
"interchainSecurityModule": "0xA158E8CaadE23eA09A84d8182Be86062842b23E3",
"pausableIsm": "0x6Fae4D9935E2fcb11fC79a64e917fb2BF14DaFaa",
"staticAggregationIsm": "0x3052aD50De54aAAc5D364d80bBE681d29e924597",
"pausableHook": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0"
"pausableHook": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0",
"fallbackRoutingHook": "0xF8DbA46fF9D8ef650052c89CA2Df793FaBc375F9",
"testRecipient": "0x7b2e996742fA42d223652A344252B725D1bC428C"
},
"viction": {
"staticMerkleRootMultisigIsmFactory": "0x2C1FAbEcd7bFBdEBF27CcdB67baADB38b6Df90fC",

@ -113,8 +113,7 @@ describe('core', async () => {
// 3x1 for aggregation ISM deploy
// 3x1 for setting ISM transaction for mailbox
// 3x1 for setting ISM transaction for test recipient
const numTransactions = 3 * TestChains.length;
const numTransactions = 2 * TestChains.length;
const nonceAfter = await signer.getTransactionCount();
expect(nonceAfter).to.equal(nonceBefore + numTransactions);
});

@ -1,6 +1,6 @@
import { ethers, utils as ethersUtils } from 'ethers';
import { Address, assert, eqAddress } from '@hyperlane-xyz/utils';
import { assert, eqAddress } from '@hyperlane-xyz/utils';
import { BytecodeHash } from '../consts/bytecode';
import { HyperlaneAppChecker } from '../deploy/HyperlaneAppChecker';
@ -51,14 +51,7 @@ export class HyperlaneCoreChecker extends HyperlaneAppChecker<
async checkDomainOwnership(chain: ChainName): Promise<void> {
const config = this.configMap[chain];
const ownableOverrides: Record<string, Address> =
config.ownerOverrides || {};
if (config.upgrade) {
const proxyOwner = await this.app.getContracts(chain).proxyAdmin.owner();
ownableOverrides.proxyAdmin = proxyOwner;
}
return this.checkOwnership(chain, config.owner, ownableOverrides);
return this.checkOwnership(chain, config.owner, config.ownerOverrides);
}
async checkMailbox(chain: ChainName): Promise<void> {

@ -19,10 +19,7 @@ import { moduleMatchesConfig } from '../ism/utils';
import { MultiProvider } from '../providers/MultiProvider';
import { ChainMap, ChainName } from '../types';
import {
TestRecipientConfig,
TestRecipientDeployer,
} from './TestRecipientDeployer';
import { TestRecipientDeployer } from './TestRecipientDeployer';
import { CoreAddresses, CoreFactories, coreFactories } from './contracts';
import { CoreConfig } from './types';
@ -213,15 +210,12 @@ export class HyperlaneCoreDeployer extends HyperlaneDeployer<
async deployTestRecipient(
chain: ChainName,
interchainSecurityModule: Address,
interchainSecurityModule?: IsmConfig,
): Promise<TestRecipient> {
const config: TestRecipientConfig = {
interchainSecurityModule: interchainSecurityModule,
};
const testRecipient = await this.testRecipient.deployContracts(
chain,
config,
);
this.testRecipient.cacheAddressesMap(this.cachedAddresses);
const testRecipient = await this.testRecipient.deployContracts(chain, {
interchainSecurityModule,
});
this.addDeployedContracts(chain, testRecipient);
return testRecipient.testRecipient;
}
@ -244,11 +238,6 @@ export class HyperlaneCoreDeployer extends HyperlaneDeployer<
mailbox.address,
);
const testRecipient = await this.deployTestRecipient(
chain,
this.cachedAddresses[chain].interchainSecurityModule,
);
if (config.upgrade) {
const timelockController = await this.deployTimelock(
chain,
@ -260,6 +249,8 @@ export class HyperlaneCoreDeployer extends HyperlaneDeployer<
};
}
const testRecipient = await this.deployTestRecipient(chain);
const contracts = {
mailbox,
proxyAdmin,

@ -1,16 +1,18 @@
import debug from 'debug';
import { TestRecipient, TestRecipient__factory } from '@hyperlane-xyz/core';
import { Address, eqAddress } from '@hyperlane-xyz/utils';
import { Address } from '@hyperlane-xyz/utils';
import { HyperlaneDeployer } from '../deploy/HyperlaneDeployer';
import { ContractVerifier } from '../deploy/verify/ContractVerifier';
import { MultiProvider } from '../providers/MultiProvider';
import { MailboxClientConfig } from '../router/types';
import { ChainName } from '../types';
export type TestRecipientConfig = {
interchainSecurityModule: Address;
};
export type TestRecipientConfig = Pick<
MailboxClientConfig,
'interchainSecurityModule'
>;
export type TestRecipientContracts = {
testRecipient: TestRecipient;
@ -43,48 +45,15 @@ export class TestRecipientDeployer extends HyperlaneDeployer<
chain: ChainName,
config: TestRecipientConfig,
): Promise<TestRecipientContracts> {
const predeployed = this.readCache(
chain,
this.factories['testRecipient'],
'testRecipient',
);
let usePreviousDeployment = false;
if (
predeployed &&
eqAddress(
await predeployed.owner(),
await this.multiProvider.getSignerAddress(chain),
)
) {
usePreviousDeployment = true;
}
const testRecipient = await this.deployContract(
chain,
'testRecipient',
[],
undefined,
usePreviousDeployment,
);
try {
this.logger(`Checking ISM ${chain}`);
const ism = await testRecipient.interchainSecurityModule();
this.logger(`Found ISM for on ${chain}: ${ism}`);
if (!eqAddress(ism, config.interchainSecurityModule)) {
this.logger(
`Current ISM does not match config. Updating to ${config.interchainSecurityModule}`,
);
const tx = testRecipient.setInterchainSecurityModule(
config.interchainSecurityModule,
);
await this.runIfOwner(
chain,
testRecipient,
async () => await this.multiProvider.handleTx(chain, tx),
);
}
} catch (error) {
this.logger(`Failed to check/update ISM for ${chain}: ${error}`);
this.logger('Leaving ISM as is and continuing.');
const testRecipient = await this.deployContract(chain, 'testRecipient', []);
if (config.interchainSecurityModule) {
await this.configureIsm(
chain,
testRecipient,
config.interchainSecurityModule,
(tr) => tr.interchainSecurityModule(),
(tr, ism) => tr.populateTransaction.setInterchainSecurityModule(ism),
);
}
return {
testRecipient,

@ -214,7 +214,7 @@ export abstract class HyperlaneDeployer<
let matches = false;
let targetIsm: Address;
if (typeof config === 'string') {
if (configuredIsm === config) {
if (eqAddress(configuredIsm, config)) {
matches = true;
} else {
targetIsm = config;

Loading…
Cancel
Save