feat: Add hook update into WarpModule.update() (#4891)

### Description
This is a multi-part PR.

This adds `createHookUpdateTxs()` to `WarpModule.update()` such that it
updates a warp route _without_ a hook, and one with an existing hook.

### Related issues

<!--
- Fixes #[issue number here]
-->

### Backward compatibility
Yes

### Testing
Unit Tests
pull/4892/merge
Lee 2 days ago committed by GitHub
parent 95f1a97e78
commit 170a0fc739
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 5
      .changeset/nice-oranges-glow.md
  2. 54
      typescript/cli/src/deploy/warp.ts
  3. 42
      typescript/cli/src/tests/warp-apply.e2e-test.ts
  4. 4
      typescript/sdk/src/hook/EvmHookModule.ts
  5. 148
      typescript/sdk/src/token/EvmERC20WarpModule.hardhat-test.ts
  6. 190
      typescript/sdk/src/token/EvmERC20WarpModule.ts

@ -0,0 +1,5 @@
---
'@hyperlane-xyz/sdk': minor
---
Add `createHookUpdateTxs()` to `WarpModule.update()` such that it 1) deploys a hook for a warp route _without_ an existing hook, or 2) update an existing hook.

@ -3,7 +3,7 @@ import { groupBy } from 'lodash-es';
import { stringify as yamlStringify } from 'yaml';
import { buildArtifact as coreBuildArtifact } from '@hyperlane-xyz/core/buildArtifact.js';
import { IRegistry } from '@hyperlane-xyz/registry';
import { ChainAddresses, IRegistry } from '@hyperlane-xyz/registry';
import {
AggregationIsmConfig,
AnnotatedEV5Transaction,
@ -30,7 +30,6 @@ import {
MultisigIsmConfig,
OpStackIsmConfig,
PausableIsmConfig,
ProxyFactoryFactoriesAddresses,
RemoteRouters,
RoutingIsmConfig,
SubmissionStrategy,
@ -519,7 +518,6 @@ async function extendWarpRoute(
const newDeployedContracts = await executeDeploy(
{
// TODO: use EvmERC20WarpModule when it's ready
context: params.context,
warpDeployConfig: extendedConfigs,
},
@ -549,7 +547,7 @@ async function updateExistingWarpRoute(
logBlue('Updating deployed Warp Routes');
const { multiProvider, registry } = params.context;
const registryAddresses =
(await registry.getAddresses()) as ChainMap<ProxyFactoryFactoriesAddresses>;
(await registry.getAddresses()) as ChainMap<ChainAddresses>;
const contractVerifier = new ContractVerifier(
multiProvider,
apiKeys,
@ -568,14 +566,31 @@ async function updateExistingWarpRoute(
`Missing artifacts for ${chain}. Probably new deployment. Skipping update...`,
);
const deployedTokenRoute = deployedConfig.addressOrDenom!;
const {
domainRoutingIsmFactory,
staticMerkleRootMultisigIsmFactory,
staticMessageIdMultisigIsmFactory,
staticAggregationIsmFactory,
staticAggregationHookFactory,
staticMerkleRootWeightedMultisigIsmFactory,
staticMessageIdWeightedMultisigIsmFactory,
} = registryAddresses[chain];
const evmERC20WarpModule = new EvmERC20WarpModule(
multiProvider,
{
config,
chain,
addresses: {
...registryAddresses[chain],
deployedTokenRoute: deployedConfig.addressOrDenom!,
deployedTokenRoute,
staticMerkleRootMultisigIsmFactory,
staticMessageIdMultisigIsmFactory,
staticAggregationIsmFactory,
staticAggregationHookFactory,
domainRoutingIsmFactory,
staticMerkleRootWeightedMultisigIsmFactory,
staticMessageIdWeightedMultisigIsmFactory,
},
},
contractVerifier,
@ -660,8 +675,7 @@ async function enrollRemoteRouters(
): Promise<AnnotatedEV5Transaction[]> {
logBlue(`Enrolling deployed routers with each other...`);
const { multiProvider, registry } = params.context;
const registryAddresses =
(await registry.getAddresses()) as ChainMap<ProxyFactoryFactoriesAddresses>;
const registryAddresses = await registry.getAddresses();
const deployedRoutersAddresses: ChainMap<Address> = objMap(
deployedContractsMap,
(_, contracts) => getRouter(contracts).address,
@ -678,20 +692,36 @@ async function enrollRemoteRouters(
objMap(deployedContractsMap, async (chain, contracts) => {
await retryAsync(async () => {
const router = getRouter(contracts); // Assume deployedContract always has 1 value
const deployedTokenRoute = router.address;
// Mutate the config.remoteRouters by setting it to all other routers to update
const warpRouteReader = new EvmERC20WarpRouteReader(
multiProvider,
chain,
);
const mutatedWarpRouteConfig =
await warpRouteReader.deriveWarpRouteConfig(router.address);
await warpRouteReader.deriveWarpRouteConfig(deployedTokenRoute);
const {
domainRoutingIsmFactory,
staticMerkleRootMultisigIsmFactory,
staticMessageIdMultisigIsmFactory,
staticAggregationIsmFactory,
staticAggregationHookFactory,
staticMerkleRootWeightedMultisigIsmFactory,
staticMessageIdWeightedMultisigIsmFactory,
} = registryAddresses[chain];
const evmERC20WarpModule = new EvmERC20WarpModule(multiProvider, {
config: mutatedWarpRouteConfig,
chain,
addresses: {
...registryAddresses[chain],
deployedTokenRoute: router.address,
deployedTokenRoute,
staticMerkleRootMultisigIsmFactory,
staticMessageIdMultisigIsmFactory,
staticAggregationIsmFactory,
staticAggregationHookFactory,
domainRoutingIsmFactory,
staticMerkleRootWeightedMultisigIsmFactory,
staticMessageIdWeightedMultisigIsmFactory,
},
});

@ -3,9 +3,12 @@ import { Wallet } from 'ethers';
import { ChainAddresses } from '@hyperlane-xyz/registry';
import {
HookType,
TokenRouterConfig,
TokenType,
WarpRouteDeployConfig,
normalizeConfig,
randomAddress,
} from '@hyperlane-xyz/sdk';
import { readYamlOrJson, writeYamlOrJson } from '../utils/files.js';
@ -95,6 +98,45 @@ describe('WarpApply e2e tests', async function () {
);
});
it('should update hook configuration', async () => {
const warpDeployPath = `${TEMP_PATH}/warp-route-deployment-2.yaml`;
// First read the existing config
const warpDeployConfig = await readWarpConfig(
CHAIN_NAME_2,
WARP_CORE_CONFIG_PATH_2,
warpDeployPath,
);
// Update with a new hook config
const owner = randomAddress();
warpDeployConfig[CHAIN_NAME_2].hook = {
type: HookType.PROTOCOL_FEE,
beneficiary: owner,
maxProtocolFee: '1000000',
protocolFee: '100000',
owner,
};
// Write the updated config
await writeYamlOrJson(warpDeployPath, warpDeployConfig);
// Apply the changes
await hyperlaneWarpApply(warpDeployPath, WARP_CORE_CONFIG_PATH_2);
// Read back the config to verify changes
const updatedConfig = await readWarpConfig(
CHAIN_NAME_2,
WARP_CORE_CONFIG_PATH_2,
warpDeployPath,
);
// Verify the hook was updated with all properties
expect(normalizeConfig(updatedConfig[CHAIN_NAME_2].hook)).to.deep.equal(
normalizeConfig(warpDeployConfig[CHAIN_NAME_2].hook),
);
});
it('should extend an existing warp route', async () => {
// Read existing config into a file
const warpConfigPath = `${TEMP_PATH}/warp-route-deployment-2.yaml`;

@ -104,7 +104,7 @@ export class EvmHookModule extends HyperlaneModule<
// Transaction overrides for the chain
protected readonly txOverrides: Partial<ethers.providers.TransactionRequest>;
protected constructor(
constructor(
protected readonly multiProvider: MultiProvider,
params: HyperlaneModuleParams<
HookConfig,
@ -243,7 +243,7 @@ export class EvmHookModule extends HyperlaneModule<
chain: ChainNameOrId;
config: HookConfig;
proxyFactoryFactories: HyperlaneAddresses<ProxyFactoryFactories>;
coreAddresses: CoreAddresses;
coreAddresses: Omit<CoreAddresses, 'validatorAnnounce'>;
multiProvider: MultiProvider;
contractVerifier?: ContractVerifier;
}): Promise<EvmHookModule> {

@ -1,6 +1,5 @@
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers.js';
import { expect } from 'chai';
import { constants } from 'ethers';
import hre from 'hardhat';
import {
@ -12,16 +11,20 @@ import {
HypERC4626Collateral__factory,
HypNative__factory,
Mailbox,
MailboxClient__factory,
Mailbox__factory,
} from '@hyperlane-xyz/core';
import {
EvmIsmModule,
HookConfig,
HookType,
HyperlaneAddresses,
HyperlaneContractsMap,
IsmConfig,
IsmType,
RouterConfig,
TestChainName,
proxyAdmin,
serializeContracts,
} from '@hyperlane-xyz/sdk';
@ -29,6 +32,7 @@ import { TestCoreApp } from '../core/TestCoreApp.js';
import { TestCoreDeployer } from '../core/TestCoreDeployer.js';
import { HyperlaneProxyFactoryDeployer } from '../deploy/HyperlaneProxyFactoryDeployer.js';
import { ProxyFactoryFactories } from '../deploy/contracts.js';
import { DerivedHookConfig } from '../hook/EvmHookReader.js';
import { HyperlaneIsmFactory } from '../ism/HyperlaneIsmFactory.js';
import { MultiProvider } from '../providers/MultiProvider.js';
import { AnnotatedEV5Transaction } from '../providers/ProviderType.js';
@ -55,7 +59,6 @@ describe('EvmERC20WarpHyperlaneModule', async () => {
const TOKEN_DECIMALS = 18;
const chain = TestChainName.test4;
let mailbox: Mailbox;
let hookAddress: string;
let ismAddress: string;
let ismFactory: HyperlaneIsmFactory;
let factories: HyperlaneContractsMap<ProxyFactoryFactories>;
@ -70,10 +73,6 @@ describe('EvmERC20WarpHyperlaneModule', async () => {
async function validateCoreValues(deployedToken: GasRouter) {
expect(await deployedToken.mailbox()).to.equal(mailbox.address);
expect(await deployedToken.hook()).to.equal(hookAddress);
expect(await deployedToken.interchainSecurityModule()).to.equal(
constants.AddressZero,
);
expect(await deployedToken.owner()).to.equal(signer.address);
}
@ -106,7 +105,6 @@ describe('EvmERC20WarpHyperlaneModule', async () => {
baseConfig = routerConfigMap[chain];
mailbox = Mailbox__factory.connect(baseConfig.mailbox, signer);
hookAddress = await mailbox.defaultHook();
ismAddress = await mailbox.defaultIsm();
});
@ -115,7 +113,6 @@ describe('EvmERC20WarpHyperlaneModule', async () => {
...baseConfig,
type: TokenType.collateral,
token: token.address,
hook: hookAddress,
};
// Deploy using WarpModule
@ -143,7 +140,6 @@ describe('EvmERC20WarpHyperlaneModule', async () => {
const config: TokenRouterConfig = {
type: TokenType.collateralVault,
token: vault.address,
hook: hookAddress,
...baseConfig,
};
@ -175,13 +171,12 @@ describe('EvmERC20WarpHyperlaneModule', async () => {
it('should create with a synthetic config', async () => {
const config: TokenRouterConfig = {
...baseConfig,
type: TokenType.synthetic,
hook: hookAddress,
name: TOKEN_NAME,
symbol: TOKEN_NAME,
decimals: TOKEN_DECIMALS,
totalSupply: TOKEN_SUPPLY,
...baseConfig,
};
// Deploy using WarpModule
@ -213,7 +208,6 @@ describe('EvmERC20WarpHyperlaneModule', async () => {
it('should create with a native config', async () => {
const config = {
type: TokenType.native,
hook: hookAddress,
...baseConfig,
} as TokenRouterConfig;
@ -244,7 +238,6 @@ describe('EvmERC20WarpHyperlaneModule', async () => {
const config = {
...baseConfig,
type: TokenType.native,
hook: hookAddress,
remoteRouters: randomRemoteRouters(numOfRouters),
} as TokenRouterConfig;
@ -260,28 +253,48 @@ describe('EvmERC20WarpHyperlaneModule', async () => {
});
describe('Update', async () => {
const owner = randomAddress();
const ismConfigToUpdate: IsmConfig[] = [
{
type: IsmType.TRUSTED_RELAYER,
relayer: randomAddress(),
relayer: owner,
},
{
type: IsmType.FALLBACK_ROUTING,
owner: randomAddress(),
owner: owner,
domains: {},
},
{
type: IsmType.PAUSABLE,
owner: randomAddress(),
owner: owner,
paused: false,
},
];
const hookConfigToUpdate: HookConfig[] = [
{
type: HookType.PROTOCOL_FEE,
beneficiary: owner,
owner: owner,
maxProtocolFee: '1337',
protocolFee: '1337',
},
{
type: HookType.INTERCHAIN_GAS_PAYMASTER,
owner: owner,
beneficiary: owner,
oracleKey: owner,
overhead: {},
oracleConfig: {},
},
{
type: HookType.MERKLE_TREE,
},
];
it('should deploy and set a new Ism', async () => {
const config = {
...baseConfig,
type: TokenType.native,
hook: hookAddress,
interchainSecurityModule: ismAddress,
} as TokenRouterConfig;
@ -297,7 +310,6 @@ describe('EvmERC20WarpHyperlaneModule', async () => {
for (const interchainSecurityModule of ismConfigToUpdate) {
const expectedConfig: TokenRouterConfig = {
...actualConfig,
interchainSecurityModule,
};
await sendTxs(await evmERC20WarpModule.update(expectedConfig));
@ -313,7 +325,6 @@ describe('EvmERC20WarpHyperlaneModule', async () => {
const config = {
...baseConfig,
type: TokenType.native,
hook: hookAddress,
interchainSecurityModule: ismAddress,
} as TokenRouterConfig;
@ -351,6 +362,99 @@ describe('EvmERC20WarpHyperlaneModule', async () => {
expect(txs.length).to.equal(0);
});
it('should update and set a new Hook based on config', async () => {
const config = {
...baseConfig,
type: TokenType.native,
} as TokenRouterConfig;
// Deploy using WarpModule
const evmERC20WarpModule = await EvmERC20WarpModule.create({
chain,
config,
multiProvider,
proxyFactoryFactories: ismFactoryAddresses,
});
const actualConfig = await evmERC20WarpModule.read();
for (const hook of hookConfigToUpdate) {
const expectedConfig: TokenRouterConfig = {
...actualConfig,
hook,
};
await sendTxs(await evmERC20WarpModule.update(expectedConfig));
const updatedConfig = (await evmERC20WarpModule.read())
.hook as DerivedHookConfig;
expect(normalizeConfig(updatedConfig)).to.deep.equal(hook);
}
});
it('should set new deployed hook mailbox to WarpConfig.owner', async () => {
const config = {
...baseConfig,
type: TokenType.native,
} as TokenRouterConfig;
// Deploy using WarpModule
const evmERC20WarpModule = await EvmERC20WarpModule.create({
chain,
config,
multiProvider,
proxyFactoryFactories: ismFactoryAddresses,
});
const actualConfig = await evmERC20WarpModule.read();
const expectedConfig: TokenRouterConfig = {
...actualConfig,
hook: hookConfigToUpdate.find(
(c: any) => c.type === HookType.MERKLE_TREE,
),
};
await sendTxs(await evmERC20WarpModule.update(expectedConfig));
const updatedConfig = (await evmERC20WarpModule.read())
.hook as DerivedHookConfig;
const hook = MailboxClient__factory.connect(
updatedConfig.address,
multiProvider.getProvider(chain),
);
expect(await hook.mailbox()).to.equal(expectedConfig.mailbox);
});
it("should set Proxied Hook's proxyAdmins to WarpConfig.proxyAdmin", async () => {
const config = {
...baseConfig,
type: TokenType.native,
} as TokenRouterConfig;
// Deploy using WarpModule
const evmERC20WarpModule = await EvmERC20WarpModule.create({
chain,
config,
multiProvider,
proxyFactoryFactories: ismFactoryAddresses,
});
const actualConfig = await evmERC20WarpModule.read();
const expectedConfig: TokenRouterConfig = {
...actualConfig,
hook: hookConfigToUpdate.find(
(c: any) => c.type === HookType.INTERCHAIN_GAS_PAYMASTER,
),
};
await sendTxs(await evmERC20WarpModule.update(expectedConfig));
const updatedConfig = (await evmERC20WarpModule.read())
.hook as DerivedHookConfig;
expect(
await proxyAdmin(
multiProvider.getProvider(chain),
updatedConfig.address,
),
).to.equal(expectedConfig.proxyAdmin?.address);
});
it('should update a mutable Ism', async () => {
const ismConfig: IsmConfig = {
type: IsmType.ROUTING,
@ -372,7 +476,6 @@ describe('EvmERC20WarpHyperlaneModule', async () => {
const config = {
...baseConfig,
type: TokenType.native,
hook: hookAddress,
interchainSecurityModule: deployedIsm,
} as TokenRouterConfig;
@ -409,7 +512,6 @@ describe('EvmERC20WarpHyperlaneModule', async () => {
const config = {
...baseConfig,
type: TokenType.native,
hook: hookAddress,
ismFactoryAddresses,
} as TokenRouterConfig;
@ -441,7 +543,6 @@ describe('EvmERC20WarpHyperlaneModule', async () => {
const config = {
...baseConfig,
type: TokenType.native,
hook: hookAddress,
ismFactoryAddresses,
} as TokenRouterConfig;
@ -494,7 +595,6 @@ describe('EvmERC20WarpHyperlaneModule', async () => {
const config = {
...baseConfig,
type: TokenType.native,
hook: hookAddress,
ismFactoryAddresses,
} as TokenRouterConfig;
@ -535,7 +635,6 @@ describe('EvmERC20WarpHyperlaneModule', async () => {
const config: TokenRouterConfig = {
...baseConfig,
type: TokenType.native,
hook: hookAddress,
};
const owner = signer.address.toLowerCase();
@ -579,7 +678,6 @@ describe('EvmERC20WarpHyperlaneModule', async () => {
const config: TokenRouterConfig = {
...baseConfig,
type: TokenType.native,
hook: hookAddress,
remoteRouters: {
[domain]: randomAddress(),
},

@ -19,6 +19,7 @@ import {
addressToBytes32,
assert,
deepEquals,
eqAddress,
isObjEmpty,
objMap,
rootLogger,
@ -31,6 +32,8 @@ import {
} from '../core/AbstractHyperlaneModule.js';
import { ProxyFactoryFactories } from '../deploy/contracts.js';
import { proxyAdminUpdateTxs } from '../deploy/proxy.js';
import { EvmHookModule } from '../hook/EvmHookModule.js';
import { DerivedHookConfig } from '../hook/EvmHookReader.js';
import { EvmIsmModule } from '../ism/EvmIsmModule.js';
import { DerivedIsmConfig } from '../ism/EvmIsmReader.js';
import { MultiProvider } from '../providers/MultiProvider.js';
@ -42,12 +45,13 @@ import { EvmERC20WarpRouteReader } from './EvmERC20WarpRouteReader.js';
import { HypERC20Deployer } from './deploy.js';
import { TokenRouterConfig, TokenRouterConfigSchema } from './schemas.js';
type WarpRouteAddresses = HyperlaneAddresses<ProxyFactoryFactories> & {
deployedTokenRoute: Address;
};
export class EvmERC20WarpModule extends HyperlaneModule<
ProtocolType.Ethereum,
TokenRouterConfig,
HyperlaneAddresses<ProxyFactoryFactories> & {
deployedTokenRoute: Address;
}
WarpRouteAddresses
> {
protected logger = rootLogger.child({
module: 'EvmERC20WarpModule',
@ -59,12 +63,7 @@ export class EvmERC20WarpModule extends HyperlaneModule<
constructor(
protected readonly multiProvider: MultiProvider,
args: HyperlaneModuleParams<
TokenRouterConfig,
HyperlaneAddresses<ProxyFactoryFactories> & {
deployedTokenRoute: Address;
}
>,
args: HyperlaneModuleParams<TokenRouterConfig, WarpRouteAddresses>,
protected readonly contractVerifier?: ContractVerifier,
) {
super(args);
@ -87,7 +86,7 @@ export class EvmERC20WarpModule extends HyperlaneModule<
* @param address - The address to derive the token router configuration from.
* @returns A promise that resolves to the token router configuration.
*/
public async read(): Promise<TokenRouterConfig> {
async read(): Promise<TokenRouterConfig> {
return this.reader.deriveWarpRouteConfig(
this.args.addresses.deployedTokenRoute,
);
@ -99,7 +98,7 @@ export class EvmERC20WarpModule extends HyperlaneModule<
* @param expectedConfig - The configuration for the token router to be updated.
* @returns An array of Ethereum transactions that were executed to update the contract, or an error if the update failed.
*/
public async update(
async update(
expectedConfig: TokenRouterConfig,
): Promise<AnnotatedEV5Transaction[]> {
TokenRouterConfigSchema.parse(expectedConfig);
@ -115,6 +114,7 @@ export class EvmERC20WarpModule extends HyperlaneModule<
*/
transactions.push(
...(await this.createIsmUpdateTxs(actualConfig, expectedConfig)),
...(await this.createHookUpdateTxs(actualConfig, expectedConfig)),
...this.createRemoteRoutersUpdateTxs(actualConfig, expectedConfig),
...this.createSetDestinationGasUpdateTxs(actualConfig, expectedConfig),
...this.createOwnershipUpdateTxs(actualConfig, expectedConfig),
@ -280,6 +280,47 @@ export class EvmERC20WarpModule extends HyperlaneModule<
return updateTransactions;
}
async createHookUpdateTxs(
actualConfig: TokenRouterConfig,
expectedConfig: TokenRouterConfig,
): Promise<AnnotatedEV5Transaction[]> {
const updateTransactions: AnnotatedEV5Transaction[] = [];
if (!expectedConfig.hook) {
return [];
}
const actualDeployedHook = (actualConfig.hook as DerivedHookConfig)
?.address;
// Try to deploy or update Hook with the expected config
const {
deployedHook: expectedDeployedHook,
updateTransactions: hookUpdateTransactions,
} = await this.deployOrUpdateHook(actualConfig, expectedConfig);
// If a Hook is updated in-place, push the update txs
updateTransactions.push(...hookUpdateTransactions);
// If a new Hook is deployed, push the setHook tx
if (!eqAddress(actualDeployedHook, expectedDeployedHook)) {
const contractToUpdate = MailboxClient__factory.connect(
this.args.addresses.deployedTokenRoute,
this.multiProvider.getProvider(this.domainId),
);
updateTransactions.push({
chainId: this.chainId,
annotation: `Setting Hook for Warp Route to ${expectedDeployedHook}`,
to: contractToUpdate.address,
data: contractToUpdate.interface.encodeFunctionData('setHook', [
expectedDeployedHook,
]),
});
}
return updateTransactions;
}
/**
* Transfer ownership of an existing Warp route with a given config.
*
@ -305,17 +346,14 @@ export class EvmERC20WarpModule extends HyperlaneModule<
*
* @returns Object with deployedIsm address, and update Transactions
*/
public async deployOrUpdateIsm(
async deployOrUpdateIsm(
actualConfig: TokenRouterConfig,
expectedConfig: TokenRouterConfig,
): Promise<{
deployedIsm: Address;
updateTransactions: AnnotatedEV5Transaction[];
}> {
assert(
expectedConfig.interchainSecurityModule,
'Ism not derived correctly',
);
assert(expectedConfig.interchainSecurityModule, 'Ism derived incorrectly');
const ismModule = new EvmIsmModule(
this.multiProvider,
@ -343,6 +381,124 @@ export class EvmERC20WarpModule extends HyperlaneModule<
return { deployedIsm, updateTransactions };
}
/**
* Updates or deploys the hook using the provided configuration.
*
* @returns Object with deployedHook address, and update Transactions
*/
async deployOrUpdateHook(
actualConfig: TokenRouterConfig,
expectedConfig: TokenRouterConfig,
): Promise<{
deployedHook: Address;
updateTransactions: AnnotatedEV5Transaction[];
}> {
assert(expectedConfig.hook, 'No hook config');
if (!actualConfig.hook) {
return this.deployNewHook(expectedConfig);
}
return this.updateExistingHook(expectedConfig, actualConfig);
}
async deployNewHook(expectedConfig: TokenRouterConfig): Promise<{
deployedHook: Address;
updateTransactions: AnnotatedEV5Transaction[];
}> {
this.logger.info(
`No hook deployed for warp route, deploying new hook on ${this.args.chain} chain`,
);
const {
staticMerkleRootMultisigIsmFactory,
staticMessageIdMultisigIsmFactory,
staticAggregationIsmFactory,
staticAggregationHookFactory,
domainRoutingIsmFactory,
staticMerkleRootWeightedMultisigIsmFactory,
staticMessageIdWeightedMultisigIsmFactory,
} = this.args.addresses;
assert(expectedConfig.hook, 'Hook is undefined');
assert(
expectedConfig.proxyAdmin?.address,
'ProxyAdmin address is undefined',
);
const hookModule = await EvmHookModule.create({
chain: this.args.chain,
config: expectedConfig.hook,
proxyFactoryFactories: {
staticMerkleRootMultisigIsmFactory,
staticMessageIdMultisigIsmFactory,
staticAggregationIsmFactory,
staticAggregationHookFactory,
domainRoutingIsmFactory,
staticMerkleRootWeightedMultisigIsmFactory,
staticMessageIdWeightedMultisigIsmFactory,
},
coreAddresses: {
mailbox: expectedConfig.mailbox,
proxyAdmin: expectedConfig.proxyAdmin?.address, // Assume that a proxyAdmin is always deployed with a WarpRoute
},
contractVerifier: this.contractVerifier,
multiProvider: this.multiProvider,
});
const { deployedHook } = hookModule.serialize();
return { deployedHook, updateTransactions: [] };
}
async updateExistingHook(
expectedConfig: TokenRouterConfig,
actualConfig: TokenRouterConfig,
): Promise<{
deployedHook: Address;
updateTransactions: AnnotatedEV5Transaction[];
}> {
const {
staticMerkleRootMultisigIsmFactory,
staticMessageIdMultisigIsmFactory,
staticAggregationIsmFactory,
staticAggregationHookFactory,
domainRoutingIsmFactory,
staticMerkleRootWeightedMultisigIsmFactory,
staticMessageIdWeightedMultisigIsmFactory,
} = this.args.addresses;
assert(actualConfig.proxyAdmin?.address, 'ProxyAdmin address is undefined');
assert(actualConfig.hook, 'Hook is undefined');
const hookModule = new EvmHookModule(
this.multiProvider,
{
chain: this.args.chain,
config: actualConfig.hook,
addresses: {
staticMerkleRootMultisigIsmFactory,
staticMessageIdMultisigIsmFactory,
staticAggregationIsmFactory,
staticAggregationHookFactory,
domainRoutingIsmFactory,
staticMerkleRootWeightedMultisigIsmFactory,
staticMessageIdWeightedMultisigIsmFactory,
mailbox: actualConfig.mailbox,
proxyAdmin: actualConfig.proxyAdmin?.address,
deployedHook: (actualConfig.hook as DerivedHookConfig).address,
},
},
this.contractVerifier,
);
this.logger.info(
`Comparing target Hook config with ${this.args.chain} chain`,
);
const updateTransactions = await hookModule.update(expectedConfig.hook!);
const { deployedHook } = hookModule.serialize();
return { deployedHook, updateTransactions };
}
/**
* Deploys the Warp Route.
*
@ -351,7 +507,7 @@ export class EvmERC20WarpModule extends HyperlaneModule<
* @param multiProvider - The multi-provider instance to use.
* @returns A new instance of the EvmERC20WarpHyperlaneModule.
*/
public static async create(params: {
static async create(params: {
chain: ChainNameOrId;
config: TokenRouterConfig;
multiProvider: MultiProvider;

Loading…
Cancel
Save