Skip to content

Commit

Permalink
fix(contracts): owner vault metadata compatibility (#4566)
Browse files Browse the repository at this point in the history
### 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 chainlight-io/2024-08-hyperlane#9

### Backward compatibility

No

### Testing

Unit test
  • Loading branch information
aroralanuk authored Oct 22, 2024
1 parent c9bd7c3 commit 72c23c0
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changeset/sweet-humans-argue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hyperlane-xyz/core': minor
---

Added PRECISION and rateUpdateNonce to ensure compatibility of HypERC4626
17 changes: 16 additions & 1 deletion solidity/contracts/token/extensions/HypERC4626.sol
Original file line number Diff line number Diff line change
@@ -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
Expand Down
19 changes: 18 additions & 1 deletion solidity/contracts/token/extensions/HypERC4626Collateral.sol
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand Down
27 changes: 24 additions & 3 deletions solidity/contracts/token/extensions/HypERC4626OwnerCollateral.sol
Original file line number Diff line number Diff line change
@@ -1,19 +1,37 @@
// 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
*/
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);

Expand All @@ -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);
}

/**
Expand Down
47 changes: 47 additions & 0 deletions solidity/test/token/HypERC20CollateralVaultDeposit.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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);
Expand All @@ -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);
}
}

0 comments on commit 72c23c0

Please sign in to comment.