diff --git a/contracts/HypNative.sol b/contracts/HypNativeCollateral.sol similarity index 93% rename from contracts/HypNative.sol rename to contracts/HypNativeCollateral.sol index 4accae4..d473304 100644 --- a/contracts/HypNative.sol +++ b/contracts/HypNativeCollateral.sol @@ -6,11 +6,11 @@ import {Message} from "./libs/Message.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; /** - * @title Hyperlane Native Token Router that extends ERC20 with remote transfer functionality. + * @title Hyperlane Native Collateral Token Router that extends native asset with remote transfer functionality. * @author Abacus Works * @dev Supply on each chain is not constant but the aggregate supply across all chains is. */ -contract HypNative is TokenRouter { +contract HypNativeCollateral is TokenRouter { /** * @notice Initializes the Hyperlane router, ERC20 metadata, and mints initial supply to deployer. * @param _mailbox The address of the mailbox contract. diff --git a/src/app.ts b/src/app.ts index 366624b..28eec88 100644 --- a/src/app.ts +++ b/src/app.ts @@ -8,13 +8,13 @@ import { HypERC721Factories, TokenFactories, } from './contracts'; -import { TokenRouter } from './types'; +import { HypERC20, HypERC20Collateral, HypERC721, HypERC721Collateral, HypNativeCollateral, TokenRouter } from './types'; class HyperlaneTokenApp< Factories extends TokenFactories, > extends RouterApp { - router(contracts: HyperlaneContracts): TokenRouter { - return contracts.router; + router(contracts: HyperlaneContracts): TokenRouter { + return contracts['synthetic'] || contracts['collateral']; } async transfer( @@ -23,7 +23,7 @@ class HyperlaneTokenApp< recipient: types.Address, amountOrId: BigNumberish, ) { - const originRouter = this.getContracts(origin).router; + const originRouter = this.router(this.getContracts(origin)); const destProvider = this.multiProvider.getProvider(destination); const destinationNetwork = await destProvider.getNetwork(); const gasPayment = await originRouter.quoteGasPayment( @@ -44,13 +44,17 @@ class HyperlaneTokenApp< } export class HypERC20App extends HyperlaneTokenApp { + router(contracts: HyperlaneContracts): HypERC20 | HypERC20Collateral | HypNativeCollateral { + return contracts['synthetic'] || contracts['collateral']; + } + async transfer( origin: ChainName, destination: ChainName, recipient: types.Address, amount: BigNumberish, ) { - const originRouter = this.getContracts(origin).router; + const originRouter = this.router(this.getContracts(origin)); const signerAddress = await this.multiProvider.getSignerAddress(origin); const balance = await originRouter.balanceOf(signerAddress); if (balance.lt(amount)) @@ -62,13 +66,17 @@ export class HypERC20App extends HyperlaneTokenApp { } export class HypERC721App extends HyperlaneTokenApp { + router(contracts: HyperlaneContracts): HypERC721 | HypERC721Collateral { + return contracts['synthetic'] || contracts['collateral']; + } + async transfer( origin: ChainName, destination: ChainName, recipient: types.Address, tokenId: BigNumberish, ) { - const originRouter = this.getContracts(origin).router; + const originRouter = this.router(this.getContracts(origin)); const signerAddress = await this.multiProvider.getSignerAddress(origin); const owner = await originRouter.ownerOf(tokenId); if (signerAddress != owner) diff --git a/src/config.ts b/src/config.ts index cbb62bd..112e467 100644 --- a/src/config.ts +++ b/src/config.ts @@ -7,7 +7,6 @@ export enum TokenType { syntheticUri = 'syntheticUri', collateral = 'collateral', collateralUri = 'collateralUri', - native = 'native', } export type TokenMetadata = { @@ -31,17 +30,12 @@ export type SyntheticConfig = TokenMetadata & { }; export type CollateralConfig = { type: TokenType.collateral | TokenType.collateralUri; - token: string; -}; -export type NativeConfig = { - type: TokenType.native; + token?: string; // no token implies native collateral }; -export type TokenConfig = { type: TokenType } & ( +export type TokenConfig = | SyntheticConfig | CollateralConfig - | NativeConfig -); export const isCollateralConfig = ( config: TokenConfig, @@ -54,21 +48,8 @@ export const isSyntheticConfig = ( ): config is SyntheticConfig => config.type === TokenType.synthetic || config.type === TokenType.syntheticUri; -export const isNativeConfig = (config: TokenConfig): config is NativeConfig => - config.type === TokenType.native; - export const isUriConfig = (config: TokenConfig) => config.type === TokenType.syntheticUri || config.type === TokenType.collateralUri; -export type HypERC20Config = GasRouterConfig & SyntheticConfig & ERC20Metadata; -export type HypERC20CollateralConfig = GasRouterConfig & CollateralConfig; -export type HypNativeConfig = GasRouterConfig & NativeConfig; -export type ERC20RouterConfig = - | HypERC20Config - | HypERC20CollateralConfig - | HypNativeConfig; - -export type HypERC721Config = GasRouterConfig & SyntheticConfig; -export type HypERC721CollateralConfig = GasRouterConfig & CollateralConfig; -export type ERC721RouterConfig = HypERC721Config | HypERC721CollateralConfig; +export type TokenRouterConfig = TokenConfig & GasRouterConfig; diff --git a/src/contracts.ts b/src/contracts.ts index e22cc49..44ff053 100644 --- a/src/contracts.ts +++ b/src/contracts.ts @@ -1,20 +1,29 @@ +import { ethers } from 'ethers'; import { HypERC20Collateral__factory, HypERC20__factory, HypERC721Collateral__factory, HypERC721URICollateral__factory, + HypERC721URIStorage__factory, HypERC721__factory, - HypNative__factory, + HypNativeCollateral__factory, + TokenRouter__factory, } from './types'; -export type HypERC20Factories = { - router: HypERC20__factory | HypERC20Collateral__factory | HypNative__factory; -}; -export type HypERC721Factories = { - router: - | HypERC721__factory - | HypERC721Collateral__factory - | HypERC721URICollateral__factory; -}; +export type TokenFactories = { synthetic: TokenRouter__factory & ethers.ContractFactory } | { collateral: TokenRouter__factory & ethers.ContractFactory }; -export type TokenFactories = HypERC20Factories | HypERC721Factories; +export type HypERC20Factories = + | { + synthetic: HypERC20__factory; + } + | { collateral: HypERC20Collateral__factory | HypNativeCollateral__factory }; + +export type HypERC721Factories = + | { + synthetic: HypERC721__factory | HypERC721URIStorage__factory; + } + | { + collateral: + | HypERC721Collateral__factory + | HypERC721URICollateral__factory; + }; diff --git a/src/deploy.ts b/src/deploy.ts index 067d36e..36f63b8 100644 --- a/src/deploy.ts +++ b/src/deploy.ts @@ -1,5 +1,3 @@ -import { providers } from 'ethers'; - import { ChainMap, ChainName, @@ -8,26 +6,23 @@ import { MultiProvider, objMap, } from '@hyperlane-xyz/sdk'; -import { GasConfig, RouterConfig } from '@hyperlane-xyz/sdk/dist/router/types'; +import { RouterConfig } from '@hyperlane-xyz/sdk/dist/router/types'; import { CollateralConfig, ERC20Metadata, - HypERC20CollateralConfig, - HypERC20Config, - HypERC721CollateralConfig, - HypERC721Config, - HypNativeConfig, + TokenRouterConfig, + SyntheticConfig, TokenConfig, TokenMetadata, + TokenType, isCollateralConfig, isErc20Metadata, - isNativeConfig, isSyntheticConfig, isUriConfig, } from './config'; import { isTokenMetadata } from './config'; -import { HypERC20Factories, HypERC721Factories } from './contracts'; +import { HypERC20Factories, HypERC721Factories, TokenFactories } from './contracts'; import { ERC20__factory, ERC721EnumerableUpgradeable__factory, @@ -41,82 +36,135 @@ import { HypERC721URICollateral__factory, HypERC721URIStorage__factory, HypERC721__factory, - HypNative, - HypNative__factory, + HypNativeCollateral, + HypNativeCollateral__factory, + TokenRouter, } from './types'; -import { ERC721RouterConfig } from './config'; -import { ERC20RouterConfig } from './config'; -export class HypERC20Deployer extends GasRouterDeployer< - ERC20RouterConfig, - HypERC20Factories +abstract class TokenDeployer extends GasRouterDeployer< + TokenRouterConfig, + any > { + abstract fetchMetadata(config: ChainMap): Promise; + + abstract gasOverheadDefault(config: TokenConfig): number; + + abstract deployCollateral( + chain: ChainName, + config: CollateralConfig, + ): Promise; + + abstract deploySynthetic( + chain: ChainName, + config: SyntheticConfig & TokenMetadata, + ): Promise; + + async deployContracts(chain: ChainName, config: TokenConfig): Promise> { + if (isCollateralConfig(config)) { + const collateral = await this.deployCollateral(chain, config); + return { collateral }; + } else if (isSyntheticConfig(config)) { + const synthetic = await this.deploySynthetic(chain, config); + return { synthetic }; + } else { + throw new Error('Invalid token router config'); + } + } + + async deploy(configMap: ChainMap) { + const tokenMetadata = await this.fetchMetadata(configMap); + const mergedConfig = objMap( + configMap, + (_, config) => { + return { + ...tokenMetadata, + gas: this.gasOverheadDefault(config), + ...config, // override with chain-specific config + }; + }, + ); + + return super.deploy(mergedConfig); + } +} + + +export class HypERC20Deployer extends TokenDeployer { constructor(multiProvider: MultiProvider) { super(multiProvider, {} as HypERC20Factories); // factories not used in deploy } - static async fetchMetadata( - provider: providers.Provider, - config: CollateralConfig, - ): Promise { - const erc20 = ERC20__factory.connect(config.token, provider); - const name = await erc20.name(); - const symbol = await erc20.symbol(); - const totalSupply = await erc20.totalSupply(); - const decimals = await erc20.decimals(); + async fetchMetadata(configMap: ChainMap): Promise { + for (const [chain, config] of Object.entries(configMap)) { + if (isErc20Metadata(config)) { + return config; + } else if (isCollateralConfig(config)) { + if (config.token) { + const erc20 = ERC20__factory.connect(config.token, this.multiProvider.getProvider(chain)); + + const name = await erc20.name(); + const symbol = await erc20.symbol(); + const totalSupply = await erc20.totalSupply(); + const decimals = await erc20.decimals(); + + return { name, symbol, totalSupply, decimals }; + } else { // native collateral + const chainMetadata = this.multiProvider.getChainMetadata(chain); + + if (chainMetadata.nativeToken) { + return { + totalSupply: 0, + ...chainMetadata.nativeToken + } + } + } + } + } - return { name, symbol, totalSupply, decimals }; + throw new Error('No ERC20 metadata found'); } - static gasOverheadDefault(config: TokenConfig): number { + gasOverheadDefault(config: TokenConfig): number { switch (config.type) { - case 'synthetic': + case TokenType.synthetic: return 64_000; - case 'native': - return 44_000; - case 'collateral': + case TokenType.collateral: + return config.token ? 68_000 : 44_000; default: - return 68_000; + throw new Error('Invalid token type'); } } - protected async deployCollateral( + async deployCollateral( chain: ChainName, - config: HypERC20CollateralConfig, - ): Promise { - const router = await this.deployContractFromFactory( - chain, - new HypERC20Collateral__factory(), - 'HypERC20Collateral', - [config.token], - ); - await this.multiProvider.handleTx( - chain, - router.initialize(config.mailbox, config.interchainGasPaymaster), - ); - return router; - } - - protected async deployNative( - chain: ChainName, - config: HypNativeConfig, - ): Promise { - const router = await this.deployContractFromFactory( - chain, - new HypNative__factory(), - 'HypNative', - [], - ); + config: CollateralConfig & RouterConfig, + ): Promise { + let collateral: HypERC20Collateral | HypNativeCollateral; + if (config.token) { + collateral = await this.deployContractFromFactory( + chain, + new HypERC20Collateral__factory(), + 'HypERC20Collateral', + [config.token], + ); + } else { + collateral = await this.deployContractFromFactory( + chain, + new HypNativeCollateral__factory(), + 'HypNativeCollateral', + [], + ); + } await this.multiProvider.handleTx( chain, - router.initialize(config.mailbox, config.interchainGasPaymaster), + collateral.initialize(config.mailbox, config.interchainGasPaymaster), ); - return router; + return collateral; } - protected async deploySynthetic( + async deploySynthetic( chain: ChainName, - config: HypERC20Config, + config: SyntheticConfig & ERC20Metadata & RouterConfig, ): Promise { const router = await this.deployContractFromFactory( chain, @@ -138,122 +186,59 @@ export class HypERC20Deployer extends GasRouterDeployer< } router(contracts: HyperlaneContracts) { - return contracts.router; - } - - async deployContracts(chain: ChainName, config: HypERC20Config) { - let router: HypERC20 | HypERC20Collateral | HypNative; - if (isCollateralConfig(config)) { - router = await this.deployCollateral(chain, config); - } else if (isNativeConfig(config)) { - router = await this.deployNative(chain, config); - } else if (isSyntheticConfig(config)) { - router = await this.deploySynthetic(chain, config); - } else { - throw new Error('Invalid ERC20 token router config'); - } - return { router }; - } - - async buildTokenMetadata( - configMap: ChainMap, - ): Promise> { - let tokenMetadata: ERC20Metadata | undefined; - - for (const [chain, config] of Object.entries(configMap)) { - if (isCollateralConfig(config)) { - const collateralMetadata = await HypERC20Deployer.fetchMetadata( - this.multiProvider.getProvider(chain), - config, - ); - tokenMetadata = { - ...collateralMetadata, - totalSupply: 0, - }; - } else if (isNativeConfig(config)) { - const chainMetadata = this.multiProvider.getChainMetadata(chain); - if (chainMetadata.nativeToken) { - tokenMetadata = { - ...chainMetadata.nativeToken, - totalSupply: 0, - }; - } - } else if (isErc20Metadata(config)) { - tokenMetadata = config; - } - } - - if (!isErc20Metadata(tokenMetadata)) { - throw new Error('Invalid ERC20 token metadata'); - } - - return objMap(configMap, () => (tokenMetadata!)); - } - - buildGasOverhead(configMap: ChainMap): ChainMap { - return objMap(configMap, (_, config) => ({ - gas: HypERC20Deployer.gasOverheadDefault(config), - })); - } - - async deploy(configMap: ChainMap) { - const tokenMetadata = await this.buildTokenMetadata(configMap); - const gasOverhead = this.buildGasOverhead(configMap); - const mergedConfig = objMap( - configMap, - (chain, config) => { - return { - ...tokenMetadata[chain], - ...gasOverhead[chain], - ...config, - }; - }, - ) as ChainMap; - - return super.deploy(mergedConfig); + return Object.values(contracts)[0]; } } -export class HypERC721Deployer extends GasRouterDeployer< - ERC721RouterConfig, - HypERC721Factories -> { +export class HypERC721Deployer extends TokenDeployer { constructor(multiProvider: MultiProvider) { super(multiProvider, {} as HypERC721Factories); // factories not used in deploy } - static async fetchMetadata( - provider: providers.Provider, - config: CollateralConfig, - ): Promise { - const erc721 = ERC721EnumerableUpgradeable__factory.connect( - config.token, - provider, - ); - const name = await erc721.name(); - const symbol = await erc721.symbol(); - const totalSupply = await erc721.totalSupply(); + async fetchMetadata(configMap: ChainMap): Promise { + for (const [chain, config] of Object.entries(configMap)) { + if (isTokenMetadata(config)) { + return config; + } else if (isCollateralConfig(config)) { + if (config.token) { + const erc721 = ERC721EnumerableUpgradeable__factory.connect( + config.token, + this.multiProvider.getProvider(chain), + ); + const name = await erc721.name(); + const symbol = await erc721.symbol(); + const totalSupply = await erc721.totalSupply(); + + return { name, symbol, totalSupply }; + } + } + } - return { name, symbol, totalSupply }; + throw new Error('No ERC721 metadata found'); } - static gasOverheadDefault(config: TokenConfig): number { + gasOverheadDefault(config: TokenConfig): number { switch (config.type) { - case 'synthetic': + case TokenType.synthetic: return 160_000; - case 'syntheticUri': + case TokenType.syntheticUri: return 163_000; - case 'collateral': - case 'collateralUri': - default: + case TokenType.collateral: + case TokenType.collateralUri: return 80_000; + default: + throw new Error('Invalid ERC721 token type'); } } - protected async deployCollateral( + async deployCollateral( chain: ChainName, - config: HypERC721CollateralConfig, + config: CollateralConfig & RouterConfig, ): Promise { + if (!config.token) { + throw new Error('Collateral config invalid'); + } + let router: HypERC721Collateral; if (isUriConfig(config)) { router = await this.deployContractFromFactory( @@ -277,9 +262,9 @@ export class HypERC721Deployer extends GasRouterDeployer< return router; } - protected async deploySynthetic( + async deploySynthetic( chain: ChainName, - config: HypERC721Config, + config: SyntheticConfig & RouterConfig, ): Promise { let router: HypERC721; if (isUriConfig(config)) { @@ -311,68 +296,6 @@ export class HypERC721Deployer extends GasRouterDeployer< } router(contracts: HyperlaneContracts) { - return contracts.router; - } - - async deployContracts(chain: ChainName, config: HypERC721Config) { - let router: HypERC721 | HypERC721Collateral; - if (isCollateralConfig(config)) { - router = await this.deployCollateral(chain, config); - } else if (isSyntheticConfig(config)) { - router = await this.deploySynthetic(chain, config); - } else { - throw new Error('Invalid ERC721 token router config'); - } - return { router }; - } - - async buildTokenMetadata( - configMap: ChainMap, - ): Promise> { - let tokenMetadata: TokenMetadata | undefined; - - for (const [chain, config] of Object.entries(configMap)) { - if (isCollateralConfig(config)) { - const collateralMetadata = await HypERC721Deployer.fetchMetadata( - this.multiProvider.getProvider(chain), - config, - ); - tokenMetadata = { - ...collateralMetadata, - totalSupply: 0, - }; - } else if (isTokenMetadata(config)) { - tokenMetadata = config; - } - } - - if (!isTokenMetadata(tokenMetadata)) { - throw new Error('Invalid ERC721 token metadata'); - } - - return objMap(configMap, () => (tokenMetadata!)); - } - - buildGasOverhead(configMap: ChainMap): ChainMap { - return objMap(configMap, (_, config) => ({ - gas: HypERC721Deployer.gasOverheadDefault(config), - })); - } - - async deploy(configMap: ChainMap) { - const tokenMetadata = await this.buildTokenMetadata(configMap); - const gasOverhead = this.buildGasOverhead(configMap); - const mergedConfig = objMap( - configMap, - (chain, config) => { - return { - ...tokenMetadata[chain], - ...gasOverhead[chain], - ...config, - }; - }, - ) as ChainMap; - - return super.deploy(mergedConfig); + return Object.values(contracts)[0]; } } diff --git a/src/index.ts b/src/index.ts index e446383..5be1530 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,10 +1,7 @@ export { HypERC20App, HypERC721App } from './app'; export { CollateralConfig, - HypERC20CollateralConfig, - HypERC20Config, - HypERC721CollateralConfig, - HypERC721Config, + TokenRouterConfig, isCollateralConfig, isUriConfig, SyntheticConfig, diff --git a/test/erc20.test.ts b/test/erc20.test.ts index c347f82..0e1fb3b 100644 --- a/test/erc20.test.ts +++ b/test/erc20.test.ts @@ -27,7 +27,7 @@ import { ERC20__factory, HypERC20, HypERC20Collateral, - HypNative, + HypNativeCollateral, } from '../src/types'; const localChain = Chains.test1; @@ -44,20 +44,24 @@ const tokenMetadata = { totalSupply, }; +let index = 0; for (const variant of [ TokenType.synthetic, TokenType.collateral, - TokenType.native, + TokenType.collateral ]) { - describe(`HypERC20${variant}`, async () => { + const isNative = index === 2; + index += 1; + + describe(`Hyp${isNative ? 'Native' : 'ERC20'}${variant}`, async () => { let owner: SignerWithAddress; let recipient: SignerWithAddress; let core: TestCoreApp; let deployer: HypERC20Deployer; let contracts: HyperlaneContractsMap; let localTokenConfig: TokenConfig; - let local: HypERC20 | HypERC20Collateral | HypNative; - let remote: HypERC20; + let local: HypERC20 | HypERC20Collateral | HypNativeCollateral; + let remote: HypERC20 | HypERC20Collateral | HypNativeCollateral; let interchainGasPayment: BigNumber; beforeEach(async () => { @@ -79,19 +83,21 @@ for (const variant of [ let erc20: ERC20 | undefined; if (variant === TokenType.collateral) { - erc20 = await new ERC20Test__factory(owner).deploy( - tokenMetadata.name, - tokenMetadata.symbol, - tokenMetadata.totalSupply, - ); - localTokenConfig = { - type: variant, - token: erc20.address, - }; - } else if (variant === TokenType.native) { - localTokenConfig = { - type: variant, - }; + if (isNative) { + localTokenConfig = { + type: variant, + }; + } else { + erc20 = await new ERC20Test__factory(owner).deploy( + tokenMetadata.name, + tokenMetadata.symbol, + tokenMetadata.totalSupply, + ); + localTokenConfig = { + type: variant, + token: erc20.address, + }; + } } else if (variant === TokenType.synthetic) { localTokenConfig = { type: variant, ...tokenMetadata }; } @@ -106,25 +112,25 @@ for (const variant of [ deployer = new HypERC20Deployer(multiProvider); contracts = await deployer.deploy(config); - local = contracts[localChain].router; + local = deployer.router(contracts[localChain]); interchainGasPayment = await local.quoteGasPayment(remoteDomain); - - if (variant === TokenType.native) { - interchainGasPayment = interchainGasPayment.add(amount); - } - + if (variant === TokenType.collateral) { - await erc20!.approve(local.address, amount); + if (isNative) { + interchainGasPayment = interchainGasPayment.add(amount); + } else { + await erc20!.approve(local.address, amount); + } } - remote = contracts[remoteChain].router as HypERC20; + remote = deployer.router(contracts[remoteChain]); }); it('should not be initializable again', async () => { const initializeTx = - variant === TokenType.collateral || variant === TokenType.native - ? (local as HypERC20Collateral).initialize( + variant === TokenType.collateral + ? (local as HypERC20Collateral | HypNativeCollateral).initialize( ethers.constants.AddressZero, ethers.constants.AddressZero, ) @@ -161,18 +167,20 @@ for (const variant of [ const localRaw = local.connect(ethers.provider); const mailboxAddress = core.contractsMap[localChain].mailbox.address; if (variant === TokenType.collateral) { - const tokenAddress = await (local as HypERC20Collateral).wrappedToken(); - const token = ERC20__factory.connect(tokenAddress, owner); - await token.transfer(local.address, totalSupply); - } else if (variant === TokenType.native) { - const remoteDomain = core.multiProvider.getDomainId(remoteChain); - // deposit amount - await local.transferRemote( - remoteDomain, - utils.addressToBytes32(remote.address), - amount, - { value: interchainGasPayment }, - ); + if (isNative) { + const remoteDomain = core.multiProvider.getDomainId(remoteChain); + // deposit amount + await local.transferRemote( + remoteDomain, + utils.addressToBytes32(remote.address), + amount, + { value: interchainGasPayment }, + ); + } else { + const tokenAddress = await (local as HypERC20Collateral).wrappedToken(); + const token = ERC20__factory.connect(tokenAddress, owner); + await token.transfer(local.address, totalSupply); + } } const message = `${utils.addressToBytes32( recipient.address, @@ -204,7 +212,7 @@ for (const variant of [ let expectedLocal = localOwner.sub(amount); await expectBalance(local, recipient, localRecipient); - if (variant === TokenType.native) { + if (isNative) { // account for tx fees, rewards, etc. expectedLocal = await local.balanceOf(owner.address); } @@ -215,7 +223,7 @@ for (const variant of [ await core.processMessages(); await expectBalance(local, recipient, localRecipient); - if (variant === TokenType.native) { + if (isNative) { // account for tx fees, rewards, etc. expectedLocal = await local.balanceOf(owner.address); } @@ -244,14 +252,15 @@ for (const variant of [ case TokenType.synthetic: return 'ERC20: burn amount exceeds balance'; case TokenType.collateral: - return 'ERC20: insufficient allowance'; - case TokenType.native: - return 'Native: amount exceeds msg.value'; + if (isNative) { + return 'Native: amount exceeds msg.value'; + } else { + return 'ERC20: insufficient allowance'; + } } return ''; }; - const value = - variant === TokenType.native ? amount - 1 : interchainGasPayment; + const value = isNative ? amount - 1 : interchainGasPayment; await expect( local .connect(recipient) @@ -283,7 +292,7 @@ for (const variant of [ } const expectBalance = async ( - token: HypERC20 | HypERC20Collateral | ERC20 | HypNative, + token: HypERC20 | HypERC20Collateral | ERC20 | HypNativeCollateral, signer: SignerWithAddress, balance: BigNumberish, ) => { diff --git a/test/erc721.test.ts b/test/erc721.test.ts index acd004e..d79132c 100644 --- a/test/erc721.test.ts +++ b/test/erc721.test.ts @@ -114,7 +114,7 @@ for (const withCollateral of [true, false]) { deployer = new HypERC721Deployer(multiProvider); contracts = await deployer.deploy(configWithTokenInfo); - local = contracts[localChain].router; + local = deployer.router(contracts[localChain]); if (withCollateral) { // approve wrapper to transfer tokens await erc721!.approve(local.address, tokenId); @@ -124,7 +124,7 @@ for (const withCollateral of [true, false]) { } interchainGasPayment = await local.quoteGasPayment(remoteDomain); - remote = contracts[remoteChain].router; + remote = deployer.router(contracts[remoteChain]); }); it('should not be initializable again', async () => {