Skip to content
This repository has been archived by the owner on Jul 10, 2023. It is now read-only.

Commit

Permalink
Add URI support (#12)
Browse files Browse the repository at this point in the history
* Add HypERC721URIStorage

* Add HypERC721URICollateral
  • Loading branch information
yorhodes authored Dec 16, 2022
1 parent cb0ba36 commit 272a195
Show file tree
Hide file tree
Showing 14 changed files with 499 additions and 258 deletions.
28 changes: 20 additions & 8 deletions contracts/HypERC20.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {TokenRouter} from "./libs/TokenRouter.sol";
import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";

/**
* @title Hyperlane Token that extends the ERC20 token standard to enable native interchain transfers.
* @title Hyperlane ERC20 Token Router that extends ERC20 with remote transfer functionality.
* @author Abacus Works
* @dev Supply on each chain is not constant but the aggregate supply across all chains is.
*/
Expand Down Expand Up @@ -40,16 +40,28 @@ contract HypERC20 is ERC20Upgradeable, TokenRouter {
_mint(msg.sender, _totalSupply);
}

// called in `TokenRouter.transferRemote` before `Mailbox.dispatch`
function _transferFromSender(uint256 _amount) internal override {
_burn(msg.sender, _amount);
}

// called by `TokenRouter.handle`
function _transferTo(address _recipient, uint256 _amount)
/**
* @dev Burns `_amount` of token from `msg.sender` balance.
* @inheritdoc TokenRouter
*/
function _transferFromSender(uint256 _amount)
internal
override
returns (bytes memory)
{
_burn(msg.sender, _amount);
return bytes(""); // no metadata
}

/**
* @dev Mints `_amount` of token to `_recipient` balance.
* @inheritdoc TokenRouter
*/
function _transferTo(
address _recipient,
uint256 _amount,
bytes calldata // no metadata
) internal override {
_mint(_recipient, _amount);
}
}
37 changes: 30 additions & 7 deletions contracts/HypERC20Collateral.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {TokenRouter} from "./libs/TokenRouter.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

/**
* @title Collateralize ERC20 token and route messages to HypERC20 tokens.
* @title Hyperlane ERC20 Token Collateral that wraps an existing ERC20 with remote transfer functionality.
* @author Abacus Works
*/
contract HypERC20Collateral is TokenRouter {
Expand All @@ -16,6 +16,12 @@ contract HypERC20Collateral is TokenRouter {
wrappedToken = IERC20(erc20);
}

/**
* @notice Initializes the Hyperlane router.
* @param _mailbox The address of the mailbox contract.
* @param _interchainGasPaymaster The address of the interchain gas paymaster contract.
* @param _interchainSecurityModule The address of the interchain security module contract.
*/
function initialize(
address _mailbox,
address _interchainGasPaymaster,
Expand All @@ -28,14 +34,31 @@ contract HypERC20Collateral is TokenRouter {
);
}

function _transferFromSender(uint256 _amount) internal override {
require(wrappedToken.transferFrom(msg.sender, address(this), _amount));
}

function _transferTo(address _recipient, uint256 _amount)
/**
* @dev Transfers `_amount` of `wrappedToken` from `msg.sender` to this contract.
* @inheritdoc TokenRouter
*/
function _transferFromSender(uint256 _amount)
internal
override
returns (bytes memory)
{
require(wrappedToken.transfer(_recipient, _amount));
require(
wrappedToken.transferFrom(msg.sender, address(this), _amount),
"!transferFrom"
);
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 override {
require(wrappedToken.transfer(_recipient, _amount), "!transfer");
}
}
29 changes: 21 additions & 8 deletions contracts/HypERC721.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {TokenRouter} from "./libs/TokenRouter.sol";
import {ERC721EnumerableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol";

/**
* @title Hyperlane Token that extends the ERC721 token standard to enable native interchain transfers.
* @title Hyperlane ERC721 Token Router that extends ERC721 with remote transfer functionality.
* @author Abacus Works
*/
contract HypERC721 is ERC721EnumerableUpgradeable, TokenRouter {
Expand Down Expand Up @@ -40,17 +40,30 @@ contract HypERC721 is ERC721EnumerableUpgradeable, TokenRouter {
}
}

// called in `TokenRouter.transferRemote` before `Mailbox.dispatch`
function _transferFromSender(uint256 _tokenId) internal override {
/**
* @dev Asserts `msg.sender` is owner and burns `_tokenId`.
* @inheritdoc TokenRouter
*/
function _transferFromSender(uint256 _tokenId)
internal
virtual
override
returns (bytes memory)
{
require(ownerOf(_tokenId) == msg.sender, "!owner");
_burn(_tokenId);
return bytes(""); // no metadata
}

// called by `TokenRouter.handle`
function _transferTo(address _recipient, uint256 _tokenId)
internal
override
{
/**
* @dev Mints `_tokenId` to `_recipient`.
* @inheritdoc TokenRouter
*/
function _transferTo(
address _recipient,
uint256 _tokenId,
bytes calldata // no metadata
) internal virtual override {
_mint(_recipient, _tokenId);
}
}
39 changes: 30 additions & 9 deletions contracts/HypERC721Collateral.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,22 @@ import {TokenRouter} from "./libs/TokenRouter.sol";
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";

/**
* @title Collateralize ERC20 token and route messages to HypERC20 tokens.
* @title Hyperlane ERC721 Token Collateral that wraps an existing ERC721 with remote transfer functionality.
* @author Abacus Works
*/
contract HypERC721Collateral is TokenRouter {
IERC721 public immutable wrappedToken;
address public immutable wrappedToken;

constructor(address erc721) {
wrappedToken = IERC721(erc721);
wrappedToken = erc721;
}

/**
* @notice Initializes the Hyperlane router.
* @param _mailbox The address of the mailbox contract.
* @param _interchainGasPaymaster The address of the interchain gas paymaster contract.
* @param _interchainSecurityModule The address of the interchain security module contract.
*/
function initialize(
address _mailbox,
address _interchainGasPaymaster,
Expand All @@ -28,14 +34,29 @@ contract HypERC721Collateral is TokenRouter {
);
}

function _transferFromSender(uint256 _amount) internal override {
wrappedToken.transferFrom(msg.sender, address(this), _amount);
}

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

/**
* @dev Transfers `_tokenId` of `wrappedToken` from this contract to `_recipient`.
* @inheritdoc TokenRouter
*/
function _transferTo(
address _recipient,
uint256 _tokenId,
bytes calldata // no metadata
) internal override {
IERC721(wrappedToken).transferFrom(address(this), _recipient, _tokenId);
}
}
29 changes: 29 additions & 0 deletions contracts/extensions/HypERC721URICollateral.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity >=0.8.0;

import {HypERC721Collateral} from "../HypERC721Collateral.sol";

import {IERC721MetadataUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/IERC721MetadataUpgradeable.sol";

/**
* @title Hyperlane ERC721 Token Collateral that wraps an existing ERC721 with remote transfer and URI relay functionality.
* @author Abacus Works
*/
contract HypERC721URICollateral is HypERC721Collateral {
constructor(address erc721) HypERC721Collateral(erc721) {}

/**
* @dev Transfers `_tokenId` of `wrappedToken` from `msg.sender` to this contract.
* @return The URI of `_tokenId` on `wrappedToken`.
* @inheritdoc HypERC721Collateral
*/
function _transferFromSender(uint256 _tokenId)
internal
override
returns (bytes memory)
{
HypERC721Collateral._transferFromSender(_tokenId);
return
bytes(IERC721MetadataUpgradeable(wrappedToken).tokenURI(_tokenId));
}
}
73 changes: 73 additions & 0 deletions contracts/extensions/HypERC721URIStorage.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity >=0.8.0;

import {HypERC721} from "../HypERC721.sol";

import {ERC721URIStorageUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721URIStorageUpgradeable.sol";
import {ERC721EnumerableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol";
import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol";

/**
* @title Hyperlane ERC721 Token that extends ERC721URIStorage with remote transfer and URI relay functionality.
* @author Abacus Works
*/
contract HypERC721URIStorage is HypERC721, ERC721URIStorageUpgradeable {
/**
* @return _tokenURI The URI of `_tokenId`.
* @inheritdoc HypERC721
*/
function _transferFromSender(uint256 _tokenId)
internal
override
returns (bytes memory _tokenURI)
{
_tokenURI = bytes(tokenURI(_tokenId)); // requires minted
HypERC721._transferFromSender(_tokenId);
}

/**
* @dev Sets the URI for `_tokenId` to `_tokenURI`.
* @inheritdoc HypERC721
*/
function _transferTo(
address _recipient,
uint256 _tokenId,
bytes calldata _tokenURI
) internal override {
HypERC721._transferTo(_recipient, _tokenId, _tokenURI);
_setTokenURI(_tokenId, string(_tokenURI)); // requires minted
}

function tokenURI(uint256 tokenId)
public
view
override(ERC721Upgradeable, ERC721URIStorageUpgradeable)
returns (string memory)
{
return ERC721URIStorageUpgradeable.tokenURI(tokenId);
}

function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId
) internal override(ERC721EnumerableUpgradeable, ERC721Upgradeable) {
ERC721EnumerableUpgradeable._beforeTokenTransfer(from, to, tokenId);
}

function supportsInterface(bytes4 interfaceId)
public
view
override(ERC721EnumerableUpgradeable, ERC721Upgradeable)
returns (bool)
{
return ERC721EnumerableUpgradeable.supportsInterface(interfaceId);
}

function _burn(uint256 tokenId)
internal
override(ERC721URIStorageUpgradeable, ERC721Upgradeable)
{
ERC721URIStorageUpgradeable._burn(tokenId);
}
}
20 changes: 14 additions & 6 deletions contracts/libs/Message.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
pragma solidity >=0.8.0;

library Message {
function format(bytes32 _recipient, uint256 _amount)
internal
pure
returns (bytes memory)
{
return abi.encodePacked(_recipient, _amount);
function format(
bytes32 _recipient,
uint256 _amount,
bytes memory _metadata
) internal pure returns (bytes memory) {
return abi.encodePacked(_recipient, _amount, _metadata);
}

function recipient(bytes calldata message) internal pure returns (bytes32) {
Expand All @@ -22,4 +22,12 @@ library Message {
function tokenId(bytes calldata message) internal pure returns (uint256) {
return amount(message);
}

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

0 comments on commit 272a195

Please sign in to comment.