Gas router (#30)

* Updates to use GasRouter and new IGP

* Update deployer and app to use gas router

* Update from mono 1.1.4

* Address more pr comments

* Warn on balance failures

---------

Co-authored-by: J M Rossy <jm.rossy@gmail.com>
pull/2435/head
Yorke Rhodes 2 years ago committed by GitHub
parent 0c63ab1731
commit 6d056dfd96
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      contracts/HypERC20.sol
  2. 8
      contracts/HypERC20Collateral.sol
  3. 6
      contracts/HypERC721.sol
  4. 16
      contracts/HypERC721Collateral.sol
  5. 10
      contracts/extensions/HypERC721URICollateral.sol
  6. 6
      contracts/extensions/HypERC721URIStorage.sol
  7. 22
      contracts/libs/TokenRouter.sol
  8. 8
      package.json
  9. 2
      scripts/deploy.ts
  10. 89
      src/app.ts
  11. 18
      src/config.ts
  12. 67
      src/deploy.ts
  13. 40
      test/erc20.test.ts
  14. 50
      test/erc721.test.ts
  15. 51
      yarn.lock

@ -11,12 +11,6 @@ import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/
* @dev Supply on each chain is not constant but the aggregate supply across all chains is.
*/
contract HypERC20 is ERC20Upgradeable, TokenRouter {
/**
* @notice Constructor
* @param gasAmount Amount of destination gas to be paid for processing
*/
constructor(uint256 gasAmount) TokenRouter(gasAmount) {}
/**
* @notice Initializes the Hyperlane router, ERC20 metadata, and mints initial supply to deployer.
* @param _mailbox The address of the mailbox contract.

@ -2,6 +2,7 @@
pragma solidity >=0.8.0;
import {TokenRouter} from "./libs/TokenRouter.sol";
import {Message} from "./libs/Message.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
@ -15,9 +16,8 @@ contract HypERC20Collateral is TokenRouter {
/**
* @notice Constructor
* @param erc20 Address of the token to keep as collateral
* @param gasAmount Amount of destination gas to be paid for processing
*/
constructor(address erc20, uint256 gasAmount) TokenRouter(gasAmount) {
constructor(address erc20) {
wrappedToken = IERC20(erc20);
}
@ -36,6 +36,10 @@ contract HypERC20Collateral is TokenRouter {
);
}
function balanceOf(address _account) external view returns (uint256) {
return wrappedToken.balanceOf(_account);
}
/**
* @dev Transfers `_amount` of `wrappedToken` from `msg.sender` to this contract.
* @inheritdoc TokenRouter

@ -10,12 +10,6 @@ import {ERC721EnumerableUpgradeable} from "@openzeppelin/contracts-upgradeable/t
* @author Abacus Works
*/
contract HypERC721 is ERC721EnumerableUpgradeable, TokenRouter {
/**
* @notice Constructor
* @param gasAmount Amount of destination gas to be paid for processing
*/
constructor(uint256 gasAmount) TokenRouter(gasAmount) {}
/**
* @notice Initializes the Hyperlane router, ERC721 metadata, and mints initial supply to deployer.
* @param _mailbox The address of the mailbox contract.

@ -2,6 +2,7 @@
pragma solidity >=0.8.0;
import {TokenRouter} from "./libs/TokenRouter.sol";
import {Message} from "./libs/Message.sol";
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
@ -10,15 +11,18 @@ import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
* @author Abacus Works
*/
contract HypERC721Collateral is TokenRouter {
address public immutable wrappedToken;
IERC721 public immutable wrappedToken;
/**
* @notice Constructor
* @param erc721 Address of the token to keep as collateral
* @param gasAmount Amount of destination gas to be paid for processing
*/
constructor(address erc721, uint256 gasAmount) TokenRouter(gasAmount) {
wrappedToken = erc721;
constructor(address erc721) {
wrappedToken = IERC721(erc721);
}
function ownerOf(uint256 _tokenId) external view returns (address) {
return IERC721(wrappedToken).ownerOf(_tokenId);
}
/**
@ -46,7 +50,7 @@ contract HypERC721Collateral is TokenRouter {
override
returns (bytes memory)
{
IERC721(wrappedToken).transferFrom(msg.sender, address(this), _tokenId);
wrappedToken.transferFrom(msg.sender, address(this), _tokenId);
return bytes(""); // no metadata
}
@ -59,6 +63,6 @@ contract HypERC721Collateral is TokenRouter {
uint256 _tokenId,
bytes calldata // no metadata
) internal override {
IERC721(wrappedToken).transferFrom(address(this), _recipient, _tokenId);
wrappedToken.transferFrom(address(this), _recipient, _tokenId);
}
}

@ -10,9 +10,7 @@ import {IERC721MetadataUpgradeable} from "@openzeppelin/contracts-upgradeable/to
* @author Abacus Works
*/
contract HypERC721URICollateral is HypERC721Collateral {
constructor(address erc721, uint256 gasAmount)
HypERC721Collateral(erc721, gasAmount)
{}
constructor(address erc721) HypERC721Collateral(erc721) {}
/**
* @dev Transfers `_tokenId` of `wrappedToken` from `msg.sender` to this contract.
@ -26,6 +24,10 @@ contract HypERC721URICollateral is HypERC721Collateral {
{
HypERC721Collateral._transferFromSender(_tokenId);
return
bytes(IERC721MetadataUpgradeable(wrappedToken).tokenURI(_tokenId));
bytes(
IERC721MetadataUpgradeable(address(wrappedToken)).tokenURI(
_tokenId
)
);
}
}

@ -12,12 +12,6 @@ import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC72
* @author Abacus Works
*/
contract HypERC721URIStorage is HypERC721, ERC721URIStorageUpgradeable {
/**
* @notice Constructor
* @param gasAmount Amount of destination gas to be paid for processing
*/
constructor(uint256 gasAmount) HypERC721(gasAmount) {}
/**
* @return _tokenURI The URI of `_tokenId`.
* @inheritdoc HypERC721

@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity >=0.8.0;
import {Router} from "@hyperlane-xyz/core/contracts/Router.sol";
import {GasRouter} from "@hyperlane-xyz/core/contracts/GasRouter.sol";
import {TypeCasts} from "@hyperlane-xyz/core/contracts/libs/TypeCasts.sol";
import {Message} from "./Message.sol";
@ -9,15 +9,10 @@ import {Message} from "./Message.sol";
* @title Hyperlane Token Router that extends Router with abstract token (ERC20/ERC721) remote transfer functionality.
* @author Abacus Works
*/
abstract contract TokenRouter is Router {
abstract contract TokenRouter is GasRouter {
using TypeCasts for bytes32;
using Message for bytes;
/**
* @notice Gas amount to use for destination chain processing, should be overriden by implementors
*/
uint256 internal immutable gasAmount;
/**
* @dev Emitted on `transferRemote` when a transfer message is dispatched.
* @param destination The identifier of the destination chain.
@ -42,10 +37,6 @@ abstract contract TokenRouter is Router {
uint256 amount
);
constructor(uint256 _gasAmount) {
gasAmount = _gasAmount;
}
/**
* @notice Transfers `_amountOrId` token to `_recipient` on `_destination` domain.
* @dev Delegates transfer logic to `_transferFromSender` implementation.
@ -58,14 +49,13 @@ abstract contract TokenRouter is Router {
uint32 _destination,
bytes32 _recipient,
uint256 _amountOrId
) external payable {
) external payable returns (bytes32 messageId) {
bytes memory metadata = _transferFromSender(_amountOrId);
_dispatchWithGas(
messageId = _dispatchWithGas(
_destination,
Message.format(_recipient, _amountOrId, metadata),
gasAmount,
msg.value,
msg.sender
msg.value, // interchain gas payment
msg.sender // refund address
);
emit SentTransferRemote(_destination, _recipient, _amountOrId);
}

@ -1,11 +1,11 @@
{
"name": "@hyperlane-xyz/hyperlane-token",
"description": "A template for interchain ERC20 and ERC721 tokens using Hyperlane",
"version": "1.1.3",
"version": "1.1.4",
"dependencies": {
"@hyperlane-xyz/core": "1.1.3",
"@hyperlane-xyz/sdk": "1.1.3",
"@hyperlane-xyz/utils": "1.1.3",
"@hyperlane-xyz/core": "1.1.4",
"@hyperlane-xyz/sdk": "1.1.4",
"@hyperlane-xyz/utils": "1.1.4",
"@openzeppelin/contracts-upgradeable": "^4.8.0",
"ethers": "^5.7.2"
},

@ -66,7 +66,7 @@ async function deployWarpRoute() {
);
}
let multiProviderConfig: ChainMap<any, IChainConnection> = {};
const multiProviderConfig: ChainMap<any, IChainConnection> = {};
for (const chain of targetChains) {
if (chainConfigs && chainConfigs[chain]) {
// Use custom config

@ -1,43 +1,76 @@
import { BigNumberish } from 'ethers';
import {
ChainName,
HyperlaneApp,
objMap,
promiseObjAll,
GasRouterApp,
RouterContracts,
} from '@hyperlane-xyz/sdk';
import { types } from '@hyperlane-xyz/utils';
import { HypERC20Contracts, HypERC721Contracts } from './contracts';
import { TokenRouter } from './types';
export class HypERC20App<Chain extends ChainName> extends HyperlaneApp<
class HyperlaneTokenApp<
Contracts extends RouterContracts<TokenRouter>,
Chain extends ChainName,
> extends GasRouterApp<Contracts, Chain> {
async transfer<Origin extends Chain>(
origin: Origin,
destination: Exclude<Chain, Origin>,
recipient: types.Address,
amountOrId: BigNumberish,
) {
const originRouter = this.getContracts(origin).router;
const destinationChainConnection = this.multiProvider.getChainConnection(destination);
const destinationNetwork = await destinationChainConnection.provider.getNetwork();
const gasPayment = await originRouter.quoteGasPayment(destinationNetwork.chainId);
const chainConnection = this.multiProvider.getChainConnection(origin);
return chainConnection.handleTx(
originRouter.transferRemote(destinationNetwork.chainId, recipient, amountOrId, {
value: gasPayment,
}),
);
}
}
export class HypERC20App<Chain extends ChainName> extends HyperlaneTokenApp<
HypERC20Contracts,
Chain
> {
getSecurityModules = () =>
promiseObjAll(
objMap(this.contractsMap, (_, contracts) =>
contracts.router.interchainSecurityModule(),
),
);
getOwners = () =>
promiseObjAll(
objMap(this.contractsMap, (_, contracts) => contracts.router.owner()),
);
async transfer<Origin extends Chain>(
origin: Origin,
destination: Exclude<Chain, Origin>,
recipient: types.Address,
amount: BigNumberish,
) {
const originRouter = this.getContracts(origin).router;
const chainConnection = this.multiProvider.getChainConnection(origin);
const signerAddress = await chainConnection.signer!.getAddress();
const balance = await originRouter.balanceOf(signerAddress);
if (balance.lt(amount))
console.warn(
`Signer ${signerAddress} has insufficient balance ${balance}, needs ${amount} on ${origin}`,
);
return super.transfer(origin, destination, recipient, amount);
}
}
// TODO: dedupe?
export class HypERC721App<Chain extends ChainName> extends HyperlaneApp<
export class HypERC721App<Chain extends ChainName> extends HyperlaneTokenApp<
HypERC721Contracts,
Chain
> {
getSecurityModules = () =>
promiseObjAll(
objMap(this.contractsMap, (_, contracts) =>
contracts.router.interchainSecurityModule(),
),
);
getOwners = () =>
promiseObjAll(
objMap(this.contractsMap, (_, contracts) => contracts.router.owner()),
);
async transfer<Origin extends Chain>(
origin: Origin,
destination: Exclude<Chain, Origin>,
recipient: types.Address,
tokenId: BigNumberish,
) {
const originRouter = this.getContracts(origin).router;
const chainConnection = this.multiProvider.getChainConnection(origin);
const signerAddress = await chainConnection.signer!.getAddress();
const owner = await originRouter.ownerOf(tokenId);
if (signerAddress != owner)
console.warn(`Signer ${signerAddress} not owner of token ${tokenId} on ${origin}`);
return super.transfer(origin, destination, recipient, tokenId);
}
}

@ -1,6 +1,6 @@
import { ethers } from 'ethers';
import { RouterConfig } from '@hyperlane-xyz/sdk';
import { GasRouterConfig } from '@hyperlane-xyz/sdk';
export enum TokenType {
synthetic = 'synthetic',
@ -14,31 +14,29 @@ export type SyntheticConfig = {
name: string;
symbol: string;
totalSupply: ethers.BigNumberish;
gasAmount?: ethers.BigNumberish;
};
export type CollateralConfig = {
type: TokenType.collateral | TokenType.collateralUri;
token: string;
gasAmount?: ethers.BigNumberish;
};
export type TokenConfig = SyntheticConfig | CollateralConfig;
export const isCollateralConfig = (
config: RouterConfig & TokenConfig,
): config is RouterConfig & CollateralConfig => {
config: TokenConfig,
): config is CollateralConfig => {
return (
config.type === TokenType.collateral ||
config.type === TokenType.collateralUri
);
};
export const isUriConfig = (config: RouterConfig & TokenConfig) =>
export const isUriConfig = (config: TokenConfig) =>
config.type === TokenType.syntheticUri ||
config.type === TokenType.collateralUri;
export type HypERC20Config = RouterConfig & TokenConfig;
export type HypERC20CollateralConfig = RouterConfig & CollateralConfig;
export type HypERC20Config = GasRouterConfig & TokenConfig;
export type HypERC20CollateralConfig = GasRouterConfig & CollateralConfig;
export type HypERC721Config = RouterConfig & TokenConfig;
export type HypERC721CollateralConfig = RouterConfig & CollateralConfig;
export type HypERC721Config = GasRouterConfig & TokenConfig;
export type HypERC721CollateralConfig = GasRouterConfig & CollateralConfig;

@ -1,7 +1,11 @@
import {
ChainMap,
ChainName,
HyperlaneRouterDeployer,
GasRouterDeployer,
MultiProvider,
objMap
} from '@hyperlane-xyz/sdk';
import { DeployerOptions } from '@hyperlane-xyz/sdk/dist/deploy/HyperlaneDeployer';
import {
HypERC20CollateralConfig,
@ -10,6 +14,7 @@ import {
isCollateralConfig,
HypERC721CollateralConfig,
isUriConfig,
TokenConfig,
} from './config';
import {
HypERC20Contracts,
@ -17,16 +22,53 @@ import {
} from './contracts';
import { HypERC20Collateral__factory, HypERC20__factory, HypERC721Collateral__factory, HypERC721URICollateral__factory, HypERC721URIStorage__factory, HypERC721__factory } from './types';
// Default value to use for TokenRouter.gasAmount
const DEFAULT_IGP_GAS_AMOUNT = 30000;
enum TokenType {
erc20 = 'erc20',
erc721 = 'erc721',
}
const gasDefaults = (config: TokenConfig, tokenType: TokenType) => {
switch (tokenType) {
case TokenType.erc721:
switch (config.type) {
case 'synthetic':
return 156000;
case 'syntheticUri':
return 160000;
case 'collateral':
case 'collateralUri':
default:
return 77000;
}
default:
case TokenType.erc20:
switch (config.type) {
case 'synthetic':
return 64000;
case 'collateral':
default:
return 68000;
}
}
}
type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;
export class HypERC20Deployer<
Chain extends ChainName // inferred from configured chains passed to constructor
> extends HyperlaneRouterDeployer<
> extends GasRouterDeployer<
Chain,
HypERC20Config | HypERC20CollateralConfig,
HypERC20Contracts,
any // RouterFactories doesn't work well when router has multiple types
> {
constructor(multiProvider: MultiProvider<Chain>, configMap: ChainMap<Chain, Optional<HypERC20Config | HypERC20CollateralConfig, 'gas'>>, factories: any, options?: DeployerOptions) {
super(multiProvider, objMap(configMap, (_, config): HypERC20Config | HypERC20CollateralConfig => ({
...config,
gas: config.gas ?? gasDefaults(config as any, TokenType.erc20)
} as HypERC20Config | HypERC20CollateralConfig)), factories, options);
}
async deployContracts(
chain: Chain,
config: HypERC20Config | HypERC20CollateralConfig,
@ -37,7 +79,7 @@ export class HypERC20Deployer<
chain,
new HypERC20Collateral__factory(),
'HypERC20Collateral',
[config.token, config.gasAmount || DEFAULT_IGP_GAS_AMOUNT],
[config.token],
);
await connection.handleTx(
router.initialize(
@ -51,7 +93,7 @@ export class HypERC20Deployer<
chain,
new HypERC20__factory(),
'HypERC20',
[config.gasAmount || DEFAULT_IGP_GAS_AMOUNT],
[],
);
await connection.handleTx(router.initialize(
config.mailbox,
@ -68,12 +110,19 @@ export class HypERC20Deployer<
// TODO: dedupe?
export class HypERC721Deployer<
Chain extends ChainName
> extends HyperlaneRouterDeployer<
> extends GasRouterDeployer<
Chain,
HypERC721Config | HypERC721CollateralConfig,
HypERC721Contracts,
any
> {
constructor(multiProvider: MultiProvider<Chain>, configMap: ChainMap<Chain, Optional<HypERC721Config | HypERC721CollateralConfig, 'gas'>>, factories: any, options?: DeployerOptions) {
super(multiProvider, objMap(configMap, (_, config): HypERC721Config | HypERC721CollateralConfig => ({
...config,
gas: config.gas ?? gasDefaults(config as any, TokenType.erc721)
} as HypERC721Config | HypERC721CollateralConfig)), factories, options);
}
async deployContracts(
chain: Chain,
config: HypERC721Config | HypERC721CollateralConfig,
@ -84,7 +133,7 @@ export class HypERC721Deployer<
chain,
isUriConfig(config) ? new HypERC721URICollateral__factory() : new HypERC721Collateral__factory(),
`HypERC721${isUriConfig(config) ? 'URI' : ''}Collateral`,
[config.token, config.gasAmount || DEFAULT_IGP_GAS_AMOUNT],
[config.token],
);
await connection.handleTx(
router.initialize(
@ -98,7 +147,7 @@ export class HypERC721Deployer<
chain,
isUriConfig(config) ? new HypERC721URIStorage__factory() : new HypERC721__factory(),
`HypERC721${isUriConfig(config) ? 'URIStorage' : ''}`,
[config.gasAmount || DEFAULT_IGP_GAS_AMOUNT],
[],
);
await connection.handleTx(router.initialize(
config.mailbox,

@ -1,6 +1,7 @@
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers';
import '@nomiclabs/hardhat-waffle';
import { expect } from 'chai';
import { BigNumber } from 'ethers';
import { ethers } from 'hardhat';
import {
@ -70,6 +71,7 @@ for (const withCollateral of [true, false]) {
...coreConfig[key],
...tokenConfig,
owner: owner.address,
gas: 63264,
}));
let erc20: ERC20 | undefined;
@ -83,6 +85,7 @@ for (const withCollateral of [true, false]) {
...configWithTokenInfo.test1,
type: TokenType.collateral,
token: erc20.address,
gas: 67615,
};
}
@ -133,12 +136,43 @@ for (const withCollateral of [true, false]) {
});
}
it('benchmark handle gas overhead', async () => {
const localRaw = local.connect(ethers.provider);
const mailboxAddress =
core.contractsMap[localChain].mailbox.contract.address;
if (withCollateral) {
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,
)}${BigNumber.from(totalSupply)
.toHexString()
.slice(2)
.padStart(64, '0')}`;
const gas = await localRaw.estimateGas.handle(
remoteDomain,
utils.addressToBytes32(remote.address),
message,
{ from: mailboxAddress },
);
console.log(gas);
});
it('should allow for remote transfers', async () => {
const interchainGasPaymaster =
core.contractsMap[localChain].interchainGasPaymaster.contract;
const gas = await local.destinationGas(remoteDomain);
const interchainGasPayment = await interchainGasPaymaster.quoteGasPayment(
remoteDomain,
gas,
);
await local.transferRemote(
remoteDomain,
utils.addressToBytes32(recipient.address),
amount,
{ value: 1 },
{ value: interchainGasPayment },
);
await expectBalance(local, recipient, 0);
@ -180,7 +214,7 @@ for (const withCollateral of [true, false]) {
remoteDomain,
utils.addressToBytes32(recipient.address),
amount,
{ value: 1 },
{ value: await local.destinationGas(remoteDomain) },
),
).to.be.revertedWith(revertReason);
});
@ -191,7 +225,7 @@ for (const withCollateral of [true, false]) {
remoteDomain,
utils.addressToBytes32(recipient.address),
amount,
{ value: 1 },
{ value: await local.destinationGas(remoteDomain) },
),
)
.to.emit(local, 'SentTransferRemote')

@ -1,6 +1,7 @@
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers';
import '@nomiclabs/hardhat-waffle';
import { expect } from 'chai';
import { BigNumber } from 'ethers';
import { ethers } from 'hardhat';
import {
@ -42,6 +43,7 @@ const tokenId2 = 20;
const tokenId3 = 30;
const tokenId4 = 40;
const testInterchainGasPayment = 123456789;
const gas = 67628;
for (const withCollateral of [true, false]) {
for (const withUri of [true, false]) {
@ -56,14 +58,17 @@ for (const withCollateral of [true, false]) {
test1: {
...tokenConfig,
totalSupply,
gas,
},
test2: {
...tokenConfig,
totalSupply: 0,
gas,
},
test3: {
...tokenConfig,
totalSupply: 0,
gas,
},
};
describe(`HypERC721${withUri ? 'URI' : ''}${
@ -92,6 +97,7 @@ for (const withCollateral of [true, false]) {
...coreConfig[key],
...configMap[key],
owner: owner.address,
gas,
}));
let erc721: ERC721 | undefined;
@ -182,7 +188,7 @@ for (const withCollateral of [true, false]) {
remoteDomain,
utils.addressToBytes32(recipient.address),
invalidTokenId,
{ value: 1 },
{ value: gas },
),
).to.be.revertedWith('ERC721: invalid token ID');
});
@ -192,7 +198,7 @@ for (const withCollateral of [true, false]) {
remoteDomain,
utils.addressToBytes32(recipient.address),
tokenId2,
{ value: 1 },
{ value: gas },
);
await expectBalance(local, recipient, 0);
@ -217,7 +223,7 @@ for (const withCollateral of [true, false]) {
remoteDomain,
utils.addressToBytes32(recipient.address),
tokenId2,
{ value: 1 },
{ value: gas },
);
await expect(remoteUri.tokenURI(tokenId2)).to.be.revertedWith('');
@ -241,11 +247,45 @@ for (const withCollateral of [true, false]) {
remoteDomain,
utils.addressToBytes32(recipient.address),
tokenId2,
{ value: 1 },
{ value: gas },
),
).to.be.revertedWith(revertReason);
});
it('benchmark handle gas overhead', async () => {
const localRaw = local.connect(ethers.provider);
const mailboxAddress =
core.contractsMap[localChain].mailbox.contract.address;
let tokenIdToUse: number;
if (withCollateral) {
const tokenAddress = await (
local as HypERC721Collateral
).wrappedToken();
const token = ERC721__factory.connect(tokenAddress, owner);
await token.transferFrom(owner.address, local.address, tokenId);
tokenIdToUse = tokenId;
} else {
tokenIdToUse = totalSupply + 1;
}
const message = `${utils.addressToBytes32(
recipient.address,
)}${BigNumber.from(tokenIdToUse)
.toHexString()
.slice(2)
.padStart(64, '0')}`;
try {
const gas = await localRaw.estimateGas.handle(
remoteDomain,
utils.addressToBytes32(remote.address),
message,
{ from: mailboxAddress },
);
console.log(gas);
} catch (e) {
console.log('FAILED');
}
});
it('allows interchain gas payment for remote transfers', async () => {
const interchainGasPaymaster =
core.contractsMap[localChain].interchainGasPaymaster.contract;
@ -267,7 +307,7 @@ for (const withCollateral of [true, false]) {
remoteDomain,
utils.addressToBytes32(recipient.address),
tokenId4,
{ value: 1 },
{ value: gas },
),
)
.to.emit(local, 'SentTransferRemote')

@ -1229,14 +1229,14 @@ __metadata:
languageName: node
linkType: hard
"@hyperlane-xyz/core@npm:1.1.3":
version: 1.1.3
resolution: "@hyperlane-xyz/core@npm:1.1.3"
"@hyperlane-xyz/core@npm:1.1.4":
version: 1.1.4
resolution: "@hyperlane-xyz/core@npm:1.1.4"
dependencies:
"@hyperlane-xyz/utils": 1.1.3
"@hyperlane-xyz/utils": 1.1.4
"@openzeppelin/contracts": ^4.8.0
"@openzeppelin/contracts-upgradeable": ^4.8.0
checksum: 6872fcdac9add5ac55aad891a7c9fbd7709e30ad06ca6d063bf8b4752533d143cd8418c78218df4073a98b06e8ec4fc8b185444ac62e558498da09ef47efbe19
checksum: 6e1e70ce7dc23c69ec2f3443cac5956241db834d745fcec6d613ac323004f9e9c279e68182b9995fb3eca572a0a99600de493bc6b7d8e1dc248203aaeaec2251
languageName: node
linkType: hard
@ -1244,9 +1244,9 @@ __metadata:
version: 0.0.0-use.local
resolution: "@hyperlane-xyz/hyperlane-token@workspace:."
dependencies:
"@hyperlane-xyz/core": 1.1.3
"@hyperlane-xyz/sdk": 1.1.3
"@hyperlane-xyz/utils": 1.1.3
"@hyperlane-xyz/core": 1.1.4
"@hyperlane-xyz/sdk": 1.1.4
"@hyperlane-xyz/utils": 1.1.4
"@nomiclabs/hardhat-ethers": ^2.2.1
"@nomiclabs/hardhat-waffle": ^2.0.3
"@openzeppelin/contracts-upgradeable": ^4.8.0
@ -1274,28 +1274,28 @@ __metadata:
languageName: unknown
linkType: soft
"@hyperlane-xyz/sdk@npm:1.1.3":
version: 1.1.3
resolution: "@hyperlane-xyz/sdk@npm:1.1.3"
"@hyperlane-xyz/sdk@npm:1.1.4":
version: 1.1.4
resolution: "@hyperlane-xyz/sdk@npm:1.1.4"
dependencies:
"@hyperlane-xyz/celo-ethers-provider": ^0.1.1
"@hyperlane-xyz/core": 1.1.3
"@hyperlane-xyz/utils": 1.1.3
"@wagmi/chains": ^0.1.3
"@hyperlane-xyz/core": 1.1.4
"@hyperlane-xyz/utils": 1.1.4
"@wagmi/chains": ^0.2.6
coingecko-api: ^1.0.10
cross-fetch: ^3.1.5
debug: ^4.3.4
ethers: ^5.7.2
checksum: 20dabd0acc33d737c80af432605608e6cea1aaf6fa6db9839687a5427324e0044dcdf29b0f26bc2ba732eb6faf44f3c1ca226a3387c9e608ab1f25c6ec24332d
checksum: 600d81648cdbdad2be4200bd772d49128b9bcd5de10d1f811008291ed268610a0bb1cac8061dfa30b5040dc20c7b8919b39ed206d7993f63c65abf3df663c125
languageName: node
linkType: hard
"@hyperlane-xyz/utils@npm:1.1.3":
version: 1.1.3
resolution: "@hyperlane-xyz/utils@npm:1.1.3"
"@hyperlane-xyz/utils@npm:1.1.4":
version: 1.1.4
resolution: "@hyperlane-xyz/utils@npm:1.1.4"
dependencies:
ethers: ^5.7.2
checksum: afe6847b0810b85ba1ddbe5c0e28718d86e1890220edf7ab3b629e1a8820c93405ec7265da6ce1b16d32b31947f8b4b912b7756cfd4f14f674f4dc48c4042f09
checksum: 9860b34cea341e2b49eb341cb2bab57d33b8e818a577f7d50daa3417c7d6dc01311d99cb13e1232d84b0c3551cc4476734e1b9bc0083b4cb1e6c441c3a0f4798
languageName: node
linkType: hard
@ -2159,10 +2159,15 @@ __metadata:
languageName: node
linkType: hard
"@wagmi/chains@npm:^0.1.3":
version: 0.1.5
resolution: "@wagmi/chains@npm:0.1.5"
checksum: 17577eaecb94450b9cbc9c16fa7c95416a79437cebbcd4cf16515098d9bb562d227c55922f5fddd493de4747f4131977c0eeb82197beafce700af42c16740ec1
"@wagmi/chains@npm:^0.2.6":
version: 0.2.8
resolution: "@wagmi/chains@npm:0.2.8"
peerDependencies:
typescript: ">=4.9.4"
peerDependenciesMeta:
typescript:
optional: true
checksum: f68b16fa0620fe4162ad3412735a5c239f59c9a7b15e900a217ff7403d74c8a262fdcd77ab0b37cbc747e78c2c197272d9340d9ef091525d5e335e91905d3def
languageName: node
linkType: hard

Loading…
Cancel
Save