Skip to content

Commit

Permalink
feat: Add hook update into WarpModule.update() (#4891)
Browse files Browse the repository at this point in the history
### 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
  • Loading branch information
ltyu authored Dec 2, 2024
1 parent 95f1a97 commit 170a0fc
Show file tree
Hide file tree
Showing 6 changed files with 387 additions and 56 deletions.
5 changes: 5 additions & 0 deletions .changeset/nice-oranges-glow.md
Original file line number Diff line number Diff line change
@@ -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.
54 changes: 42 additions & 12 deletions typescript/cli/src/deploy/warp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -30,7 +30,6 @@ import {
MultisigIsmConfig,
OpStackIsmConfig,
PausableIsmConfig,
ProxyFactoryFactoriesAddresses,
RemoteRouters,
RoutingIsmConfig,
SubmissionStrategy,
Expand Down Expand Up @@ -519,7 +518,6 @@ async function extendWarpRoute(

const newDeployedContracts = await executeDeploy(
{
// TODO: use EvmERC20WarpModule when it's ready
context: params.context,
warpDeployConfig: extendedConfigs,
},
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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,
},
});

Expand Down
42 changes: 42 additions & 0 deletions typescript/cli/src/tests/warp-apply.e2e-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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`;
Expand Down
4 changes: 2 additions & 2 deletions typescript/sdk/src/hook/EvmHookModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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> {
Expand Down
Loading

0 comments on commit 170a0fc

Please sign in to comment.