diff --git a/solidity/contracts/isms/PausableIsm.sol b/solidity/contracts/isms/PausableIsm.sol index d2c4784f3..cbe696d2e 100644 --- a/solidity/contracts/isms/PausableIsm.sol +++ b/solidity/contracts/isms/PausableIsm.sol @@ -11,6 +11,10 @@ import {IInterchainSecurityModule} from "../interfaces/IInterchainSecurityModule contract PausableIsm is IInterchainSecurityModule, Ownable, Pausable { uint8 public constant override moduleType = uint8(Types.NULL); + constructor(address owner) Ownable() Pausable() { + _transferOwnership(owner); + } + /** * @inheritdoc IInterchainSecurityModule * @dev Reverts when paused, otherwise returns `true`. diff --git a/solidity/test/isms/PausableIsm.t.sol b/solidity/test/isms/PausableIsm.t.sol index 74a2bfdd7..c31511e29 100644 --- a/solidity/test/isms/PausableIsm.t.sol +++ b/solidity/test/isms/PausableIsm.t.sol @@ -8,24 +8,35 @@ import {PausableIsm} from "../../contracts/isms/PausableIsm.sol"; contract PausableIsmTest is Test { PausableIsm ism; + address owner; + function setUp() public { - ism = new PausableIsm(); + owner = msg.sender; + ism = new PausableIsm(owner); } function test_verify() public { assertTrue(ism.verify("", "")); + vm.prank(owner); ism.pause(); vm.expectRevert(bytes("Pausable: paused")); ism.verify("", ""); } function test_pause() public { + vm.expectRevert(bytes("Ownable: caller is not the owner")); + ism.pause(); + vm.prank(owner); ism.pause(); assertTrue(ism.paused()); } function test_unpause() public { + vm.prank(owner); ism.pause(); + vm.expectRevert(bytes("Ownable: caller is not the owner")); + ism.unpause(); + vm.prank(owner); ism.unpause(); assertFalse(ism.paused()); } diff --git a/typescript/infra/config/environments/mainnet3/core.ts b/typescript/infra/config/environments/mainnet3/core.ts index 7fa613833..c228b2d94 100644 --- a/typescript/infra/config/environments/mainnet3/core.ts +++ b/typescript/infra/config/environments/mainnet3/core.ts @@ -2,23 +2,67 @@ import { BigNumber, ethers } from 'ethers'; import { AggregationHookConfig, + AggregationIsmConfig, ChainMap, CoreConfig, HookType, IgpHookConfig, + IsmType, MerkleTreeHookConfig, + MultisigConfig, + MultisigIsmConfig, + PausableHookConfig, + PausableIsmConfig, ProtocolFeeHookConfig, + RoutingIsmConfig, + defaultMultisigConfigs, } from '@hyperlane-xyz/sdk'; import { objMap } from '@hyperlane-xyz/utils'; -import { Contexts } from '../../contexts'; -import { routingIsm } from '../../routingIsm'; - +import { supportedChainNames } from './chains'; import { igp } from './igp'; import { owners, safes } from './owners'; export const core: ChainMap = objMap(owners, (local, owner) => { - const defaultIsm = routingIsm('mainnet3', local, Contexts.Hyperlane); + const originMultisigs: ChainMap = Object.fromEntries( + supportedChainNames + .filter((chain) => chain !== local) + .map((origin) => [origin, defaultMultisigConfigs[origin]]), + ); + + const merkleRoot = (multisig: MultisigConfig): MultisigIsmConfig => ({ + type: IsmType.MERKLE_ROOT_MULTISIG, + ...multisig, + }); + + const messageIdIsm = (multisig: MultisigConfig): MultisigIsmConfig => ({ + type: IsmType.MESSAGE_ID_MULTISIG, + ...multisig, + }); + + const routingIsm: RoutingIsmConfig = { + type: IsmType.ROUTING, + domains: objMap( + originMultisigs, + (_, multisig): AggregationIsmConfig => ({ + type: IsmType.AGGREGATION, + modules: [messageIdIsm(multisig), merkleRoot(multisig)], + threshold: 1, + }), + ), + owner, + }; + + const pausableIsm: PausableIsmConfig = { + type: IsmType.PAUSABLE, + owner, + }; + + const defaultIsm: AggregationIsmConfig = { + type: IsmType.AGGREGATION, + modules: [routingIsm, pausableIsm], + threshold: 2, + }; const merkleHook: MerkleTreeHookConfig = { type: HookType.MERKLE_TREE, @@ -29,9 +73,14 @@ export const core: ChainMap = objMap(owners, (local, owner) => { ...igp[local], }; + const pausableHook: PausableHookConfig = { + type: HookType.PAUSABLE, + owner, + }; + const defaultHook: AggregationHookConfig = { type: HookType.AGGREGATION, - hooks: [merkleHook, igpHook], + hooks: [pausableHook, merkleHook, igpHook], }; const requiredHook: ProtocolFeeHookConfig = { diff --git a/typescript/infra/config/environments/testnet4/core.ts b/typescript/infra/config/environments/testnet4/core.ts index f8747befa..5d23ef799 100644 --- a/typescript/infra/config/environments/testnet4/core.ts +++ b/typescript/infra/config/environments/testnet4/core.ts @@ -5,17 +5,19 @@ import { AggregationIsmConfig, ChainMap, CoreConfig, - FallbackRoutingHookConfig, HookType, IgpHookConfig, IsmType, MerkleTreeHookConfig, MultisigConfig, MultisigIsmConfig, + PausableHookConfig, + PausableIsmConfig, ProtocolFeeHookConfig, RoutingIsmConfig, defaultMultisigConfigs, } from '@hyperlane-xyz/sdk'; +import { DomainRoutingHookConfig } from '@hyperlane-xyz/sdk/src/hook/types'; import { objMap } from '@hyperlane-xyz/utils'; import { supportedChainNames } from './chains'; @@ -39,7 +41,7 @@ export const core: ChainMap = objMap(owners, (local, owner) => { ...multisig, }); - const defaultIsm: RoutingIsmConfig = { + const routingIsm: RoutingIsmConfig = { type: IsmType.ROUTING, domains: objMap( originMultisigs, @@ -52,6 +54,17 @@ export const core: ChainMap = objMap(owners, (local, owner) => { owner, }; + const pausableIsm: PausableIsmConfig = { + type: IsmType.PAUSABLE, + owner, + }; + + const defaultIsm: AggregationIsmConfig = { + type: IsmType.AGGREGATION, + modules: [routingIsm, pausableIsm], + threshold: 2, + }; + const merkleHook: MerkleTreeHookConfig = { type: HookType.MERKLE_TREE, }; @@ -61,18 +74,22 @@ export const core: ChainMap = objMap(owners, (local, owner) => { ...igp[local], }; + const pausableHook: PausableHookConfig = { + type: HookType.PAUSABLE, + owner, + }; + const aggregationHooks = objMap( originMultisigs, (_origin, _): AggregationHookConfig => ({ type: HookType.AGGREGATION, - hooks: [igpHook, merkleHook], + hooks: [pausableHook, merkleHook, igpHook], }), ); - const defaultHook: FallbackRoutingHookConfig = { - type: HookType.FALLBACK_ROUTING, + const defaultHook: DomainRoutingHookConfig = { + type: HookType.ROUTING, owner, - fallback: merkleHook, domains: aggregationHooks, }; diff --git a/typescript/infra/src/deployment/deploy.ts b/typescript/infra/src/deployment/deploy.ts index 3de8269dc..df7de5390 100644 --- a/typescript/infra/src/deployment/deploy.ts +++ b/typescript/infra/src/deployment/deploy.ts @@ -20,7 +20,7 @@ import { writeMergedJSONAtPath, } from '../utils/utils'; -export async function deployWithArtifacts( +export async function deployWithArtifacts( configMap: ChainMap, deployer: HyperlaneDeployer, cache: { @@ -71,7 +71,7 @@ export async function deployWithArtifacts( await postDeploy(deployer, cache, agentConfig); } -export async function postDeploy( +export async function postDeploy( deployer: HyperlaneDeployer, cache: { addresses: string; diff --git a/typescript/sdk/src/core/types.ts b/typescript/sdk/src/core/types.ts index f8da0c8b9..f8bc7a1ae 100644 --- a/typescript/sdk/src/core/types.ts +++ b/typescript/sdk/src/core/types.ts @@ -2,17 +2,17 @@ import type { Mailbox } from '@hyperlane-xyz/core'; import type { Address, ParsedMessage } from '@hyperlane-xyz/utils'; import type { UpgradeConfig } from '../deploy/proxy'; -import type { CheckerViolation } from '../deploy/types'; +import type { CheckerViolation, OwnableConfig } from '../deploy/types'; import { HookConfig } from '../hook/types'; import type { IsmConfig } from '../ism/types'; import type { ChainName } from '../types'; -export type CoreConfig = { +import { CoreFactories } from './contracts'; + +export type CoreConfig = OwnableConfig & { defaultIsm: IsmConfig; defaultHook: HookConfig; requiredHook: HookConfig; - owner: Address; - ownerOverrides?: Record; remove?: boolean; upgrade?: UpgradeConfig; }; diff --git a/typescript/sdk/src/deploy/HyperlaneDeployer.ts b/typescript/sdk/src/deploy/HyperlaneDeployer.ts index 0875bc4af..c47ee7ca6 100644 --- a/typescript/sdk/src/deploy/HyperlaneDeployer.ts +++ b/typescript/sdk/src/deploy/HyperlaneDeployer.ts @@ -53,7 +53,7 @@ export interface DeployerOptions { } export abstract class HyperlaneDeployer< - Config, + Config extends object, Factories extends HyperlaneFactories, > { public verificationInputs: ChainMap = {}; diff --git a/typescript/sdk/src/deploy/types.ts b/typescript/sdk/src/deploy/types.ts index 49380f19b..8ce65d835 100644 --- a/typescript/sdk/src/deploy/types.ts +++ b/typescript/sdk/src/deploy/types.ts @@ -5,9 +5,19 @@ import type { Ownable, TimelockController, } from '@hyperlane-xyz/core'; +import { Address } from '@hyperlane-xyz/utils'; import type { ChainName } from '../types'; +export type OwnableConfig = { + owner: Address; + ownerOverrides?: Partial>; +}; + +export function isOwnableConfig(config: object): config is OwnableConfig { + return 'owner' in config; +} + export interface CheckerViolation { chain: ChainName; type: string; diff --git a/typescript/sdk/src/gas/types.ts b/typescript/sdk/src/gas/types.ts index ca0c0485a..c4f76c05a 100644 --- a/typescript/sdk/src/gas/types.ts +++ b/typescript/sdk/src/gas/types.ts @@ -3,15 +3,16 @@ import { BigNumber } from 'ethers'; import { InterchainGasPaymaster } from '@hyperlane-xyz/core'; import type { Address } from '@hyperlane-xyz/utils'; -import type { CheckerViolation } from '../deploy/types'; +import type { CheckerViolation, OwnableConfig } from '../deploy/types'; import { ChainMap } from '../types'; +import { IgpFactories } from './contracts'; + export enum GasOracleContractType { StorageGasOracle = 'StorageGasOracle', } -export type IgpConfig = { - owner: Address; +export type IgpConfig = OwnableConfig & { beneficiary: Address; gasOracleType: ChainMap; oracleKey: Address; diff --git a/typescript/sdk/src/hook/HyperlaneHookDeployer.ts b/typescript/sdk/src/hook/HyperlaneHookDeployer.ts index 5eb961cf9..4c52d78fc 100644 --- a/typescript/sdk/src/hook/HyperlaneHookDeployer.ts +++ b/typescript/sdk/src/hook/HyperlaneHookDeployer.ts @@ -22,7 +22,7 @@ import { IsmType, OpStackIsmConfig } from '../ism/types'; import { MultiProvider } from '../providers/MultiProvider'; import { ChainMap, ChainName } from '../types'; -import { HookFactories, hookFactories } from './contracts'; +import { DeployedHook, HookFactories, hookFactories } from './contracts'; import { AggregationHookConfig, DomainRoutingHookConfig, @@ -59,17 +59,20 @@ export class HyperlaneHookDeployer extends HyperlaneDeployer< config: HookConfig, coreAddresses = this.core[chain], ): Promise> { - // other simple hooks can go here - let hook; + let hook: DeployedHook; if (config.type === HookType.MERKLE_TREE) { const mailbox = coreAddresses.mailbox; if (!mailbox) { throw new Error(`Mailbox address is required for ${config.type}`); } hook = await this.deployContract(chain, config.type, [mailbox]); - return { [config.type]: hook } as any; } else if (config.type === HookType.INTERCHAIN_GAS_PAYMASTER) { - return this.deployIgp(chain, config, coreAddresses) as any; + const { interchainGasPaymaster } = await this.deployIgp( + chain, + config, + coreAddresses, + ); + hook = interchainGasPaymaster; } else if (config.type === HookType.AGGREGATION) { return this.deployAggregation(chain, config, coreAddresses); // deploy from factory } else if (config.type === HookType.PROTOCOL_FEE) { @@ -81,8 +84,14 @@ export class HyperlaneHookDeployer extends HyperlaneDeployer< config.type === HookType.FALLBACK_ROUTING ) { hook = await this.deployRouting(chain, config, coreAddresses); + } else if (config.type === HookType.PAUSABLE) { + hook = await this.deployContract(chain, config.type, []); + await this.transferOwnershipOfContracts(chain, config.owner, { hook }); + } else { + throw new Error(`Unsupported hook config: ${config}`); } - const deployedContracts = { [config.type]: hook } as any; + + const deployedContracts = { [config.type]: hook } as any; // partial this.addDeployedContracts(chain, deployedContracts); return deployedContracts; } diff --git a/typescript/sdk/src/hook/contracts.ts b/typescript/sdk/src/hook/contracts.ts index 8d6abca0d..d7fa4995a 100644 --- a/typescript/sdk/src/hook/contracts.ts +++ b/typescript/sdk/src/hook/contracts.ts @@ -4,9 +4,11 @@ import { InterchainGasPaymaster__factory, MerkleTreeHook__factory, OPStackHook__factory, + PausableHook__factory, ProtocolFee__factory, StaticAggregationHook__factory, } from '@hyperlane-xyz/core'; +import { ValueOf } from '@hyperlane-xyz/utils'; import { HookType } from './types'; @@ -18,6 +20,11 @@ export const hookFactories = { [HookType.OP_STACK]: new OPStackHook__factory(), [HookType.ROUTING]: new DomainRoutingHook__factory(), [HookType.FALLBACK_ROUTING]: new FallbackDomainRoutingHook__factory(), + [HookType.PAUSABLE]: new PausableHook__factory(), }; export type HookFactories = typeof hookFactories; + +export type DeployedHook = Awaited< + ReturnType['deploy']> +>; diff --git a/typescript/sdk/src/hook/types.ts b/typescript/sdk/src/hook/types.ts index 0cbedfb7a..01f44cbd0 100644 --- a/typescript/sdk/src/hook/types.ts +++ b/typescript/sdk/src/hook/types.ts @@ -1,5 +1,6 @@ import { Address } from '@hyperlane-xyz/utils'; +import { OwnableConfig } from '../deploy/types'; import { IgpConfig } from '../gas/types'; import { ChainMap, ChainName } from '../types'; @@ -11,6 +12,7 @@ export enum HookType { OP_STACK = 'opStackHook', ROUTING = 'domainRoutingHook', FALLBACK_ROUTING = 'fallbackRoutingHook', + PAUSABLE = 'pausableHook', } export type MerkleTreeHookConfig = { @@ -26,12 +28,15 @@ export type IgpHookConfig = IgpConfig & { type: HookType.INTERCHAIN_GAS_PAYMASTER; }; -export type ProtocolFeeHookConfig = { +export type ProtocolFeeHookConfig = OwnableConfig & { type: HookType.PROTOCOL_FEE; maxProtocolFee: string; protocolFee: string; beneficiary: Address; - owner: Address; +}; + +export type PausableHookConfig = OwnableConfig & { + type: HookType.PAUSABLE; }; export type OpStackHookConfig = { @@ -40,8 +45,7 @@ export type OpStackHookConfig = { destinationChain: ChainName; }; -type RoutingHookConfig = { - owner: Address; +type RoutingHookConfig = OwnableConfig & { domains: ChainMap; }; @@ -61,7 +65,8 @@ export type HookConfig = | ProtocolFeeHookConfig | OpStackHookConfig | DomainRoutingHookConfig - | FallbackRoutingHookConfig; + | FallbackRoutingHookConfig + | PausableHookConfig; export type HooksConfig = { required: HookConfig; diff --git a/typescript/sdk/src/index.ts b/typescript/sdk/src/index.ts index 487a9685c..4013fa9a9 100644 --- a/typescript/sdk/src/index.ts +++ b/typescript/sdk/src/index.ts @@ -82,6 +82,7 @@ export { DeployerOptions, HyperlaneDeployer } from './deploy/HyperlaneDeployer'; export { HyperlaneProxyFactoryDeployer } from './deploy/HyperlaneProxyFactoryDeployer'; export { CheckerViolation, + OwnableConfig, OwnerViolation, ViolationType, } from './deploy/types'; @@ -125,6 +126,7 @@ export { IgpHookConfig, MerkleTreeHookConfig, OpStackHookConfig, + PausableHookConfig, ProtocolFeeHookConfig, } from './hook/types'; export { @@ -145,6 +147,7 @@ export { MultisigConfig, MultisigIsmConfig, OpStackIsmConfig, + PausableIsmConfig, RoutingIsmConfig, } from './ism/types'; export { @@ -303,7 +306,6 @@ export { GasConfig, GasRouterConfig, MailboxClientConfig, - OwnableConfig, ProxiedFactories, ProxiedRouterConfig, RouterAddress, diff --git a/typescript/sdk/src/ism/HyperlaneIsmFactory.ts b/typescript/sdk/src/ism/HyperlaneIsmFactory.ts index f5a0ae43b..bcfc2a4b6 100644 --- a/typescript/sdk/src/ism/HyperlaneIsmFactory.ts +++ b/typescript/sdk/src/ism/HyperlaneIsmFactory.ts @@ -16,6 +16,7 @@ import { MailboxClient__factory, OPStackIsm, OPStackIsm__factory, + PausableIsm__factory, StaticAddressSetFactory, StaticAggregationIsm__factory, StaticThresholdAddressSetFactory, @@ -145,6 +146,13 @@ export class HyperlaneIsmFactory extends HyperlaneApp { case IsmType.OP_STACK: contract = await this.deployOpStackIsm(destination, config); break; + case IsmType.PAUSABLE: + contract = await this.multiProvider.handleDeploy( + destination, + new PausableIsm__factory(), + [config.owner], + ); + break; case IsmType.TEST_ISM: contract = await this.multiProvider.handleDeploy( destination, @@ -616,7 +624,7 @@ export async function moduleMatchesConfig( ); // Check that the RoutingISM owner matches the config const owner = await routingIsm.owner(); - matches = matches && eqAddress(owner, config.owner); + matches &&= eqAddress(owner, config.owner); // check if the mailbox matches the config for fallback routing if (config.type === IsmType.FALLBACK_ROUTING) { const client = MailboxClient__factory.connect(moduleAddress, provider); @@ -653,8 +661,8 @@ export async function moduleMatchesConfig( const [subModules, threshold] = await aggregationIsm.modulesAndThreshold( '0x', ); - matches = matches && threshold === config.threshold; - matches = matches && subModules.length === config.modules.length; + matches &&= threshold === config.threshold; + matches &&= subModules.length === config.modules.length; const configIndexMatched = new Map(); for (const subModule of subModules) { @@ -666,12 +674,12 @@ export async function moduleMatchesConfig( // The submodule returned by the ISM must match exactly one // entry in the config. const count = subModuleMatchesConfig.filter(Boolean).length; - matches = matches && count === 1; + matches &&= count === 1; // That entry in the config should not have been matched already. subModuleMatchesConfig.forEach((matched, index) => { if (matched) { - matches = matches && !configIndexMatched.has(index); + matches &&= !configIndexMatched.has(index); configIndexMatched.set(index, true); } }); @@ -681,7 +689,7 @@ export async function moduleMatchesConfig( case IsmType.OP_STACK: { const opStackIsm = OPStackIsm__factory.connect(moduleAddress, provider); const type = await opStackIsm.moduleType(); - matches = matches && type === ModuleType.NULL; + matches &&= type === ModuleType.NULL; break; } case IsmType.TEST_ISM: { @@ -689,6 +697,17 @@ export async function moduleMatchesConfig( matches = true; break; } + case IsmType.PAUSABLE: { + const pausableIsm = PausableIsm__factory.connect(moduleAddress, provider); + const owner = await pausableIsm.owner(); + matches &&= eqAddress(owner, config.owner); + + if (config.paused) { + const isPaused = await pausableIsm.paused(); + matches &&= config.paused === isPaused; + } + break; + } default: { throw new Error('Unsupported ModuleType'); } @@ -789,8 +808,10 @@ export function collectValidators( aggregatedValidators.forEach((set) => { validators = validators.concat([...set]); }); - } else if (config.type === IsmType.TEST_ISM) { - // This is just a TestISM + } else if ( + config.type === IsmType.TEST_ISM || + config.type === IsmType.PAUSABLE + ) { return new Set([]); } else { throw new Error('Unsupported ModuleType'); diff --git a/typescript/sdk/src/ism/types.ts b/typescript/sdk/src/ism/types.ts index 8cd7886f2..12c84a2a9 100644 --- a/typescript/sdk/src/ism/types.ts +++ b/typescript/sdk/src/ism/types.ts @@ -3,10 +3,12 @@ import { IMultisigIsm, IRoutingIsm, OPStackIsm, + PausableIsm, TestIsm, } from '@hyperlane-xyz/core'; import type { Address, Domain, ValueOf } from '@hyperlane-xyz/utils'; +import { OwnableConfig } from '../deploy/types'; import { ChainMap } from '../types'; // this enum should match the IInterchainSecurityModule.sol enum @@ -31,6 +33,7 @@ export enum IsmType { MERKLE_ROOT_MULTISIG = 'merkleRootMultisigIsm', MESSAGE_ID_MULTISIG = 'messageIdMultisigIsm', TEST_ISM = 'testIsm', + PAUSABLE = 'pausableIsm', } // mapping between the two enums @@ -50,6 +53,8 @@ export function ismTypeToModuleType(ismType: IsmType): ModuleType { return ModuleType.MESSAGE_ID_MULTISIG; case IsmType.TEST_ISM: return ModuleType.NULL; + case IsmType.PAUSABLE: + return ModuleType.NULL; } } @@ -66,9 +71,13 @@ export type TestIsmConfig = { type: IsmType.TEST_ISM; }; -export type RoutingIsmConfig = { +export type PausableIsmConfig = OwnableConfig & { + type: IsmType.PAUSABLE; + paused?: boolean; +}; + +export type RoutingIsmConfig = OwnableConfig & { type: IsmType.ROUTING | IsmType.FALLBACK_ROUTING; - owner: Address; domains: ChainMap; }; @@ -90,7 +99,8 @@ export type IsmConfig = | MultisigIsmConfig | AggregationIsmConfig | OpStackIsmConfig - | TestIsmConfig; + | TestIsmConfig + | PausableIsmConfig; export type DeployedIsmType = { [IsmType.ROUTING]: IRoutingIsm; @@ -100,6 +110,7 @@ export type DeployedIsmType = { [IsmType.MESSAGE_ID_MULTISIG]: IMultisigIsm; [IsmType.OP_STACK]: OPStackIsm; [IsmType.TEST_ISM]: TestIsm; + [IsmType.PAUSABLE]: PausableIsm; }; export type DeployedIsm = ValueOf; diff --git a/typescript/sdk/src/router/HyperlaneRouterChecker.ts b/typescript/sdk/src/router/HyperlaneRouterChecker.ts index 7d3ded9a1..d56e29c77 100644 --- a/typescript/sdk/src/router/HyperlaneRouterChecker.ts +++ b/typescript/sdk/src/router/HyperlaneRouterChecker.ts @@ -19,7 +19,6 @@ import { ClientViolation, ClientViolationType, MailboxClientConfig, - OwnableConfig, RouterConfig, RouterViolation, RouterViolationType, @@ -49,7 +48,7 @@ export class HyperlaneRouterChecker< const router = this.app.router(this.app.getContracts(chain)); const checkMailboxClientProperty = async ( - property: keyof (MailboxClientConfig & OwnableConfig), + property: keyof MailboxClientConfig, actual: string, violationType: ClientViolationType, ) => { diff --git a/typescript/sdk/src/router/types.ts b/typescript/sdk/src/router/types.ts index 4026ea8f9..9dd5e86ce 100644 --- a/typescript/sdk/src/router/types.ts +++ b/typescript/sdk/src/router/types.ts @@ -8,17 +8,13 @@ import type { Address } from '@hyperlane-xyz/utils'; import { HyperlaneFactories } from '../contracts/types'; import { UpgradeConfig } from '../deploy/proxy'; -import { CheckerViolation } from '../deploy/types'; +import { CheckerViolation, OwnableConfig } from '../deploy/types'; import { IsmConfig } from '../ism/types'; export type RouterAddress = { router: Address; }; -export type OwnableConfig = { - owner: Address; -}; - export type ForeignDeploymentConfig = { foreignDeployment?: Address; };