Skip to content

Commit 69e6b3f

Browse files
authored
feat: unify warp route checks onto shared logic (#8554)
1 parent c4c3520 commit 69e6b3f

20 files changed

Lines changed: 1422 additions & 1241 deletions

.changeset/real-bugs-dance.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@hyperlane-xyz/cli': patch
3+
'@hyperlane-xyz/sdk': major
4+
---
5+
6+
Warp route checks were unified onto the shared CLI comparison flow, including explicit proxyAdmin address checks and owner override ownership checks. The legacy `HypERC20App` and `HypERC20Checker` SDK exports were removed.

typescript/cli/cli.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@ ignoreBrokenPipe(process.stderr);
4949

5050
console.log(chalk.blue('Hyperlane'), chalk.magentaBright('CLI'));
5151

52-
await checkVersion();
52+
if (!process.env.CI && process.env.HYPERLANE_SKIP_VERSION_CHECK !== '1') {
53+
await checkVersion();
54+
}
5355

5456
try {
5557
await yargs(process.argv.slice(2))

typescript/cli/src/check/warp.ts

Lines changed: 10 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,13 @@ import { stringify as yamlStringify } from 'yaml';
22

33
import {
44
type AccountConfig,
5-
type DerivedWarpRouteDeployConfig,
6-
type HypTokenRouterVirtualConfig,
75
InterchainAccount,
6+
type WarpRouteCheckResult,
87
type WarpRouteDeployConfigMailboxRequired,
9-
derivedHookAddress,
10-
derivedIsmAddress,
11-
transformConfigToCheck,
12-
verifyScale,
138
} from '@hyperlane-xyz/sdk';
149
import {
1510
type ObjectDiff,
1611
assert,
17-
diffObjMerge,
1812
eqAddress,
1913
isEVMLike,
2014
keepOnlyDiffObjects,
@@ -26,81 +20,23 @@ import { log, logGreen, logRed, warnYellow } from '../logger.js';
2620
import { formatYamlViolationsOutput } from '../utils/output.js';
2721

2822
export async function runWarpRouteCheck({
29-
warpRouteConfig,
30-
onChainWarpConfig,
23+
result,
3124
}: {
32-
warpRouteConfig: WarpRouteDeployConfigMailboxRequired &
33-
Record<string, Partial<HypTokenRouterVirtualConfig>>;
34-
onChainWarpConfig: DerivedWarpRouteDeployConfig &
35-
Record<string, Partial<HypTokenRouterVirtualConfig>>;
25+
result: WarpRouteCheckResult;
3626
}): Promise<void> {
37-
// Check whether the decimals are consistent. If not, ensure that the scale is correct.
38-
const decimalsAreValid = verifyDecimalsAndScale(warpRouteConfig);
39-
40-
// Go through each chain and only add to the output the chains that have mismatches
41-
const [violations, isInvalid] = Object.keys(warpRouteConfig).reduce(
42-
(acc, chain) => {
43-
const expectedDeployedConfig = warpRouteConfig[chain];
44-
const currentDeployedConfig = onChainWarpConfig[chain];
45-
46-
// If the expected config specifies the hook or the ism as an address instead of the full config
47-
// compare just the addresses
48-
if (typeof expectedDeployedConfig.hook === 'string') {
49-
currentDeployedConfig.hook = derivedHookAddress(currentDeployedConfig);
50-
}
51-
52-
if (typeof expectedDeployedConfig.interchainSecurityModule === 'string') {
53-
currentDeployedConfig.interchainSecurityModule = derivedIsmAddress(
54-
currentDeployedConfig,
55-
);
56-
}
57-
58-
// if the input config does not specify the expected contractVersion we skip to
59-
// avoid triggering a false positive
60-
if (!expectedDeployedConfig.contractVersion) {
61-
currentDeployedConfig.contractVersion = undefined;
62-
}
63-
64-
const { mergedObject, isInvalid } = diffObjMerge(
65-
transformConfigToCheck(currentDeployedConfig),
66-
transformConfigToCheck(expectedDeployedConfig),
67-
);
68-
69-
if (isInvalid) {
70-
acc[0][chain] = mergedObject;
71-
acc[1] ||= isInvalid;
72-
}
73-
74-
return acc;
75-
},
76-
[{}, false] as [{ [index: string]: ObjectDiff }, boolean],
77-
);
27+
if (Object.keys(result.diff).length > 0) {
28+
log(formatYamlViolationsOutput(yamlStringify(result.diff, null, 2)));
29+
}
7830

79-
if (isInvalid) {
80-
log(
81-
formatYamlViolationsOutput(
82-
yamlStringify(keepOnlyDiffObjects(violations), null, 2),
83-
),
84-
);
85-
process.exit(1);
31+
if (result.scaleViolations.length > 0) {
32+
logRed(`Found invalid or missing scale for inconsistent decimals`);
8633
}
8734

88-
if (!decimalsAreValid) {
35+
if (!result.isValid) {
8936
process.exit(1);
9037
}
91-
logGreen(`No violations found`);
92-
}
9338

94-
function verifyDecimalsAndScale(
95-
warpRouteConfig: WarpRouteDeployConfigMailboxRequired &
96-
Record<string, Partial<HypTokenRouterVirtualConfig>>,
97-
): boolean {
98-
let valid = true;
99-
if (!verifyScale(warpRouteConfig)) {
100-
logRed(`Found invalid or missing scale for inconsistent decimals`);
101-
valid = false;
102-
}
103-
return valid;
39+
logGreen(`No violations found`);
10440
}
10541

10642
/**

typescript/cli/src/commands/warp.ts

Lines changed: 5 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,13 @@ import { RebalancerConfig, RebalancerService } from '@hyperlane-xyz/rebalancer';
66
import {
77
type RawForkedChainConfigByChain,
88
RawForkedChainConfigByChainSchema,
9-
expandVirtualWarpDeployConfig,
10-
expandWarpDeployConfig,
11-
getRouterAddressesFromWarpCoreConfig,
9+
checkWarpRouteDeployConfig,
1210
} from '@hyperlane-xyz/sdk';
1311
import {
1412
assert,
1513
difference,
1614
intersection,
1715
isEVMLike,
18-
objFilter,
1916
rootLogger,
2017
} from '@hyperlane-xyz/utils';
2118

@@ -42,7 +39,7 @@ import {
4239
logCommandHeader,
4340
logGreen,
4441
} from '../logger.js';
45-
import { getWarpRouteConfigsByCore, runWarpRouteRead } from '../read/warp.js';
42+
import { runWarpRouteRead } from '../read/warp.js';
4643
import { sendTestTransfer } from '../send/transfer.js';
4744
import { ExtendedChainSubmissionStrategySchema } from '../submitters/types.js';
4845
import {
@@ -584,44 +581,14 @@ export const check: CommandModuleWithContext<
584581
warpCoreConfig,
585582
));
586583

587-
const deployedRoutersAddresses =
588-
getRouterAddressesFromWarpCoreConfig(warpCoreConfig);
589-
590-
// Remove any non EVM chain configs to avoid the checker crashing
591-
warpCoreConfig.tokens = warpCoreConfig.tokens.filter((config) =>
592-
isEVMLike(
593-
context.multiProvider.getChainMetadata(config.chainName).protocol,
594-
),
595-
);
596-
597-
// Get on-chain config
598-
const onChainWarpConfig = await getWarpRouteConfigsByCore({
599-
context,
600-
warpCoreConfig,
601-
});
602-
603-
// get virtual on-chain config
604-
const expandedOnChainWarpConfig = await expandVirtualWarpDeployConfig({
605-
multiProvider: context.multiProvider,
606-
onChainWarpConfig,
607-
deployedRoutersAddresses,
608-
});
609-
610-
let expandedWarpDeployConfig = await expandWarpDeployConfig({
584+
const result = await checkWarpRouteDeployConfig({
611585
multiProvider: context.multiProvider,
586+
warpCoreConfig,
612587
warpDeployConfig,
613-
deployedRoutersAddresses,
614-
expandedOnChainWarpConfig,
615588
});
616-
expandedWarpDeployConfig = objFilter(
617-
expandedWarpDeployConfig,
618-
(chain, _config): _config is any =>
619-
isEVMLike(context.multiProvider.getChainMetadata(chain).protocol),
620-
);
621589

622590
await runWarpRouteCheck({
623-
onChainWarpConfig: expandedOnChainWarpConfig,
624-
warpRouteConfig: expandedWarpDeployConfig,
591+
result,
625592
});
626593

627594
process.exit(0);

typescript/infra/config/warp.ts

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
MultiProvider,
88
OwnableConfig,
99
WarpRouteDeployConfig,
10+
WarpRouteDeployConfigMailboxRequired,
1011
} from '@hyperlane-xyz/sdk';
1112
import { assert, objMap, promiseObjAll } from '@hyperlane-xyz/utils';
1213

@@ -266,12 +267,10 @@ export const sandboxStrategyConfigGetterMap: Record<
266267
/**
267268
* Retrieves the Warp configuration for the specified Warp route ID by fetching it from the FileSystemRegistry and GithubRegistry
268269
*/
269-
async function getConfigFromMergedRegistry(
270-
_routerConfig: ChainMap<RouterConfigWithoutOwner>,
271-
_abacusWorksEnvOwnerConfig: ChainMap<OwnableConfig>,
270+
export async function getWarpDeployConfigFromMergedRegistry(
272271
warpRouteId: string,
273272
registryUris: string[],
274-
): Promise<ChainMap<HypTokenRouterConfig>> {
273+
): Promise<WarpRouteDeployConfigMailboxRequired> {
275274
const registry = getRegistry({
276275
registryUris,
277276
enableProxy: true,
@@ -289,7 +288,7 @@ async function getConfigFromMergedRegistry(
289288
*/
290289
export async function getWarpConfigMapFromMergedRegistry(
291290
registryUris: string[],
292-
): Promise<Record<string, ChainMap<HypTokenRouterConfig>>> {
291+
): Promise<Record<string, WarpRouteDeployConfigMailboxRequired>> {
293292
const registry = getRegistry({
294293
registryUris,
295294
enableProxy: true,
@@ -317,7 +316,7 @@ export async function getWarpConfigMapFromMergedRegistry(
317316
async function populateWarpRouteMailboxAddresses(
318317
warpRoute: WarpRouteDeployConfig,
319318
registry: IRegistry,
320-
): Promise<ChainMap<HypTokenRouterConfig>> {
319+
): Promise<WarpRouteDeployConfigMailboxRequired> {
321320
const mailboxPromises = objMap(warpRoute, async (chainName, config) => {
322321
const mailbox =
323322
config.mailbox || (await registry.getChainAddresses(chainName))?.mailbox;
@@ -339,7 +338,28 @@ export async function getWarpConfig(
339338
warpRouteId: string,
340339
registryUris = [DEFAULT_REGISTRY_URI],
341340
forceRegistryConfig = false,
341+
getterInputs?: WarpConfigGetterInputs,
342342
): Promise<ChainMap<HypTokenRouterConfig>> {
343+
const { abacusWorksEnvOwnerConfig, routerConfigWithoutOwner } =
344+
getterInputs ?? (await getWarpConfigGetterInputs(multiProvider, envConfig));
345+
return getWarpConfigWithGetterInputs(
346+
warpRouteId,
347+
routerConfigWithoutOwner,
348+
abacusWorksEnvOwnerConfig,
349+
registryUris,
350+
forceRegistryConfig,
351+
);
352+
}
353+
354+
export interface WarpConfigGetterInputs {
355+
abacusWorksEnvOwnerConfig: ChainMap<OwnableConfig>;
356+
routerConfigWithoutOwner: ChainMap<RouterConfigWithoutOwner>;
357+
}
358+
359+
export async function getWarpConfigGetterInputs(
360+
multiProvider: MultiProvider,
361+
envConfig: EnvironmentConfig,
362+
): Promise<WarpConfigGetterInputs> {
343363
const routerConfig = await getRouterConfigsForAllVms(
344364
envConfig,
345365
multiProvider,
@@ -362,6 +382,19 @@ export async function getWarpConfig(
362382
};
363383
});
364384

385+
return {
386+
abacusWorksEnvOwnerConfig,
387+
routerConfigWithoutOwner,
388+
};
389+
}
390+
391+
async function getWarpConfigWithGetterInputs(
392+
warpRouteId: string,
393+
routerConfigWithoutOwner: ChainMap<RouterConfigWithoutOwner>,
394+
abacusWorksEnvOwnerConfig: ChainMap<OwnableConfig>,
395+
registryUris = [DEFAULT_REGISTRY_URI],
396+
forceRegistryConfig = false,
397+
): Promise<ChainMap<HypTokenRouterConfig>> {
365398
const warpConfigGetter = warpConfigGetterMap[warpRouteId];
366399
if (warpConfigGetter && !forceRegistryConfig) {
367400
return warpConfigGetter(
@@ -371,10 +404,5 @@ export async function getWarpConfig(
371404
);
372405
}
373406

374-
return getConfigFromMergedRegistry(
375-
routerConfigWithoutOwner,
376-
abacusWorksEnvOwnerConfig,
377-
warpRouteId,
378-
registryUris,
379-
);
407+
return getWarpDeployConfigFromMergedRegistry(warpRouteId, registryUris);
380408
}

typescript/infra/scripts/agent-utils.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ export enum Modules {
7171
INTERCHAIN_QUERY_SYSTEM = 'iqs',
7272
TEST_QUERY_SENDER = 'testquerysender',
7373
TEST_RECIPIENT = 'testrecipient',
74-
WARP = 'warp',
7574
HAAS = 'haas',
7675
CCIP = 'ccip',
7776
}

typescript/infra/scripts/check/check-deploy.ts

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,24 @@
1+
import { assert } from '@hyperlane-xyz/utils';
2+
13
import {
24
getCheckDeployArgs,
35
getGovernor,
46
logViolations,
57
} from './check-utils.js';
68

79
async function main() {
8-
const {
9-
module,
10-
context,
11-
environment,
12-
asDeployer,
13-
chains,
14-
fork,
15-
govern,
16-
warpRouteId,
17-
registry,
18-
forceRegistryConfig,
19-
} = await getCheckDeployArgs().argv;
10+
const { module, context, environment, asDeployer, chains, fork, govern } =
11+
await getCheckDeployArgs().argv;
12+
assert(module, 'Module is required');
2013

2114
const governor = await getGovernor(
2215
module,
2316
context,
2417
environment,
2518
asDeployer,
26-
warpRouteId,
2719
chains,
2820
fork,
2921
govern,
30-
undefined,
31-
registry,
32-
forceRegistryConfig,
3322
);
3423

3524
if (fork) {

0 commit comments

Comments
 (0)