Skip to content

Commit

Permalink
cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
aroralanuk committed Mar 25, 2024
1 parent 5fc3b1b commit c4bc1c3
Show file tree
Hide file tree
Showing 20 changed files with 59 additions and 622 deletions.
40 changes: 0 additions & 40 deletions typescript/infra/scripts/check-deploy.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { HelloWorldChecker } from '@hyperlane-xyz/helloworld';
import {
HypERC20App,
HypERC20Checker,
HyperlaneCore,
HyperlaneCoreChecker,
HyperlaneIgp,
Expand All @@ -11,7 +9,6 @@ import {
InterchainAccountChecker,
InterchainQuery,
InterchainQueryChecker,
TokenType,
resolveAccountOwner,
} from '@hyperlane-xyz/sdk';

Expand All @@ -26,7 +23,6 @@ import { impersonateAccount, useLocalProvider } from '../src/utils/fork';

import {
Modules,
getAddresses,
getArgs as getRootArgs,
withContext,
withModuleAndFork,
Expand Down Expand Up @@ -115,42 +111,6 @@ async function check() {
ismFactory,
);
governor = new ProxiedRouterGovernor(checker);
} else if (module === Modules.WARP) {
// test config
const plumetestnet = {
...routerConfig.plumetestnet,
type: TokenType.synthetic,
name: 'Wrapped Ether',
symbol: 'WETH',
decimals: 18,
totalSupply: '0',
gas: 0,
};
const sepolia = {
...routerConfig.sepolia,
type: TokenType.native,
gas: 0,
};
const config = {
plumetestnet,
sepolia,
};
const addresses = getAddresses(environment, Modules.WARP);
const filteredAddresses = Object.keys(addresses) // filter out changes not in config
.filter((key) => key in config)
.reduce((obj, key) => {
obj[key] = addresses[key];
return obj;
}, {} as typeof addresses);
const app = HypERC20App.fromAddressesMap(filteredAddresses, multiProvider);

const checker = new HypERC20Checker(
multiProvider,
app,
config as any,
ismFactory,
);
governor = new ProxiedRouterGovernor(checker, ica);
} else {
console.log(`Skipping ${module}, checker or governor unimplemented`);
return;
Expand Down
43 changes: 15 additions & 28 deletions typescript/infra/scripts/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
import { objMap } from '@hyperlane-xyz/utils';

import { Contexts } from '../config/contexts';
import { safes } from '../config/environments/mainnet3/owners';
import { deployEnvToSdkEnv } from '../src/config/environment';
import { deployWithArtifacts } from '../src/deployment/deploy';
import { TestQuerySenderDeployer } from '../src/deployment/testcontracts/testquerysender';
Expand Down Expand Up @@ -122,31 +123,19 @@ async function main() {
multiProvider,
);
const routerConfig = core.getRouterConfig(envConfig.owners);
console.log('routerConfig', routerConfig.sepolia.owner);
// const scrollsepolia = {
// ...routerConfig.scrollsepolia,
// type: TokenType.synthetic,
// name: 'Wrapped Ether',
// symbol: 'WETH',
// decimals: 18,
// totalSupply: '0',
// };
const sepolia = {
...routerConfig.sepolia,
const inevm = {
...routerConfig.inevm,
type: TokenType.native,
interchainSecurityModule: ethers.constants.AddressZero,
owner: safes.inevm,
};
const plumetestnet = {
...routerConfig.plumetestnet,
type: TokenType.synthetic,
name: 'Wrapped Ether',
symbol: 'WETH',
decimals: 18,
totalSupply: '0',
const injective = {
...routerConfig.injective,
type: TokenType.native,
};
config = {
// scrollsepolia,
plumetestnet,
sepolia,
inevm,
injective,
};
// return;
deployer = new HypERC20Deployer(
Expand All @@ -168,15 +157,8 @@ async function main() {
} else if (module === Modules.INTERCHAIN_ACCOUNTS) {
const core = HyperlaneCore.fromEnvironment(env, multiProvider);
config = core.getRouterConfig(envConfig.owners);
// filter config to only include sepolia and optimismgoerli for now
config = {
sepolia: config.sepolia,
// scrollsepolia: config.scrollsepolia,
plumetestnet: config.plumetestnet,
};
deployer = new InterchainAccountDeployer(multiProvider, contractVerifier);
const addresses = getAddresses(environment, Modules.INTERCHAIN_ACCOUNTS);
console.log('deploy: ICA addresses', JSON.stringify(addresses, null, 2));
InterchainAccount.fromAddressesMap(addresses, multiProvider);
} else if (module === Modules.INTERCHAIN_QUERY_SYSTEM) {
const core = HyperlaneCore.fromEnvironment(env, multiProvider);
Expand Down Expand Up @@ -230,6 +212,11 @@ async function main() {
return;
}

// cache addresses for interchain account support
deployer.cacheAddressesMap(
getAddresses(environment, Modules.INTERCHAIN_ACCOUNTS),
);

const modulePath = getModuleDirectory(environment, module, context);

console.log(`Deploying to ${modulePath}`);
Expand Down
1 change: 0 additions & 1 deletion typescript/infra/src/deployment/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ export async function deployWithArtifacts<Config extends object>(
if (cache.read) {
let addressesMap = {};
try {
console.log('at deployWithArtifacts');
addressesMap = readJSONAtPath(cache.addresses);
} catch (e) {
console.error('Failed to load cached addresses');
Expand Down
152 changes: 36 additions & 116 deletions typescript/infra/src/govern/HyperlaneAppGovernor.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,14 @@
import { BigNumber } from 'ethers';
import { prompts } from 'prompts';

import { Ownable__factory } from '@hyperlane-xyz/core';
import {
AccountConfig,
ChainMap,
ChainName,
HyperlaneApp,
HyperlaneAppChecker,
InterchainAccount,
OwnableConfig,
OwnerViolation,
} from '@hyperlane-xyz/sdk';
import {
Address,
CallData,
bytes32ToAddress,
eqAddress,
objMap,
} from '@hyperlane-xyz/utils';
import { Address, CallData, objMap } from '@hyperlane-xyz/utils';

import { canProposeSafeTransactions } from '../utils/safe';

Expand All @@ -30,9 +20,9 @@ import {
} from './multisend';

export enum SubmissionType {
MANUAL = 0,
SAFE = 1,
SIGNER = 2,
MANUAL = 'MANUAL',
SIGNER = 'SIGNER',
SAFE = 'SAFE',
}

export type AnnotatedCallData = CallData & {
Expand All @@ -45,20 +35,13 @@ export abstract class HyperlaneAppGovernor<
Config extends OwnableConfig,
> {
readonly checker: HyperlaneAppChecker<App, Config>;
protected calls: ChainMap<AnnotatedCallData[]>;
private calls: ChainMap<AnnotatedCallData[]>;
private canPropose: ChainMap<Map<string, boolean>>;
readonly interchainAccount?: InterchainAccount;

constructor(
checker: HyperlaneAppChecker<App, Config>,
readonly ica?: InterchainAccount,
) {
constructor(checker: HyperlaneAppChecker<App, Config>) {
this.checker = checker;
this.calls = objMap(this.checker.app.contractsMap, () => []);
this.canPropose = objMap(this.checker.app.contractsMap, () => new Map());
if (ica) {
this.interchainAccount = ica;
}
}

async govern(confirm = true, chain?: ChainName) {
Expand Down Expand Up @@ -117,11 +100,7 @@ export abstract class HyperlaneAppGovernor<
if (confirmed) {
console.log(`Submitting calls on ${chain} via ${submissionType}`);
await multiSend.sendTransactions(
calls.map((call) => ({
to: call.to,
data: call.data,
value: call.value,
})),
calls.map((call) => ({ to: call.to, data: call.data })),
);
} else {
console.log(
Expand All @@ -135,84 +114,29 @@ export abstract class HyperlaneAppGovernor<
SubmissionType.SIGNER,
new SignerMultiSend(this.checker.multiProvider, chain),
);
let safeOwner: Address;
if (typeof this.checker.configMap[chain].owner === 'string') {
safeOwner = this.checker.configMap[chain].owner as Address;
} else {
safeOwner = (this.checker.configMap[chain].owner as AccountConfig).owner;
}
await sendCallsForType(
SubmissionType.SAFE,
new SafeMultiSend(this.checker.multiProvider, chain, safeOwner),
new SafeMultiSend(
this.checker.multiProvider,
chain,
this.checker.configMap[chain].owner,
),
);
await sendCallsForType(SubmissionType.MANUAL, new ManualMultiSend(chain));
}

protected pushCall(chain: ChainName, call: AnnotatedCallData) {
this.calls[chain] = this.calls[chain] || [];
this.calls[chain].push(call);
}

protected popCall(chain: ChainName): AnnotatedCallData | undefined {
return this.calls[chain].pop();
}

protected abstract mapViolationsToCalls(): Promise<void>;

protected async inferCallSubmissionTypes() {
for (const chain of Object.keys(this.calls)) {
for (const call of this.calls[chain]) {
let submissionType = await this.inferCallSubmissionType(chain, call);
if (!submissionType) {
submissionType = await this.inferICAEncodedSubmissionType(
chain,
call,
);
}
call.submissionType = submissionType;
}
}
}

protected async inferICAEncodedSubmissionType(
chain: ChainName,
call: AnnotatedCallData,
): Promise<SubmissionType> {
const multiProvider = this.checker.multiProvider;
const signer = multiProvider.getSigner(chain);
if (this.interchainAccount) {
const ownableAddress = call.to;
const ownable = Ownable__factory.connect(ownableAddress, signer); // mailbox
const account = Ownable__factory.connect(await ownable.owner(), signer);
const localOwner = await account.owner();
if (eqAddress(localOwner, this.interchainAccount.routerAddress(chain))) {
const [originDomain, remoteOwner] =
await this.interchainAccount.getAccountOwner(chain, account.address);
const origin =
this.interchainAccount.multiProvider.getChainName(originDomain);
console.log(
`Inferred call for ICA remote owner ${bytes32ToAddress(
remoteOwner,
)} on ${origin}`,
);
const callRemote = await this.interchainAccount.getCallRemote(
origin,
chain,
[call],
);
const encodedCall = {
...callRemote, // encode the call data for ICA
description: `${call.description} - interchain account call from ${origin} to ${chain}`,
};
const subType = await this.inferCallSubmissionType(origin, encodedCall);
if (subType) {
this.popCall(chain);
this.pushCall(origin, encodedCall);
return subType;
}
call.submissionType = await this.inferCallSubmissionType(chain, call);
}
}
return SubmissionType.MANUAL;
}

protected async inferCallSubmissionType(
Expand All @@ -224,7 +148,6 @@ export abstract class HyperlaneAppGovernor<
const signerAddress = await signer.getAddress();

const transactionSucceedsFromSender = async (
chain: ChainName,
submitterAddress: Address,
): Promise<boolean> => {
try {
Expand All @@ -234,38 +157,36 @@ export abstract class HyperlaneAppGovernor<
return false;
};

if (await transactionSucceedsFromSender(chain, signerAddress)) {
if (await transactionSucceedsFromSender(signerAddress)) {
return SubmissionType.SIGNER;
}

// 2. Check if the call will succeed via Gnosis Safe.
const safeAddress = this.checker.configMap[chain].owner;

if (typeof safeAddress === 'string') {
if (!safeAddress) throw new Error(`Owner address not found for ${chain}`);
// 2a. Confirm that the signer is a Safe owner or delegate.
// This should implicitly check whether or not the owner is a gnosis
// safe.
if (!this.canPropose[chain].has(safeAddress)) {
this.canPropose[chain].set(
if (!safeAddress) throw new Error(`Owner address not found for ${chain}`);
// 2a. Confirm that the signer is a Safe owner or delegate.
// This should implicitly check whether or not the owner is a gnosis
// safe.
if (!this.canPropose[chain].has(safeAddress)) {
this.canPropose[chain].set(
safeAddress,
await canProposeSafeTransactions(
signerAddress,
chain,
multiProvider,
safeAddress,
await canProposeSafeTransactions(
signerAddress,
chain,
multiProvider,
safeAddress,
),
);
}
// 2b. Check if calling from the owner/safeAddress will succeed.
if (
(this.canPropose[chain].get(safeAddress) &&
(await transactionSucceedsFromSender(chain, safeAddress))) ||
chain === 'moonbeam'
) {
return SubmissionType.SAFE;
}
),
);
}
// 2b. Check if calling from the owner/safeAddress will succeed.
if (
(this.canPropose[chain].get(safeAddress) &&
(await transactionSucceedsFromSender(safeAddress))) ||
chain === 'moonbeam'
) {
return SubmissionType.SAFE;
}

return SubmissionType.MANUAL;
}

Expand All @@ -276,7 +197,6 @@ export abstract class HyperlaneAppGovernor<
'transferOwnership',
[violation.expected],
),
value: BigNumber.from(0),
description: `Transfer ownership of ${violation.name} at ${violation.contract.address} to ${violation.expected}`,
});
}
Expand Down
Loading

0 comments on commit c4bc1c3

Please sign in to comment.