Skip to content

Commit 840fb33

Browse files
antigremlinxeno097claude
authored
refactor(cli,sdk): integrate warp artifact API and remove deprecated AltVM warp modules (#8178)
Co-authored-by: xeno097 <xeno097.cp@gmail.com> Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 048df98 commit 840fb33

25 files changed

Lines changed: 1577 additions & 2044 deletions

.changeset/rare-bugs-cheat.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
'@hyperlane-xyz/deploy-sdk': major
3+
'@hyperlane-xyz/cli': patch
4+
'@hyperlane-xyz/sdk': minor
5+
'@hyperlane-xyz/provider-sdk': major
6+
'@hyperlane-xyz/cosmos-sdk': patch
7+
---
8+
9+
Deprecated AltVM warp module classes were removed from deploy-sdk and replaced with the artifact API.
10+
11+
deploy-sdk removed public exports:
12+
- AltVMWarpModule (use createWarpTokenWriter instead)
13+
- AltVMWarpRouteReader (use createWarpTokenReader instead)
14+
- AltVMDeployer (use createWarpTokenWriter per-chain instead)
15+
- warpModuleProvider (no longer needed)
16+
- ismConfigToArtifact (moved to @hyperlane-xyz/provider-sdk/ism)
17+
- shouldDeployNewIsm (moved to @hyperlane-xyz/provider-sdk/ism)
18+
19+
provider-sdk breaking change: warpConfigToArtifact no longer accepts pre-built ismArtifact/hookArtifact parameters; ISM and hook conversion is now handled internally from the config.
20+
21+
cosmos-sdk: name and symbol for warp tokens without on-chain metadata were changed from empty strings to 'Unknown'.
22+
23+
CLI and SDK were updated to use the new artifact API via createWarpTokenWriter and createWarpTokenReader.

typescript/aleo-sdk/src/warp/warp-artifact-manager.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ export class AleoWarpArtifactManager implements IRawWarpArtifactManager {
3535
private readonly onChainArtifactManagers: OnChainArtifactManagers,
3636
) {}
3737

38+
supportsHookUpdates(): boolean {
39+
return true;
40+
}
41+
3842
async readWarpToken(address: string): Promise<DeployedRawWarpArtifact> {
3943
// Detect warp token type first
4044
const aleoTokenType = await getAleoWarpTokenType(this.aleoClient, address);

typescript/cli/src/deploy/configValidation.ts

Lines changed: 2 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -10,28 +10,8 @@
1010
import { validateIsmConfig } from '@hyperlane-xyz/deploy-sdk';
1111
import { type CoreConfig as ProviderCoreConfig } from '@hyperlane-xyz/provider-sdk/core';
1212
import { type IsmConfig as ProviderIsmConfig } from '@hyperlane-xyz/provider-sdk/ism';
13-
import {
14-
type CollateralWarpConfig,
15-
type NativeWarpConfig,
16-
TokenType as ProviderTokenType,
17-
type WarpConfig as ProviderWarpConfig,
18-
type SyntheticWarpConfig,
19-
} from '@hyperlane-xyz/provider-sdk/warp';
20-
import {
21-
type CoreConfig,
22-
TokenType,
23-
type WarpRouteDeployConfigMailboxRequired,
24-
} from '@hyperlane-xyz/sdk';
25-
26-
/**
27-
* Supported token types in provider-sdk.
28-
* Alt-VM chains currently support collateral, synthetic, and native tokens.
29-
*/
30-
const SUPPORTED_TOKEN_TYPES = new Set<TokenType>([
31-
TokenType.synthetic,
32-
TokenType.collateral,
33-
TokenType.native,
34-
]);
13+
import { type CoreConfig } from '@hyperlane-xyz/sdk';
14+
export { validateWarpConfigForAltVM } from '@hyperlane-xyz/sdk';
3515

3616
/**
3717
* Validates that a CoreConfig is compatible with provider-sdk requirements.
@@ -62,77 +42,3 @@ export function validateCoreConfigForAltVM(
6242
// and provider-sdk types are a subset of SDK types
6343
return config as ProviderCoreConfig;
6444
}
65-
66-
/**
67-
* Validates that a WarpRouteDeployConfig is compatible with provider-sdk requirements.
68-
*
69-
* @param config - WarpRouteDeployConfig from the main SDK
70-
* @param chain - Chain name for error messages
71-
* @returns a provider-sdk WarpConfig derived from the given config
72-
* @throws Error if config contains unsupported token types
73-
*/
74-
export function validateWarpConfigForAltVM(
75-
config: WarpRouteDeployConfigMailboxRequired[string],
76-
chain: string,
77-
): ProviderWarpConfig {
78-
// Check if token type is supported
79-
if (!SUPPORTED_TOKEN_TYPES.has(config.type)) {
80-
const supportedTypes = Array.from(SUPPORTED_TOKEN_TYPES).join(', ');
81-
const errorMsg =
82-
`Unsupported token type '${config.type}' for Alt-VM chain '${chain}'.\n` +
83-
`Supported token types: ${supportedTypes}.`;
84-
throw new Error(errorMsg);
85-
}
86-
87-
// Validate the token conforms to basic collateral or synthetic structure
88-
if (config.type === TokenType.collateral) {
89-
if (!config.token) {
90-
const errorMsg = `Collateral token config for chain '${chain}' must specify 'token' address`;
91-
throw new Error(errorMsg);
92-
}
93-
}
94-
95-
// Validate ISM if present (handles recursion for routing ISMs)
96-
if (config.interchainSecurityModule) {
97-
validateIsmConfig(
98-
config.interchainSecurityModule as ProviderIsmConfig | string,
99-
chain,
100-
'warp config',
101-
);
102-
}
103-
104-
// Construct the provider-sdk config
105-
const baseConfig = {
106-
owner: config.owner,
107-
mailbox: config.mailbox,
108-
interchainSecurityModule: config.interchainSecurityModule,
109-
hook: config.hook,
110-
remoteRouters: config.remoteRouters,
111-
destinationGas: config.destinationGas,
112-
};
113-
114-
if (config.type === TokenType.collateral) {
115-
return {
116-
...baseConfig,
117-
type: ProviderTokenType.collateral,
118-
token: config.token,
119-
} as CollateralWarpConfig;
120-
} else if (config.type === TokenType.synthetic) {
121-
return {
122-
...baseConfig,
123-
type: ProviderTokenType.synthetic,
124-
name: config.name,
125-
symbol: config.symbol,
126-
decimals: config.decimals,
127-
} as SyntheticWarpConfig;
128-
} else if (config.type === TokenType.native) {
129-
return {
130-
...baseConfig,
131-
type: ProviderTokenType.native,
132-
} as NativeWarpConfig;
133-
} else {
134-
throw new Error(
135-
`Unsupported token type '${config.type}' for Alt-VM chain '${chain}'.`,
136-
);
137-
}
138-
}

typescript/cli/src/deploy/warp.ts

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ import { stringify as yamlStringify } from 'yaml';
44
import { buildArtifact as coreBuildArtifact } from '@hyperlane-xyz/core/buildArtifact.js';
55
import {
66
AltVMJsonRpcSubmitter,
7-
AltVMWarpModule,
7+
createWarpTokenWriter,
88
} from '@hyperlane-xyz/deploy-sdk';
99
import { AltVMFileSubmitter } from '@hyperlane-xyz/deploy-sdk/AltVMFileSubmitter';
1010
import { GasAction, ProtocolType } from '@hyperlane-xyz/provider-sdk';
11+
import { ArtifactState } from '@hyperlane-xyz/provider-sdk/artifact';
12+
import { warpConfigToArtifact } from '@hyperlane-xyz/provider-sdk/warp';
1113
import {
1214
type AddWarpRouteConfigOptions,
1315
BaseRegistry,
@@ -795,19 +797,22 @@ async function updateExistingWarpRoute(
795797
chain,
796798
);
797799

798-
const warpModule = new AltVMWarpModule(
799-
altVmChainLookup(multiProvider),
800+
const chainLookup = altVmChainLookup(multiProvider);
801+
const chainMetadata = chainLookup.getChainMetadata(chain);
802+
const writer = createWarpTokenWriter(
803+
chainMetadata,
804+
chainLookup,
800805
signer,
801-
{
802-
config: validatedConfig,
803-
chain,
804-
addresses: {
805-
deployedTokenRoute,
806-
},
807-
},
808806
);
807+
const artifact = warpConfigToArtifact(validatedConfig, chainLookup);
808+
809+
const artifactToUpdate = {
810+
artifactState: ArtifactState.DEPLOYED,
811+
config: artifact.config,
812+
deployed: { address: deployedTokenRoute },
813+
};
809814

810-
const transactions = await warpModule.update(validatedConfig);
815+
const transactions = await writer.update(artifactToUpdate);
811816
updateTransactions[chain] = transactions;
812817
break;
813818
}

typescript/cli/src/ism/deploy.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { buildArtifact as coreBuildArtifact } from '@hyperlane-xyz/core/buildArtifact.js';
2+
import { createIsmWriter } from '@hyperlane-xyz/deploy-sdk';
3+
import { GasAction, ProtocolType } from '@hyperlane-xyz/provider-sdk';
24
import {
3-
createIsmWriter,
5+
type IsmConfig as ProviderIsmConfig,
46
ismConfigToArtifact,
5-
} from '@hyperlane-xyz/deploy-sdk';
6-
import { GasAction, ProtocolType } from '@hyperlane-xyz/provider-sdk';
7-
import { type IsmConfig as ProviderIsmConfig } from '@hyperlane-xyz/provider-sdk/ism';
7+
} from '@hyperlane-xyz/provider-sdk/ism';
88
import {
99
ContractVerifier,
1010
EvmIsmModule,

typescript/cli/src/read/warp.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
HypXERC20__factory,
66
IXERC20__factory,
77
} from '@hyperlane-xyz/core';
8-
import { AltVMWarpRouteReader } from '@hyperlane-xyz/deploy-sdk';
8+
import { createWarpTokenReader } from '@hyperlane-xyz/deploy-sdk';
99
import { hasProtocol } from '@hyperlane-xyz/provider-sdk';
1010
import {
1111
type ChainMap,
@@ -21,7 +21,6 @@ import {
2121
import {
2222
type Address,
2323
ProtocolType,
24-
mustGet,
2524
objFilter,
2625
objMap,
2726
promiseObjAll,
@@ -132,14 +131,10 @@ async function deriveWarpRouteConfigs(
132131
).deriveWarpRouteConfig(address);
133132
}
134133
default: {
135-
const provider = mustGet(context.altVmProviders, chain);
136134
const chainLookup = altVmChainLookup(multiProvider);
137-
const metadata = chainLookup.getChainMetadata(chain);
138-
return new AltVMWarpRouteReader(
139-
metadata,
140-
chainLookup,
141-
provider,
142-
).deriveWarpRouteConfig(address);
135+
const chainMetadata = chainLookup.getChainMetadata(chain);
136+
const reader = createWarpTokenReader(chainMetadata, chainLookup);
137+
return reader.deriveWarpConfig(address);
143138
}
144139
}
145140
}),

typescript/cli/src/tests/cross-chain/warp/warp-apply.e2e-test.ts

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,21 @@ import {
4747
getUnsupportedChainWarpCoreTokenConfig,
4848
} from '../../utils.js';
4949

50+
// AltVM readers key remoteRouters by chain name; EVM readers by domain ID.
51+
// Try both until the inconsistency is addressed in a follow-up PR.
52+
function getUnsupportedChainRouterAddress(
53+
config: DerivedWarpRouteDeployConfig,
54+
chainName: string,
55+
): string | undefined {
56+
const routers = config[chainName].remoteRouters ?? {};
57+
return (
58+
routers[TEST_CHAIN_METADATA_BY_PROTOCOL.sealevel.UNSUPPORTED_CHAIN.name]
59+
?.address ??
60+
routers[TEST_CHAIN_METADATA_BY_PROTOCOL.sealevel.UNSUPPORTED_CHAIN.domainId]
61+
?.address
62+
);
63+
}
64+
5065
chai.use(chaiAsPromised);
5166
const expect = chai.expect;
5267
chai.should();
@@ -252,11 +267,9 @@ describe('hyperlane warp apply e2e tests', async function () {
252267
chainName,
253268
);
254269

255-
expect(
256-
(config[chainName].remoteRouters ?? {})[
257-
TEST_CHAIN_METADATA_BY_PROTOCOL.sealevel.UNSUPPORTED_CHAIN.domainId
258-
].address,
259-
).to.eql(addressToBytes32(unsupportedChainAddress));
270+
expect(getUnsupportedChainRouterAddress(config, chainName)).to.eql(
271+
addressToBytes32(unsupportedChainAddress),
272+
);
260273
}
261274
});
262275

@@ -325,11 +338,9 @@ describe('hyperlane warp apply e2e tests', async function () {
325338
chainName,
326339
);
327340

328-
expect(
329-
(config[chainName].remoteRouters ?? {})[
330-
TEST_CHAIN_METADATA_BY_PROTOCOL.sealevel.UNSUPPORTED_CHAIN.domainId
331-
].address,
332-
).to.eql(addressToBytes32(unsupportedChainAddress));
341+
expect(getUnsupportedChainRouterAddress(config, chainName)).to.eql(
342+
addressToBytes32(unsupportedChainAddress),
343+
);
333344
}
334345
});
335346
});

typescript/cli/src/tests/cross-chain/warp/warp-deploy.e2e-test.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -262,11 +262,19 @@ describe('hyperlane warp deploy e2e tests', async function () {
262262
chainName,
263263
);
264264

265-
expect(
265+
// AltVM readers key remoteRouters by chain name; EVM readers by domain ID.
266+
// Try both until the inconsistency is addressed in a follow-up PR.
267+
const maybeUnsupportedChainRouterAddress =
268+
(config[chainName].remoteRouters ?? {})[
269+
TEST_CHAIN_METADATA_BY_PROTOCOL.sealevel.UNSUPPORTED_CHAIN.name
270+
]?.address ??
266271
(config[chainName].remoteRouters ?? {})[
267272
TEST_CHAIN_METADATA_BY_PROTOCOL.sealevel.UNSUPPORTED_CHAIN.domainId
268-
].address,
269-
).to.eql(addressToBytes32(unsupportedChainAddress));
273+
]?.address;
274+
275+
expect(maybeUnsupportedChainRouterAddress).to.eql(
276+
addressToBytes32(unsupportedChainAddress),
277+
);
270278
}
271279

272280
const warpCoreConfig: WarpCoreConfig = readYamlOrJson(WARP_CORE_PATH);

typescript/cosmos-sdk/src/warp/warp-artifact-manager.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ export class CosmosWarpArtifactManager implements IRawWarpArtifactManager {
4343
return QueryClient.withExtensions(cometClient, setupWarpExtension);
4444
}
4545

46+
supportsHookUpdates(): boolean {
47+
return false;
48+
}
49+
4650
async readWarpToken(address: string): Promise<DeployedRawWarpArtifact> {
4751
const query = await this.getQuery();
4852
const altVMType = await getWarpTokenType(query, address);

typescript/cosmos-sdk/src/warp/warp-query.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { type QueryClient } from '@cosmjs/stargate';
22

33
import { warpTypes } from '@hyperlane-xyz/cosmos-types';
44
import { AltVM } from '@hyperlane-xyz/provider-sdk';
5-
import { assert } from '@hyperlane-xyz/utils';
5+
import { assert, rootLogger } from '@hyperlane-xyz/utils';
66

77
import { type WarpExtension } from '../hyperlane/warp/query.js';
88
import {
@@ -89,15 +89,20 @@ export async function getCollateralWarpTokenConfig(
8989
tokenAddress,
9090
);
9191

92+
// Cosmos SDK tokens do not store token metadata on chain yet
93+
rootLogger.warn(
94+
`Token metadata (name, symbol, decimals) is not stored on-chain for Cosmos collateral token at ${tokenAddress}. Falling back to placeholder values.`,
95+
);
9296
return {
9397
type: AltVM.TokenType.collateral,
9498
address: token.id,
9599
owner: token.owner,
96100
mailbox: token.origin_mailbox,
97101
interchainSecurityModule: token.ism_id,
98102
token: token.origin_denom,
99-
name: '',
100-
symbol: '',
103+
// Cosmos SDK tokens do not store token metadata on chain yet
104+
name: 'Unknown',
105+
symbol: 'Unknown',
101106
decimals: 0,
102107
remoteRouters,
103108
destinationGas,
@@ -129,14 +134,19 @@ export async function getSyntheticWarpTokenConfig(
129134
tokenAddress,
130135
);
131136

137+
// Cosmos SDK tokens do not store token metadata on chain yet
138+
rootLogger.warn(
139+
`Token metadata (name, symbol, decimals) is not stored on-chain for Cosmos synthetic token at ${tokenAddress}. Falling back to placeholder values.`,
140+
);
132141
return {
133142
type: AltVM.TokenType.synthetic,
134143
address: token.id,
135144
owner: token.owner,
136145
mailbox: token.origin_mailbox,
137146
interchainSecurityModule: token.ism_id,
138-
name: '',
139-
symbol: '',
147+
// Cosmos SDK tokens do not store token metadata on chain yet
148+
name: 'Unknown',
149+
symbol: 'Unknown',
140150
decimals: 0,
141151
remoteRouters,
142152
destinationGas,

0 commit comments

Comments
 (0)