Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(contracts): ValueRouter #4814

Open
wants to merge 27 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
3e2f9e3
refactor: implement outbound and inbound warp route amount transforms…
yorhodes Oct 22, 2024
a51b288
fix(contracts): check for sufficient msgValue for `AggregationHook` …
aroralanuk Oct 29, 2024
7215577
init
aroralanuk Nov 5, 2024
4556e24
Merge branch 'main' into kunal/value-router
aroralanuk Nov 7, 2024
99647fe
revert
aroralanuk Nov 7, 2024
6876905
more
aroralanuk Nov 7, 2024
2514043
more
aroralanuk Nov 7, 2024
670912b
fixes
aroralanuk Nov 8, 2024
3fec6a0
rename
aroralanuk Nov 11, 2024
1e54bf6
account.balance
aroralanuk Nov 11, 2024
d8d4d2f
resolve sdk imports
aroralanuk Nov 20, 2024
e302e9c
Merge branch 'main' into kunal/value-router
aroralanuk Nov 20, 2024
ecd1e90
override if more
aroralanuk Nov 27, 2024
8fb963c
testpostdispatchhook
aroralanuk Nov 28, 2024
bee6d22
rm quote fetch
aroralanuk Nov 28, 2024
bab9928
Merge branch 'main' into kunal/value-router
aroralanuk Dec 10, 2024
139ba55
rm extra insuff check
aroralanuk Dec 13, 2024
9fcc4d9
rm comment
aroralanuk Dec 13, 2024
41ff083
inherit from hypnativecollateral
aroralanuk Dec 13, 2024
9c38a7a
interchange names
aroralanuk Dec 13, 2024
5c1f2e8
more
aroralanuk Dec 13, 2024
ec225b4
revert
aroralanuk Dec 13, 2024
d996b3a
Merge branch 'main' into kunal/value-router
aroralanuk Dec 13, 2024
4f04099
rm override if higher
aroralanuk Dec 13, 2024
7cf2d75
docs(changeset): Added a new router HypNativeCollateral with a unifie…
aroralanuk Dec 13, 2024
b541129
revrt
aroralanuk Dec 13, 2024
13e79af
Update long-llamas-fly.md
aroralanuk Dec 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/pretty-keys-give.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hyperlane-xyz/core': minor
---

Added a new router HypNativeCollateral with a unified interface for sending value hook/ism agnostic
19 changes: 19 additions & 0 deletions solidity/contracts/hooks/libs/StandardHookMetadata.sol
Original file line number Diff line number Diff line change
Expand Up @@ -165,4 +165,23 @@ library StandardHookMetadata {
) internal pure returns (bytes memory) {
return formatMetadata(uint256(0), uint256(0), _refundAddress, "");
}

/**
* @notice Overrides the msg.value in the metadata.
* @param _metadata encoded standard hook metadata.
* @param _msgValue msg.value for the message.
* @return encoded standard hook metadata.
*/
function overrideMsgValue(
bytes calldata _metadata,
uint256 _msgValue
) internal view returns (bytes memory) {
return
formatMetadata(
Fixed Show fixed Hide fixed
_msgValue,
gasLimit(_metadata, 0),
refundAddress(_metadata, msg.sender),
Comment on lines +182 to +183
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont understand the 0 and msg.sender here
this will also memcopy for every field iiuc

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are just default values in case the specific part of the metadata is null
true but memcopy is cheap

Copy link
Member

@yorhodes yorhodes Nov 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 gas limit and msg.sender for refund address as defaults does not make sense to me

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what would you have in their place?

getCustomMetadata(_metadata)
Fixed Show fixed Hide fixed
Fixed Show fixed Hide fixed
);
}
}
84 changes: 84 additions & 0 deletions solidity/contracts/token/HypNativeCollateral.sol
aroralanuk marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.0;
Fixed Show fixed Hide fixed

Check notice

Code scanning / Olympix Integrated Security

Using an unbounded pragma for Solidity version may be unsafe if future versions introduce breaking changes. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unbounded-pragma Low

Using an unbounded pragma for Solidity version may be unsafe if future versions introduce breaking changes. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unbounded-pragma

/*@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@ HYPERLANE @@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@*/

// ============ Internal Imports ============
import {TokenRouter} from "./libs/TokenRouter.sol";
import {HypNative} from "./HypNative.sol";
import {StandardHookMetadata} from "../hooks/libs/StandardHookMetadata.sol";

/**
* @title HypNativeCollateral
* @author Abacus Works
* @notice This contract facilitates the transfer of value between chains using value transfer hooks
*/
contract HypNativeCollateral is HypNative {
Dismissed Show dismissed Hide dismissed
constructor(address _mailbox) HypNative(_mailbox) {}

Check notice

Code scanning / Olympix Integrated Security

Test functions fail to thoroughly test all aspects of contract constructors, potentially missing critical initialization issues. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/incomplete-constructor-tests Low

Test functions fail to thoroughly test all aspects of contract constructors, potentially missing critical initialization issues. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/incomplete-constructor-tests

Check notice

Code scanning / Olympix Integrated Security

Parameters passed to a constructor that are not validated for correct values may lead to contract creation in an undesired state. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/no-parameter-validation-in-constructor Low

Parameters passed to a constructor that are not validated for correct values may lead to contract creation in an undesired state. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/no-parameter-validation-in-constructor

// ============ External Functions ============

/// @inheritdoc TokenRouter
function transferRemote(
Dismissed Show dismissed Hide dismissed
uint32 _destination,
bytes32 _recipient,
uint256 _amount
) external payable virtual override returns (bytes32 messageId) {
bytes calldata emptyBytes;
assembly {
emptyBytes.length := 0
emptyBytes.offset := 0

Check warning on line 40 in solidity/contracts/token/HypNativeCollateral.sol

View check run for this annotation

Codecov / codecov/patch

solidity/contracts/token/HypNativeCollateral.sol#L39-L40

Added lines #L39 - L40 were not covered by tests
}
return
transferRemote(
_destination,
_recipient,
_amount,
emptyBytes,
address(hook)
);
}

/**
* @inheritdoc TokenRouter
* @dev use _hook with caution, make sure that this hook can handle msg.value transfer using the metadata.msgValue()
*/
function transferRemote(
Dismissed Show dismissed Hide dismissed
uint32 _destination,
bytes32 _recipient,
uint256 _amount,
bytes calldata _hookMetadata,
address _hook
) public payable virtual override returns (bytes32 messageId) {
uint256 quote = _GasRouter_quoteDispatch(
_destination,
_hookMetadata,
_hook
);

bytes memory hookMetadata = StandardHookMetadata.overrideMsgValue(
_hookMetadata,
_amount
);

return
_transferRemote(
_destination,
_recipient,
_amount,
_amount + quote,
hookMetadata,
_hook
);
}
}
152 changes: 152 additions & 0 deletions solidity/test/token/HypNative.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.0;

import {TypeCasts} from "../../contracts/libs/TypeCasts.sol";
import {HypTokenTest} from "./HypERC20.t.sol";
import {HypERC20} from "../../contracts/token/HypERC20.sol";
import {TokenRouter} from "../../contracts/token/libs/TokenRouter.sol";
import {HypNativeCollateral} from "../../contracts/token/HypNativeCollateral.sol";
import {TestPostDispatchHook} from "../../contracts/test/TestPostDispatchHook.sol";
import {TestIsm} from "../../contracts/test/TestIsm.sol";

contract HypNativeCollateralTest is HypTokenTest {
using TypeCasts for address;

HypNativeCollateral internal localValueRouter;
HypNativeCollateral internal remoteValueRouter;
TestPostDispatchHook internal valueHook;
TestIsm internal ism;

function setUp() public override {
super.setUp();

localValueRouter = new HypNativeCollateral(address(localMailbox));
remoteValueRouter = new HypNativeCollateral(address(remoteMailbox));

localToken = TokenRouter(payable(address(localValueRouter)));
remoteToken = HypERC20(payable(address(remoteValueRouter)));

ism = new TestIsm();

valueHook = new TestPostDispatchHook();
valueHook.setFee(1e10);

localValueRouter.initialize(
address(valueHook),
address(ism),
address(this)
);
remoteValueRouter.initialize(
address(valueHook),
address(ism),
address(this)
);

localValueRouter.enrollRemoteRouter(
DESTINATION,
address(remoteToken).addressToBytes32()
);
remoteValueRouter.enrollRemoteRouter(
ORIGIN,
address(localToken).addressToBytes32()
);

vm.deal(ALICE, TRANSFER_AMT * 10);
}

function testRemoteTransfer() public {
uint256 quote = localValueRouter.quoteGasPayment(DESTINATION);
uint256 msgValue = TRANSFER_AMT + quote;

vm.expectEmit(true, true, false, true);
emit TokenRouter.SentTransferRemote(
DESTINATION,
BOB.addressToBytes32(),
TRANSFER_AMT
);

vm.prank(ALICE);
localToken.transferRemote{value: msgValue}(
DESTINATION,
BOB.addressToBytes32(),
TRANSFER_AMT
);

vm.assertEq(address(localToken).balance, 0);
vm.assertEq(address(valueHook).balance, msgValue);

vm.deal(address(remoteToken), TRANSFER_AMT);
vm.prank(address(remoteMailbox));

remoteToken.handle(
ORIGIN,
address(localToken).addressToBytes32(),
abi.encodePacked(BOB.addressToBytes32(), TRANSFER_AMT)
);

assertEq(BOB.balance, TRANSFER_AMT);
assertEq(address(valueHook).balance, msgValue);
}

// when msg.value is >= quote + amount, it should revert in
function testRemoteTransfer_insufficientValue() public {
vm.expectRevert();
vm.prank(ALICE);
localToken.transferRemote{value: TRANSFER_AMT}(
DESTINATION,
BOB.addressToBytes32(),
TRANSFER_AMT
);
}

function testTransfer_withHookSpecified(
uint256 fee,
bytes calldata metadata
) public override {
vm.assume(fee < TRANSFER_AMT);
uint256 msgValue = TRANSFER_AMT + fee;
vm.deal(ALICE, msgValue);

TestPostDispatchHook hook = new TestPostDispatchHook();
hook.setFee(fee);

vm.prank(ALICE);
localToken.transferRemote{value: msgValue}(
DESTINATION,
BOB.addressToBytes32(),
TRANSFER_AMT,
metadata,
address(hook)
);

vm.assertEq(address(localToken).balance, 0);
vm.assertEq(address(valueHook).balance, 0);
}

function testTransfer_withHookSpecified_revertsInsufficientValue(
uint256 fee,
bytes calldata metadata
) public {
vm.assume(fee < TRANSFER_AMT);
uint256 msgValue = TRANSFER_AMT + fee;
vm.deal(ALICE, msgValue);

TestPostDispatchHook hook = new TestPostDispatchHook();
hook.setFee(fee);

vm.prank(ALICE);
vm.expectRevert();
localToken.transferRemote{value: msgValue - 1}(
DESTINATION,
BOB.addressToBytes32(),
TRANSFER_AMT,
metadata,
address(hook)
);
}

function testBenchmark_overheadGasUsage() public override {
vm.deal(address(localValueRouter), TRANSFER_AMT);
super.testBenchmark_overheadGasUsage();
}
}
Loading