Skip to content

Commit

Permalink
feat: create HypLSP7Collateral + adjusted version of HypERC20 whe…
Browse files Browse the repository at this point in the history
…n bridging an LSP7 from LUKSO to Ethereum
  • Loading branch information
CJ42 committed Oct 7, 2024
1 parent e592fdb commit aa68fe0
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 26 deletions.
31 changes: 31 additions & 0 deletions src/HypERC20ForLSP7.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.19;

// modules
import { HypERC20 } from "@hyperlane-xyz/core/contracts/token/HypERC20.sol";
import { TokenRouter } from "@hyperlane-xyz/core/contracts/token/libs/TokenRouter.sol";

// libraries
import { TypeCasts } from "@hyperlane-xyz/core/contracts/libs/TypeCasts.sol";
import { TokenMessageForLSP7 } from "./TokenMessageForLSP7.sol";

contract HypERC20ForLSP7 is HypERC20 {
constructor(uint8 __decimals, address _mailbox) HypERC20(__decimals, _mailbox) { }

/**
* @dev Mints tokens to recipient when router receives transfer message.
* @dev Emits `ReceivedTransferRemote` event on the destination chain.
* @param _origin The identifier of the origin chain.
* @param _message The encoded remote transfer message containing the recipient address and amount.
*
* @dev This function is overriden to extract the right params and calldata slices
* from a transfer message coming from LSP7, via the modified library `TokenMessageForLSP7`.
*/
function _handle(uint32 _origin, bytes32, bytes calldata _message) internal virtual override(TokenRouter) {
bytes32 recipient = TokenMessageForLSP7.recipient(_message);
uint256 amount = TokenMessageForLSP7.amount(_message);
bytes calldata metadata = TokenMessageForLSP7.metadata(_message);
_transferTo(TypeCasts.bytes32ToAddress(recipient), amount, metadata);
emit ReceivedTransferRemote(_origin, recipient, amount);
}
}
24 changes: 0 additions & 24 deletions src/HypLSP7.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ import { LSP7DigitalAssetInitAbstract } from "@lukso/lsp7-contracts/contracts/LS
import { TokenRouter } from "@hyperlane-xyz/core/contracts/token/libs/TokenRouter.sol";
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

// libraries
import { TokenMessageForLSP7 } from "./TokenMessageForLSP7.sol";

// constants
import { _LSP4_TOKEN_TYPE_TOKEN } from "@lukso/lsp4-contracts/contracts/LSP4Constants.sol";

Expand Down Expand Up @@ -100,25 +97,4 @@ contract HypLSP7 is LSP7DigitalAssetInitAbstract, TokenRouter {
{
LSP7DigitalAssetInitAbstract._mint(_recipient, _amount, true, "");
}

function _transferRemote(
uint32 _destination,
bytes32 _recipient,
uint256 _amountOrId,
uint256 _value,
bytes memory _hookMetadata,
address _hook
)
internal
virtual
override(TokenRouter)
returns (bytes32 messageId)
{
bytes memory _tokenMetadata = _transferFromSender(_amountOrId);
bytes memory _tokenMessage = TokenMessageForLSP7.format(_recipient, _amountOrId, _tokenMetadata);

messageId = _Router_dispatch(_destination, _value, _tokenMessage, _hookMetadata, _hook);

emit SentTransferRemote(_destination, _recipient, _amountOrId);
}
}
53 changes: 53 additions & 0 deletions src/HypLSP7Collateral.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.19;

// Interfaces
import { ILSP7DigitalAsset as ILSP7 } from "@lukso/lsp7-contracts/contracts/ILSP7DigitalAsset.sol";

// Modules
import { TokenRouter } from "@hyperlane-xyz/core/contracts/token/libs/TokenRouter.sol";

contract HypLSP7Collateral is TokenRouter {
ILSP7 public immutable wrappedToken;

/**
* @notice Constructor
* @param lsp7_ Address of the token to keep as collateral
*/
constructor(address lsp7_, address mailbox_) TokenRouter(mailbox_) {
wrappedToken = ILSP7(lsp7_);
}

function initialize(address _hook, address _interchainSecurityModule, address _owner) public virtual initializer {
_MailboxClient_initialize(_hook, _interchainSecurityModule, _owner);
}

function balanceOf(address _account) external view override returns (uint256) {
return wrappedToken.balanceOf(_account);
}

/**
* @dev Transfers `_amount` of `wrappedToken` from `msg.sender` to this contract.
* @inheritdoc TokenRouter
*/
function _transferFromSender(uint256 _amount) internal virtual override returns (bytes memory) {
wrappedToken.transfer(msg.sender, address(this), _amount, true, "");
return bytes(""); // no metadata
}

/**
* @dev Transfers `_amount` of `wrappedToken` from this contract to `_recipient`.
* @inheritdoc TokenRouter
*/
function _transferTo(
address _recipient,
uint256 _amount,
bytes calldata // no metadata
)
internal
virtual
override
{
wrappedToken.transfer(address(this), _recipient, _amount, true, "");
}
}
44 changes: 42 additions & 2 deletions src/TokenMessageForLSP7.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,41 @@ pragma solidity >=0.8.0;
/// @dev Adjusted version of the TokenMessage library from Hyperlane
/// to extract parameters from the calldata of an LSP7 transfer
/// according to the `transfer(address,address,uint256,bool,bytes)` signature.
/**
* @title TokenMessage library for LSP7 calldatas
* @author CJ42
* @dev
*
* Example: for the following `transfer(...)` function call:
*
* from: 0x927aad446e3bf6eeb776387b3d7a89d8016fa54d (cj42)
* to: 0x345b918b9e06faa7b0e56bd71ba418f31f47fed4 (yamen)
* amount: 100000000000000000000 (= 100 tokens with 18 decimals)
* force: false
* data: 0x
*
* The calldata will look as follow:
* 0x760d9bba000000000000000000000000927aad446e3bf6eeb776387b3d7a89d8016fa54d000000000000000000000000345b918b9e06faa7b0e56bd71ba418f31f47fed40000000000000000000000000000000000000000000000056bc75e2d63100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000
*
* 0x760d9bba -> bytes4 selector
* 000000000000000000000000927aad446e3bf6eeb776387b3d7a89d8016fa54d -> address `from`
* 000000000000000000000000345b918b9e06faa7b0e56bd71ba418f31f47fed4 -> address `to`
* 0000000000000000000000000000000000000000000000056bc75e2d63100000 -> uint256 `amount`
* 0000000000000000000000000000000000000000000000000000000000000000 -> bool `force`
* 00000000000000000000000000000000000000000000000000000000000000a0 -> offset of bytes `data`
* 0000000000000000000000000000000000000000000000000000000000000000 -> `data.length` = 0
*
* Note: the offset of data is index starting from just after the bytes4 selector, where the data [length + value] is
* located in the calldata (0xa0 = 160).
*/
library TokenMessageForLSP7 {
function format(bytes32 _recipient, uint256 _amount, bytes memory _metadata) internal view returns (bytes memory) {
return abi.encodePacked(
msg.sender, // TODO: which sender should be specified here? Should we add an extra parameter?
abi.encode(msg.sender), // TODO: which sender should be specified here? Should we add an
// extra parameter?
_recipient,
_amount,
true, // force param set to `true` by default
abi.encode(true), // force param set to `true` by default
_metadata
);
}
Expand All @@ -22,4 +50,16 @@ library TokenMessageForLSP7 {
function amount(bytes calldata message) internal pure returns (uint256) {
return uint256(bytes32(message[64:96]));
}

function metadata(bytes calldata message) internal pure returns (bytes calldata) {
return message[128:];
}
}

// 0x44c028fe
// 0000000000000000000000000000000000000000000000000000000000000000
// 0000000000000000000000005b8b0e44d4719f8a328470dccd3746bfc73d6b14
// 0000000000000000000000000000000000000000000000000000000000000000
// 0000000000000000000000000000000000000000000000000000000000000080
// 00000000000000000000000000000000000000000000000000000000000000c4
// 760d9bba000000000000000000000000927aad446e3bf6eeb776387b3d7a89d8016fa54d000000000000000000000000345b918b9e06faa7b0e56bd71ba418f31f47fed40000000000000000000000000000000000000000000000056bc75e2d63100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

0 comments on commit aa68fe0

Please sign in to comment.