Skip to content

Commit

Permalink
Yield-earning Warp Routes with ERC4626 (#3076)
Browse files Browse the repository at this point in the history
### Description
Integrates ERC4626 compatible vaults. This PR assumes that the vault
`asset` is the same as `wrappedToken`
- `_transferFromSender()` deposits into the vault
- `_transferTo()` withdraws from the vault
- `sweep()` redeems excess shares for the vault asset
- Uses internal `assetDeposited` store to keep track of assets
deposited. Used to calculate excess shares to be withdrawn by owner
- Makes minor changes to existing test files to allow new tests to
inherit

### Drive-by changes

<!--
Are there any minor or drive-by changes also included?
-->

### Related issues


- Implements #2450


### Backward compatibility
Yes

### Testing
Manual/Unit Tests

---------

Co-authored-by: Yorke Rhodes <[email protected]>
  • Loading branch information
ltyu and yorhodes committed Mar 22, 2024
1 parent 5cad9a9 commit 0cc0905
Show file tree
Hide file tree
Showing 8 changed files with 358 additions and 3 deletions.
4 changes: 4 additions & 0 deletions solidity/contracts/hooks/libs/AbstractMessageIdAuthHook.sol
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ abstract contract AbstractMessageIdAuthHook is
message.destination() == destinationDomain,
"AbstractMessageIdAuthHook: invalid destination domain"
);
require(
metadata.msgValue(0) < 2 ** 255,
"AbstractMessageIdAuthHook: msgValue must be less than 2 ** 255"
);
bytes memory payload = abi.encodeCall(
AbstractMessageIdAuthorizedIsm.verifyMessageId,
id
Expand Down
8 changes: 8 additions & 0 deletions solidity/contracts/test/ERC20Test.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,12 @@ contract ERC20Test is ERC20 {
function decimals() public view override returns (uint8) {
return _decimals;
}

function mint(uint256 amount) public {
_mint(msg.sender, amount);
}

function mintTo(address account, uint256 amount) public {
_mint(account, amount);
}
}
13 changes: 13 additions & 0 deletions solidity/contracts/test/ERC4626/ERC4626Test.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity >=0.8.0;
import "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/interfaces/IERC20.sol";

contract ERC4626Test is ERC4626 {
constructor(
address _asset,
string memory _name,
string memory _symbol
) ERC4626(IERC20(_asset)) ERC20(_name, _symbol) {}
}
2 changes: 1 addition & 1 deletion solidity/contracts/token/HypERC20Collateral.sol
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ contract HypERC20Collateral is TokenRouter {
*/
function _transferFromSender(
uint256 _amount
) internal override returns (bytes memory) {
) internal virtual override returns (bytes memory) {
wrappedToken.safeTransferFrom(msg.sender, address(this), _amount);
return bytes(""); // no metadata
}
Expand Down
82 changes: 82 additions & 0 deletions solidity/contracts/token/HypERC20CollateralVaultDeposit.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity >=0.8.0;
import "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol";
import {HypERC20Collateral} from "./HypERC20Collateral.sol";

/**
* @title Hyperlane ERC20 Token Collateral with deposits collateral to a vault
* @author ltyu
*/
contract HypERC20CollateralVaultDeposit is HypERC20Collateral {
// Address of the ERC4626 compatible vault
ERC4626 public immutable vault;

// Internal balance of total asset deposited
uint256 public assetDeposited;

event ExcessSharesSwept(uint256 amount, uint256 assetsRedeemed);

constructor(
ERC4626 _vault,
address _mailbox
) HypERC20Collateral(_vault.asset(), _mailbox) {
vault = _vault;
wrappedToken.approve(address(vault), type(uint256).max);
}

/**
* @dev Transfers `_amount` of `wrappedToken` from `msg.sender` to this contract, and deposit into vault
* @inheritdoc HypERC20Collateral
*/
function _transferFromSender(
uint256 _amount
) internal override returns (bytes memory metadata) {
metadata = super._transferFromSender(_amount);
_depositIntoVault(_amount);
}

/**
* @dev Deposits into the vault and increment assetDeposited
* @param _amount amount to deposit into vault
*/
function _depositIntoVault(uint256 _amount) internal {
assetDeposited += _amount;
vault.deposit(_amount, address(this));
}

/**
* @dev Transfers `_amount` of `wrappedToken` from this contract to `_recipient`, and withdraws from vault
* @inheritdoc HypERC20Collateral
*/
function _transferTo(
address _recipient,
uint256 _amount,
bytes calldata
) internal virtual override {
_withdrawFromVault(_amount, _recipient);
}

/**
* @dev Withdraws from the vault and decrement assetDeposited
* @param _amount amount to withdraw from vault
* @param _recipient address to deposit withdrawn underlying to
*/
function _withdrawFromVault(uint256 _amount, address _recipient) internal {
assetDeposited -= _amount;
vault.withdraw(_amount, _recipient, address(this));
}

/**
* @notice Allows the owner to redeem excess shares
*/
function sweep() external onlyOwner {
uint256 excessShares = vault.maxRedeem(address(this)) -
vault.convertToShares(assetDeposited);
uint256 assetsRedeemed = vault.redeem(
excessShares,
owner(),
address(this)
);
emit ExcessSharesSwept(excessShares, assetsRedeemed);
}
}
4 changes: 3 additions & 1 deletion solidity/test/isms/OPStackIsm.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,9 @@ contract OPStackIsmTest is Test {
.overrideMsgValue(uint256(2 ** 255 + 1));

l1Mailbox.updateLatestDispatchedId(messageId);
vm.expectRevert("OPStackHook: msgValue must be less than 2 ** 255");
vm.expectRevert(
"AbstractMessageIdAuthHook: msgValue must be less than 2 ** 255"
);
opHook.postDispatch(excessValueMetadata, encodedMessage);
}

Expand Down
16 changes: 15 additions & 1 deletion solidity/test/token/HypERC20.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,20 @@ abstract contract HypTokenTest is Test {
);
}

function _handleLocalTransfer(uint256 _transferAmount) internal {
vm.prank(address(localMailbox));
localToken.handle(
DESTINATION,
address(remoteToken).addressToBytes32(),
abi.encodePacked(ALICE.addressToBytes32(), _transferAmount)
);
}

function _mintAndApprove(uint256 _amount, address _account) internal {
primaryToken.mint(_amount);
primaryToken.approve(_account, _amount);
}

function _setCustomGasConfig() internal {
localToken.setHook(address(igp));

Expand Down Expand Up @@ -153,7 +167,7 @@ abstract contract HypTokenTest is Test {
_performRemoteTransferAndGas(_msgValue, _amount, _gasOverhead);
}

function testBenchmark_overheadGasUsage() public {
function testBenchmark_overheadGasUsage() public virtual {
vm.prank(address(localMailbox));

uint256 gasBefore = gasleft();
Expand Down
Loading

0 comments on commit 0cc0905

Please sign in to comment.