Skip to content

Commit

Permalink
yorke PR review
Browse files Browse the repository at this point in the history
  • Loading branch information
ltyu committed May 28, 2024
1 parent 07e68f1 commit 9bd4308
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 51 deletions.
19 changes: 8 additions & 11 deletions typescript/sdk/src/token/EvmERC20WarpModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,13 @@ import {
} from '../core/AbstractHyperlaneModule.js';
import { MultiProvider } from '../providers/MultiProvider.js';
import { EthersV5Transaction } from '../providers/ProviderType.js';
import { RouterConfig } from '../router/types.js';
import { ChainMap, ChainNameOrId } from '../types.js';
import { ChainNameOrId } from '../types.js';

import {
DerivedTokenRouterConfig,
DerivedTokenType,
EvmERC20WarpRouteReader,
} from './EvmERC20WarpRouteReader.js';
import { TokenConfig } from './config.js';
import { HypERC20Config } from './config.js';
import { HypERC20Factories } from './contracts.js';
import { HypERC20Deployer } from './deploy.js';

Expand Down Expand Up @@ -86,18 +84,17 @@ export class EvmERC20WarpModule extends HyperlaneModule<
multiProvider: MultiProvider;
}): Promise<EvmERC20WarpModule> {
const { chain, config, multiProvider } = params;
const chainName = multiProvider.getChainName(chain);
const deployer = new HypERC20Deployer(multiProvider);
const deployedContracts = (
await deployer.deploy({
[chain]: config,
} as ChainMap<TokenConfig & RouterConfig>)
)[chain];
const deployedContracts = await deployer.deployContracts(
chainName,
config as HypERC20Config,
);

return new EvmERC20WarpModule(multiProvider, {
addresses: {
...serializeContracts(deployedContracts),
deployedTokenRoute:
deployedContracts[config.type as DerivedTokenType].address,
deployedTokenRoute: deployedContracts[config.type].address,
},
chain,
config,
Expand Down
53 changes: 50 additions & 3 deletions typescript/sdk/src/token/EvmERC20WarpRouteReader.hardhat-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import { ChainMap } from '../types.js';

import {
DerivedTokenRouterConfig,
DerivedTokenType,
EvmERC20WarpRouteReader,
} from './EvmERC20WarpRouteReader.js';
import { TokenConfig, TokenType } from './config.js';
Expand Down Expand Up @@ -80,12 +79,12 @@ describe('ERC20WarpRouterReader', async () => {
});

it('should derive a token type from contract', async () => {
const typesToDerive: DerivedTokenType[] = [
const typesToDerive = [
TokenType.collateral,
TokenType.collateralVault,
TokenType.synthetic,
TokenType.native,
];
] as const;

await Promise.all(
typesToDerive.map(async (type) => {
Expand Down Expand Up @@ -211,4 +210,52 @@ describe('ERC20WarpRouterReader', async () => {
// Check if token values matches
expect(derivedConfig.decimals).to.equal(TOKEN_DECIMALS);
});

it('should return undefined if ism is not set onchain', async () => {
// Create config
let config = {
[chain]: {
type: TokenType.collateral,
token: token.address,
hook: await mailbox.defaultHook(),
...baseConfig,
},
};
// Deploy with config
let warpRoute = await deployer.deploy(
config as ChainMap<TokenConfig & RouterConfig>,
);

// Derive config and check if each value matches
let derivedConfig = await evmERC20WarpRouteReader.deriveWarpRouteConfig(
warpRoute[chain].collateral.address,
);

expect(derivedConfig.interchainSecurityModule).to.be.undefined;
const interchainSecurityModule = await mailbox.defaultIsm();

// Try with Ism set
config = {
[chain]: {
type: TokenType.collateral,
token: token.address,
hook: await mailbox.defaultHook(),
interchainSecurityModule,
...baseConfig,
},
};
// Deploy with config
warpRoute = await deployer.deploy(
config as ChainMap<TokenConfig & RouterConfig>,
);

// Derive config and check if each value matches
derivedConfig = await evmERC20WarpRouteReader.deriveWarpRouteConfig(
warpRoute[chain].collateral.address,
);

expect(derivedConfig.interchainSecurityModule?.address).to.be.equal(
interchainSecurityModule,
);
});
});
57 changes: 20 additions & 37 deletions typescript/sdk/src/token/EvmERC20WarpRouteReader.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ethers, providers } from 'ethers';
import { providers } from 'ethers';

import {
HypERC20CollateralVaultDeposit__factory,
Expand All @@ -7,7 +7,6 @@ import {
} from '@hyperlane-xyz/core';
import {
ERC20Metadata,
IsmType,
TokenRouterConfig,
TokenType,
} from '@hyperlane-xyz/sdk';
Expand All @@ -26,17 +25,7 @@ type WarpRouteBaseMetadata = Record<'mailbox' | 'owner' | 'hook', string> & {
interchainSecurityModule?: DerivedIsmConfigWithAddress;
};

/**
* @remark
* We only expect to support deriving a subset of these types, for now.
*/
export type DerivedTokenType = Extract<
TokenType,
'collateral' | 'collateralVault' | 'native' | 'synthetic'
>;

export type DerivedTokenRouterConfig = TokenRouterConfig & {
type: DerivedTokenType;
interchainSecurityModule?: DerivedIsmConfigWithAddress;
};

Expand Down Expand Up @@ -89,10 +78,9 @@ export class EvmERC20WarpRouteReader {
* @param warpRouteAddress - The Warp Route address to derive the token type for.
* @returns The derived token type, which can be one of: collateralVault, collateral, native, or synthetic.
*/
async deriveTokenType(warpRouteAddress: Address): Promise<DerivedTokenType> {
const contractTypes: Record<
Exclude<DerivedTokenType, 'native'>, // native is excluded because it's the default return type
{ factory: any; method: string }
async deriveTokenType(warpRouteAddress: Address): Promise<TokenType> {
const contractTypes: Partial<
Record<TokenType, { factory: any; method: string }>
> = {
collateralVault: {
factory: HypERC20CollateralVaultDeposit__factory,
Expand All @@ -112,7 +100,7 @@ export class EvmERC20WarpRouteReader {
try {
const warpRoute = factory.connect(warpRouteAddress, this.provider);
await warpRoute[method]();
return type as DerivedTokenType;
return type as TokenType;
} catch (e) {
this.logger.info(
`Error accessing token specific method, ${method}, implying this is not a ${type} token.`,
Expand Down Expand Up @@ -154,23 +142,14 @@ export class EvmERC20WarpRouteReader {
hook,
};

// If ISM is unset, then Address Zero will be returned
isZeroishAddress(interchainSecurityModule)
? (metadata.interchainSecurityModule = {
type: IsmType.CUSTOM,
address: ethers.constants.AddressZero,
})
: (metadata.interchainSecurityModule =
await this.evmIsmReader.deriveIsmConfig(interchainSecurityModule));

// @todo add after https://github.com/hyperlane-xyz/hyperlane-monorepo/issues/3667 is fixed
// isZeroishAddress(interchainSecurityModule)
// ? (metadata.hook = {
// type: IsmType.ADDRESS,
// address: ethers.constants.AddressZero,
// })
// : (metadata.hook =
// await this.evmIsmReader.deriveHookConfig(hook));
// Derive If ISM is set onchain
metadata.interchainSecurityModule = !isZeroishAddress(
interchainSecurityModule,
)
? await this.evmIsmReader.deriveIsmConfig(interchainSecurityModule)
: undefined;

// @todo add Hook config after https://github.com/hyperlane-xyz/hyperlane-monorepo/issues/3667 is fixed

return metadata;
}
Expand All @@ -180,9 +159,10 @@ export class EvmERC20WarpRouteReader {
*
* @param tokenAddress - The address of the token.
* @returns A partial ERC20 metadata object containing the token name, symbol, total supply, and decimals.
* Throws if unsupported token type
*/
async fetchTokenMetadata(
type: DerivedTokenType,
type: TokenType,
tokenAddress: Address,
): Promise<ERC20Metadata & { token?: string }> {
if (type === TokenType.collateral || type === TokenType.collateralVault) {
Expand All @@ -197,8 +177,7 @@ export class EvmERC20WarpRouteReader {
return { name, symbol, decimals, totalSupply, token };
} else if (type === TokenType.synthetic) {
return this.fetchERC20Metadata(tokenAddress);
} else {
// Assumes Native
} else if (type === TokenType.native) {
const chainMetadata = this.multiProvider.getChainMetadata(this.chain);
if (chainMetadata.nativeToken) {
const { name, symbol, decimals } = chainMetadata.nativeToken;
Expand All @@ -208,6 +187,10 @@ export class EvmERC20WarpRouteReader {
`Warp route config specifies native token but chain metadata for ${this.chain} does not provide native token details`,
);
}
} else {
throw new Error(
`Unsupported token type ${type} when fetching token metadata`,
);
}
}

Expand Down

0 comments on commit 9bd4308

Please sign in to comment.