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 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
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
13 changes: 10 additions & 3 deletions solidity/contracts/hooks/OPL2ToL1Hook.sol
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,12 @@ contract OPL2ToL1Hook is AbstractMessageIdAuthHook {
bytes calldata metadata,
bytes calldata message
) internal view override returns (uint256) {
bytes memory metadataWithGasLimit = metadata.overrideGasLimit(
MIN_GAS_LIMIT
);
return
metadata.msgValue(0) + childHook.quoteDispatch(metadata, message);
metadata.msgValue(0) +
childHook.quoteDispatch(metadataWithGasLimit, message);
}

// ============ Internal functions ============
Expand All @@ -83,9 +87,12 @@ contract OPL2ToL1Hook is AbstractMessageIdAuthHook {
(message.id(), metadata.msgValue(0))
);

bytes memory metadataWithGasLimit = metadata.overrideGasLimit(
MIN_GAS_LIMIT
);
aroralanuk marked this conversation as resolved.
Show resolved Hide resolved
childHook.postDispatch{
value: childHook.quoteDispatch(metadata, message)
}(metadata, message);
value: childHook.quoteDispatch(metadataWithGasLimit, message)
}(metadataWithGasLimit, message);
l2Messenger.sendMessage{value: metadata.msgValue(0)}(
TypeCasts.bytes32ToAddress(ism),
payload,
Expand Down
38 changes: 38 additions & 0 deletions solidity/contracts/hooks/libs/StandardHookMetadata.sol
Original file line number Diff line number Diff line change
Expand Up @@ -165,4 +165,42 @@ 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(
_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)
);
}

/**
* @notice Overrides the gas limit in the metadata.
* @param _metadata encoded standard hook metadata.
* @param _gasLimit gas limit for the message.
* @return encoded standard hook metadata.
*/
function overrideGasLimit(
bytes calldata _metadata,
uint256 _gasLimit
) internal view returns (bytes memory) {
return
formatMetadata(
msgValue(_metadata, 0),
_gasLimit,
refundAddress(_metadata, msg.sender),
getCustomMetadata(_metadata)
);
}
}
166 changes: 166 additions & 0 deletions solidity/contracts/token/HypValue.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.0;

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

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

// ============ External Imports ============
import {Address} from "@openzeppelin/contracts/utils/Address.sol";

/**
* @title HypValue
* @author Abacus Works
* @notice This contract facilitates the transfer of value between chains using value transfer hooks
*/
contract HypValue is TokenRouter {
aroralanuk marked this conversation as resolved.
Show resolved Hide resolved
// ============ Errors ============
error InsufficientValue(uint256 amount, uint256 value);

constructor(address _mailbox) TokenRouter(_mailbox) {}

// ============ Initialization ============

/**
* @notice Initializes the contract
* @param _valuehook The address of the value transfer hook
* @param _interchainSecurityModule The address of the interchain security module
* @param _owner The owner of the contract
*/
function initialize(
address _valuehook,
address _interchainSecurityModule,
address _owner
) public initializer {
_MailboxClient_initialize(
_valuehook,
_interchainSecurityModule,
_owner
);
}

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

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

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

return
_transferRemote(
_destination,
_recipient,
_amount,
_amount + quote,
hookMetadata,
_hook
);
}

/// @inheritdoc TokenRouter
function transferRemote(
uint32 _destination,
bytes32 _recipient,
uint256 _amount
) external payable virtual override returns (bytes32 messageId) {
uint256 quote = _checkSufficientValue(
_destination,
_amount,
address(hook)
);
bytes memory hookMetadata = StandardHookMetadata.formatMetadata(
_amount,
destinationGas[_destination],
msg.sender,
""
);

aroralanuk marked this conversation as resolved.
Show resolved Hide resolved
return
_transferRemote(
_destination,
_recipient,
_amount,
_amount + quote,
hookMetadata,
address(hook)
);
}

// ============ Internal Functions ============

/**
* @inheritdoc TokenRouter
* @dev No token metadata is needed for value transfers
*/
function _transferFromSender(
uint256
) internal pure override returns (bytes memory) {
return bytes(""); // no token metadata
}

/**
* @inheritdoc TokenRouter
* @dev Sends the value to the recipient
*/
function _transferTo(
address _recipient,
uint256 _amount,
bytes calldata // no token metadata
) internal virtual override {
Address.sendValue(payable(_recipient), _amount);
}

/**
* @inheritdoc TokenRouter
* @dev This contract doesn't hold value
aroralanuk marked this conversation as resolved.
Show resolved Hide resolved
*/
function balanceOf(
address /* _account */
) external pure override returns (uint256) {
return 0;
}
aroralanuk marked this conversation as resolved.
Show resolved Hide resolved

/// @dev Checks if the provided value is sufficient for the transfer
function _checkSufficientValue(
uint32 _destination,
uint256 _amount,
address _hook
) internal view returns (uint256) {
uint256 quote = _GasRouter_quoteDispatch(
_destination,
new bytes(0),
aroralanuk marked this conversation as resolved.
Show resolved Hide resolved
_hook
);
if (msg.value < _amount + quote) {
revert InsufficientValue(_amount + quote, msg.value);
}
return quote;
aroralanuk marked this conversation as resolved.
Show resolved Hide resolved
}

receive() external payable {}
aroralanuk marked this conversation as resolved.
Show resolved Hide resolved
}
Loading
Loading