fix: correctly recover the warp route router from artifacts (#3379)

### Description

- Writing and read to cache as the [token.type]: address.

NOTE: this breaks if the agents index by {router: address} for warp
routes but can we easily fixed by checking for any of the tokenTypes
Ideally, we want a multi-key artifact like { sepolia: [{type:synthetic,
standard:erc20, name: 'USD Coin', address: 0x1233..}],} but that's more
scope than intended for this issue. cc @daniel-savu @tkporter

### Drive-by changes

None

### Related issues

- fixes https://github.com/hyperlane-xyz/hyperlane-monorepo/issues/3296

### Backward compatibility

Yes

### Testing

Manual
pull/3438/head
Kunal Arora 8 months ago committed by GitHub
parent 8a216c116e
commit d90dc92b22
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 5
      typescript/cli/src/deploy/warp.ts
  2. 1
      typescript/infra/src/deployment/deploy.ts
  3. 1
      typescript/sdk/src/token/TokenStandard.ts
  4. 1
      typescript/sdk/src/token/config.ts
  5. 32
      typescript/sdk/src/token/contracts.ts
  6. 139
      typescript/sdk/src/token/deploy.ts
  7. 1
      typescript/utils/index.ts
  8. 5
      typescript/utils/src/objects.ts

@ -318,7 +318,7 @@ function writeTokenDeploymentArtifacts(
tokenType: TokenType;
}> = objMap(contracts, (chain, contract) => {
return {
router: contract.router.address,
router: contract[configMap[chain].type as keyof TokenFactories].address,
tokenType: configMap[chain].type,
};
});
@ -343,7 +343,8 @@ function writeWarpUiTokenConfig(
name: metadata.name,
symbol: metadata.symbol,
decimals: metadata.decimals,
addressOrDenom: contract.router.address,
addressOrDenom:
contract[configMap[chainName].type as keyof TokenFactories].address,
collateralAddressOrDenom,
});
}

@ -16,7 +16,6 @@ import { DeployEnvironment } from '../config';
import {
readJSONAtPath,
writeJsonAtPath,
writeMergedJSON,
writeMergedJSONAtPath,
} from '../utils/utils';

@ -138,6 +138,7 @@ export const TOKEN_TYPE_TO_STANDARD: Record<TokenType, TokenStandard> = {
[TokenType.synthetic]: TokenStandard.EvmHypSynthetic,
[TokenType.syntheticUri]: TokenStandard.EvmHypSynthetic,
[TokenType.fastSynthetic]: TokenStandard.EvmHypSynthetic,
[TokenType.nativeScaled]: TokenStandard.EvmHypNative,
};
export const PROTOCOL_TO_NATIVE_STANDARD: Record<ProtocolType, TokenStandard> =

@ -10,6 +10,7 @@ export enum TokenType {
fastCollateral = 'fastCollateral',
collateralUri = 'collateralUri',
native = 'native',
nativeScaled = 'nativeScaled',
}
export type TokenMetadata = {

@ -5,23 +5,31 @@ import {
HypERC20__factory,
HypERC721Collateral__factory,
HypERC721URICollateral__factory,
HypERC721URIStorage__factory,
HypERC721__factory,
HypNativeScaled__factory,
HypNative__factory,
} from '@hyperlane-xyz/core';
export type HypERC20Factories = {
router:
| HypERC20__factory
| HypERC20Collateral__factory
| HypNative__factory
| FastHypERC20__factory
| FastHypERC20Collateral__factory;
import { TokenType } from './config';
export const hypERC20factories = {
[TokenType.fastCollateral]: new FastHypERC20Collateral__factory(),
[TokenType.fastSynthetic]: new FastHypERC20__factory(),
[TokenType.synthetic]: new HypERC20__factory(),
[TokenType.collateral]: new HypERC20Collateral__factory(),
[TokenType.native]: new HypNative__factory(),
[TokenType.nativeScaled]: new HypNativeScaled__factory(),
};
export type HypERC721Factories = {
router:
| HypERC721__factory
| HypERC721Collateral__factory
| HypERC721URICollateral__factory;
export type HypERC20Factories = typeof hypERC20factories;
export const hypERC721factories = {
[TokenType.collateralUri]: new HypERC721URICollateral__factory(),
[TokenType.collateral]: new HypERC721Collateral__factory(),
[TokenType.syntheticUri]: new HypERC721URIStorage__factory(),
[TokenType.synthetic]: new HypERC721__factory(),
};
export type HypERC721Factories = typeof hypERC721factories;
export type TokenFactories = HypERC20Factories | HypERC721Factories;

@ -5,23 +5,13 @@ import { providers } from 'ethers';
import {
ERC20__factory,
ERC721EnumerableUpgradeable__factory,
FastHypERC20Collateral__factory,
FastHypERC20__factory,
HypERC20,
HypERC20Collateral,
HypERC20Collateral__factory,
HypERC20__factory,
HypERC721,
HypERC721Collateral,
HypERC721Collateral__factory,
HypERC721URICollateral__factory,
HypERC721URIStorage__factory,
HypERC721__factory,
HypNative,
HypNativeScaled__factory,
HypNative__factory,
} from '@hyperlane-xyz/core';
import { objMap } from '@hyperlane-xyz/utils';
import { objKeys, objMap } from '@hyperlane-xyz/utils';
import { HyperlaneContracts } from '../contracts/types';
import { ContractVerifier } from '../deploy/verify/ContractVerifier';
@ -43,6 +33,7 @@ import {
HypNativeConfig,
TokenConfig,
TokenMetadata,
TokenType,
isCollateralConfig,
isErc20Metadata,
isFastConfig,
@ -51,7 +42,12 @@ import {
isTokenMetadata,
isUriConfig,
} from './config';
import { HypERC20Factories, HypERC721Factories } from './contracts';
import {
HypERC20Factories,
HypERC721Factories,
hypERC20factories,
hypERC721factories,
} from './contracts';
export class HypERC20Deployer extends GasRouterDeployer<
ERC20RouterConfig,
@ -62,7 +58,7 @@ export class HypERC20Deployer extends GasRouterDeployer<
ismFactory?: HyperlaneIsmFactory,
contractVerifier?: ContractVerifier,
) {
super(multiProvider, {} as HypERC20Factories, {
super(multiProvider, hypERC20factories, {
logger: debug('hyperlane:HypERC20Deployer'),
ismFactory,
contractVerifier,
@ -139,56 +135,36 @@ export class HypERC20Deployer extends GasRouterDeployer<
chain: ChainName,
config: HypERC20CollateralConfig,
): Promise<HypERC20Collateral> {
const isFast = isFastConfig(config);
const factory = isFast
? new FastHypERC20Collateral__factory()
: new HypERC20Collateral__factory();
const name = isFast ? 'FastHypERC20Collateral' : 'HypERC20Collateral';
return this.deployContractFromFactory(chain, factory, name, [
config.token,
config.mailbox,
]);
return this.deployContract(
chain,
isFastConfig(config) ? TokenType.fastCollateral : TokenType.collateral,
[config.token, config.mailbox],
);
}
protected async deployNative(
chain: ChainName,
config: HypNativeConfig,
): Promise<HypNative> {
let router: HypNative;
if (config.scale) {
router = await this.deployContractFromFactory(
chain,
new HypNativeScaled__factory(),
'HypNativeScaled',
[config.scale, config.mailbox],
);
return this.deployContract(chain, TokenType.nativeScaled, [
config.scale,
config.mailbox,
]);
} else {
router = await this.deployContractFromFactory(
chain,
new HypNative__factory(),
'HypNative',
[config.mailbox],
);
return this.deployContract(chain, TokenType.native, [config.mailbox]);
}
return router;
}
protected async deploySynthetic(
chain: ChainName,
config: HypERC20Config,
): Promise<HypERC20> {
const isFast = isFastConfig(config);
const factory = isFast
? new FastHypERC20__factory()
: new HypERC20__factory();
const name = isFast ? 'FastHypERC20' : 'HypERC20';
const router = await this.deployContractFromFactory(chain, factory, name, [
config.decimals,
config.mailbox,
]);
const router: HypERC20 = await this.deployContract(
chain,
isFastConfig(config) ? TokenType.fastSynthetic : TokenType.synthetic,
[config.decimals, config.mailbox],
);
try {
await this.multiProvider.handleTx(
chain,
@ -198,13 +174,18 @@ export class HypERC20Deployer extends GasRouterDeployer<
if (!e.message.includes('already initialized')) {
throw e;
}
this.logger(`${name} already initialized`);
this.logger(`${config.type} already initialized`);
}
return router;
}
router(contracts: HyperlaneContracts<HypERC20Factories>) {
return contracts.router;
for (const key of objKeys(hypERC20factories)) {
if (contracts[key]) {
return contracts[key];
}
}
throw new Error('No matching contract found');
}
async deployContracts(chain: ChainName, config: HypERC20Config) {
@ -219,7 +200,7 @@ export class HypERC20Deployer extends GasRouterDeployer<
throw new Error('Invalid ERC20 token router config');
}
await this.configureClient(chain, router, config);
return { router };
return { [config.type]: router } as any;
}
async buildTokenMetadata(
@ -290,10 +271,10 @@ export class HypERC721Deployer extends GasRouterDeployer<
multiProvider: MultiProvider,
contractVerifier?: ContractVerifier,
) {
super(multiProvider, {} as HypERC721Factories, {
super(multiProvider, hypERC721factories, {
logger: debug('hyperlane:HypERC721Deployer'),
contractVerifier,
}); // factories not used in deploy
});
}
static async fetchMetadata(
@ -330,45 +311,22 @@ export class HypERC721Deployer extends GasRouterDeployer<
chain: ChainName,
config: HypERC721CollateralConfig,
): Promise<HypERC721Collateral> {
let router: HypERC721Collateral;
if (isUriConfig(config)) {
router = await this.deployContractFromFactory(
chain,
new HypERC721URICollateral__factory(),
'HypERC721URICollateral',
[config.token, config.mailbox],
);
} else {
router = await this.deployContractFromFactory(
chain,
new HypERC721Collateral__factory(),
'HypERC721Collateral',
[config.token, config.mailbox],
);
}
return router;
return this.deployContract(
chain,
isUriConfig(config) ? TokenType.collateralUri : TokenType.collateral,
[config.token, config.mailbox],
);
}
protected async deploySynthetic(
chain: ChainName,
config: HypERC721Config,
): Promise<HypERC721> {
let router: HypERC721;
if (isUriConfig(config)) {
router = await this.deployContractFromFactory(
chain,
new HypERC721URIStorage__factory(),
'HypERC721URIStorage',
[config.mailbox],
);
} else {
router = await this.deployContractFromFactory(
chain,
new HypERC721__factory(),
'HypERC721',
[config.mailbox],
);
}
const router = await this.deployContract(
chain,
isUriConfig(config) ? TokenType.syntheticUri : TokenType.synthetic,
[config.mailbox],
);
await this.multiProvider.handleTx(
chain,
router.initialize(config.totalSupply, config.name, config.symbol),
@ -377,7 +335,12 @@ export class HypERC721Deployer extends GasRouterDeployer<
}
router(contracts: HyperlaneContracts<HypERC721Factories>) {
return contracts.router;
for (const key of objKeys(hypERC721factories)) {
if (contracts[key]) {
return contracts[key];
}
}
throw new Error('No matching contract found');
}
async deployContracts(chain: ChainName, config: HypERC721Config) {
@ -389,7 +352,7 @@ export class HypERC721Deployer extends GasRouterDeployer<
} else {
throw new Error('Invalid ERC721 token router config');
}
return { router };
return { [config.type]: router } as any;
}
async buildTokenMetadata(

@ -90,6 +90,7 @@ export {
invertKeysAndValues,
isObject,
objFilter,
objKeys,
objMap,
objMapEntries,
objMerge,

@ -12,6 +12,11 @@ export function deepCopy(v: any) {
export type ValueOf<T> = T[keyof T];
// Useful for maintaining type safety when using Object.keys
export function objKeys<T extends string | number>(obj: Record<T, any>): T[] {
return Object.keys(obj) as T[];
}
export function objMapEntries<
M extends Record<K, I>,
K extends keyof M,

Loading…
Cancel
Save