fix(contracts): owner vault metadata compatibility (#4566)

### Description

- Added PRECISION and rateUpdateNonce to ensure compatibility of
HypERC4626 (even though this is not a useful warp route bc exchangeRate
will stay at 1e10)

### Drive-by changes

None

### Related issues

- closes https://github.com/chainlight-io/2024-08-hyperlane/issues/9

### Backward compatibility

No

### Testing

Unit test
pull/4724/head
Kunal Arora 1 month ago committed by GitHub
parent c9bd7c3c52
commit 72c23c0d63
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 5
      .changeset/sweet-humans-argue.md
  2. 17
      solidity/contracts/token/extensions/HypERC4626.sol
  3. 19
      solidity/contracts/token/extensions/HypERC4626Collateral.sol
  4. 27
      solidity/contracts/token/extensions/HypERC4626OwnerCollateral.sol
  5. 47
      solidity/test/token/HypERC20CollateralVaultDeposit.t.sol

@ -0,0 +1,5 @@
---
'@hyperlane-xyz/core': minor
---
Added PRECISION and rateUpdateNonce to ensure compatibility of HypERC4626

@ -1,13 +1,28 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.0;
/*@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@ HYPERLANE @@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@*/
// ============ Internal Imports ============
import {IXERC20} from "../interfaces/IXERC20.sol";
import {HypERC20} from "../HypERC20.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {Message} from "../../libs/Message.sol";
import {TokenMessage} from "../libs/TokenMessage.sol";
import {TokenRouter} from "../libs/TokenRouter.sol";
// ============ External Imports ============
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
/**
* @title Hyperlane ERC20 Rebasing Token
* @author Abacus Works

@ -1,11 +1,26 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity >=0.8.0;
import "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol";
/*@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@ HYPERLANE @@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@*/
// ============ Internal Imports ============
import {TokenMessage} from "../libs/TokenMessage.sol";
import {HypERC20Collateral} from "../HypERC20Collateral.sol";
import {TypeCasts} from "../../libs/TypeCasts.sol";
// ============ External Imports ============
import "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol";
/**
* @title Hyperlane ERC4626 Token Collateral with deposits collateral to a vault
* @author Abacus Works
@ -17,7 +32,9 @@ contract HypERC4626Collateral is HypERC20Collateral {
// Address of the ERC4626 compatible vault
ERC4626 public immutable vault;
// Precision for the exchange rate
uint256 public constant PRECISION = 1e10;
// Null recipient for rebase transfer
bytes32 public constant NULL_RECIPIENT =
0x0000000000000000000000000000000000000000000000000000000000000001;
// Nonce for the rate update, to ensure sequential updates

@ -1,9 +1,24 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity >=0.8.0;
import "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol";
/*@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@ HYPERLANE @@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@*/
// ============ Internal Imports ============
import {HypERC20Collateral} from "../HypERC20Collateral.sol";
// ============ External Imports ============
import {ERC4626} from "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol";
/**
* @title Hyperlane ERC20 Token Collateral with deposits collateral to a vault, the yield goes to the owner
* @author ltyu
@ -11,9 +26,12 @@ import {HypERC20Collateral} from "../HypERC20Collateral.sol";
contract HypERC4626OwnerCollateral is HypERC20Collateral {
// Address of the ERC4626 compatible vault
ERC4626 public immutable vault;
// standby precision for exchange rate
uint256 public constant PRECISION = 1e10;
// Internal balance of total asset deposited
uint256 public assetDeposited;
// Nonce for the rate update, to ensure sequential updates (not necessary for Owner variant but for compatibility with HypERC4626)
uint32 public rateUpdateNonce;
event ExcessSharesSwept(uint256 amount, uint256 assetsRedeemed);
@ -40,8 +58,11 @@ contract HypERC4626OwnerCollateral is HypERC20Collateral {
function _transferFromSender(
uint256 _amount
) internal override returns (bytes memory metadata) {
metadata = super._transferFromSender(_amount);
super._transferFromSender(_amount);
_depositIntoVault(_amount);
rateUpdateNonce++;
return abi.encode(PRECISION, rateUpdateNonce);
}
/**

@ -16,8 +16,11 @@ pragma solidity ^0.8.13;
import "forge-std/Test.sol";
import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import {HypERC4626} from "../../contracts/token/extensions/HypERC4626.sol";
import {ERC4626Test} from "../../contracts/test/ERC4626/ERC4626Test.sol";
import {TypeCasts} from "../../contracts/libs/TypeCasts.sol";
import {TokenMessage} from "../../contracts/token/libs/TokenMessage.sol";
import {HypTokenTest} from "./HypERC20.t.sol";
import {HypERC4626OwnerCollateral} from "../../contracts/token/extensions/HypERC4626OwnerCollateral.sol";
@ -227,6 +230,20 @@ contract HypERC4626OwnerCollateralTest is HypTokenTest {
);
}
function testERC4626VaultDeposit_TransferFromSender_CorrectMetadata()
public
{
remoteToken = new HypERC4626(18, address(remoteMailbox), ORIGIN);
_enrollRemoteTokenRouter();
vm.prank(ALICE);
primaryToken.approve(address(localToken), TRANSFER_AMT);
_performRemoteTransfer(0, TRANSFER_AMT, 1);
assertEq(HypERC4626(address(remoteToken)).exchangeRate(), 1e10);
assertEq(HypERC4626(address(remoteToken)).previousNonce(), 1);
}
function testBenchmark_overheadGasUsage() public override {
vm.prank(ALICE);
primaryToken.approve(address(localToken), TRANSFER_AMT);
@ -243,4 +260,34 @@ contract HypERC4626OwnerCollateralTest is HypTokenTest {
uint256 gasAfter = gasleft();
console.log("Overhead gas usage: %d", gasBefore - gasAfter);
}
function _performRemoteTransfer(
uint256 _msgValue,
uint256 _amount,
uint32 _nonce
) internal {
vm.prank(ALICE);
localToken.transferRemote{value: _msgValue}(
DESTINATION,
BOB.addressToBytes32(),
_amount
);
vm.expectEmit(true, true, false, true);
emit ReceivedTransferRemote(ORIGIN, BOB.addressToBytes32(), _amount);
bytes memory _tokenMessage = TokenMessage.format(
BOB.addressToBytes32(),
_amount,
abi.encode(uint256(1e10), _nonce)
);
vm.prank(address(remoteMailbox));
remoteToken.handle(
ORIGIN,
address(localToken).addressToBytes32(),
_tokenMessage
);
assertEq(remoteToken.balanceOf(BOB), _amount);
}
}

Loading…
Cancel
Save