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

Pull and push updated token metadata #47

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
9 changes: 9 additions & 0 deletions contracts/interfaces/IAMB.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@ pragma solidity 0.7.5;
interface IAMB {
event UserRequestForAffirmation(bytes32 indexed messageId, bytes encodedData);
event UserRequestForSignature(bytes32 indexed messageId, bytes encodedData);
event UserRequestForInformation(
bytes32 indexed messageId,
bytes32 indexed requestSelector,
address indexed sender,
bytes data
);
event InformationRetrieved(bytes32 indexed messageId, bool status, bool callbackStatus);
event CollectedSignatures(
address authorityResponsibleForRelay,
bytes32 messageHash,
Expand Down Expand Up @@ -46,6 +53,8 @@ interface IAMB {
uint256 _gas
) external returns (bytes32);

function requireToGetInformation(bytes32 _requestSelector, bytes calldata _data) external returns (bytes32);

function sourceChainId() external view returns (uint256);

function destinationChainId() external view returns (uint256);
Expand Down
5 changes: 5 additions & 0 deletions contracts/interfaces/IForeignNFTOmnibridge.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pragma solidity 0.7.5;

interface IForeignNFTOmnibridge {
function updateBridgedTokenMetadata(address _token, bytes calldata _data) external;
}
9 changes: 9 additions & 0 deletions contracts/interfaces/IInformationReceiver.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
pragma solidity 0.7.5;

interface IInformationReceiver {
function onInformationReceived(
bytes32 _messageId,
bool _status,
bytes calldata _data
) external;
}
9 changes: 9 additions & 0 deletions contracts/interfaces/ITokenMetadata.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
pragma solidity 0.7.5;

interface ITokenMetadata {
function owner() external view returns (address);

function setOwner(address _owner) external;

function setTokenURI(uint256 _tokenId, string calldata _tokenURI) external;
}
99 changes: 0 additions & 99 deletions contracts/libraries/TokenReader.sol

This file was deleted.

30 changes: 25 additions & 5 deletions contracts/mocks/AMBMock.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
pragma solidity 0.7.5;

import "../interfaces/IInformationReceiver.sol";

contract AMBMock {
event MockedEvent(bytes32 indexed messageId, address executor, uint8 dataType, bytes data, uint256 gas);
event MockedInformationRequest(bytes32 indexed messageId, bytes32 indexed selector, bytes data);

address public messageSender;
uint256 public immutable maxGasPerTx;
Expand Down Expand Up @@ -43,6 +46,15 @@ contract AMBMock {
}
}

function executeInformationResponse(
address _sender,
bytes32 _messageId,
bool _status,
bytes calldata _data
) external {
IInformationReceiver(_sender).onInformationReceived(_messageId, _status, _data);
}

function requireToPassMessage(
address _contract,
bytes calldata _data,
Expand All @@ -59,22 +71,30 @@ contract AMBMock {
return _sendMessage(_contract, _data, _gas, 0x80);
}

function requireToGetInformation(bytes32 _requestSelector, bytes calldata _data) external returns (bytes32) {
bytes32 _messageId = _newMessageId();
emit MockedInformationRequest(_messageId, _requestSelector, _data);
return _messageId;
}

function _sendMessage(
address _contract,
bytes calldata _data,
uint256 _gas,
uint256 _dataType
) internal returns (bytes32) {
bytes32 _messageId = _newMessageId();
emit MockedEvent(_messageId, _contract, uint8(_dataType), _data, _gas);
return _messageId;
}

function _newMessageId() internal returns (bytes32) {
require(messageId == bytes32(0));
bytes32 bridgeId =
keccak256(abi.encodePacked(uint16(1337), address(this))) &
0x00000000ffffffffffffffffffffffffffffffffffffffff0000000000000000;

bytes32 _messageId = bytes32(uint256(0x11223344 << 224)) | bridgeId | bytes32(nonce);
nonce += 1;

emit MockedEvent(_messageId, _contract, uint8(_dataType), _data, _gas);
return _messageId;
return bytes32(uint256(0x11223344 << 224)) | bridgeId | bytes32(nonce++);
}

function sourceChainId() external pure returns (uint256) {
Expand Down
13 changes: 13 additions & 0 deletions contracts/tokens/ERC1155BridgeToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ contract ERC1155BridgeToken is ERC1155, IBurnableMintableERC1155Token {

bool private hasAlreadyMinted;

// metadata field for Opensea, it is not a real owner
address public owner;

constructor(
string memory _name,
string memory _symbol,
Expand Down Expand Up @@ -153,6 +156,16 @@ contract ERC1155BridgeToken is ERC1155, IBurnableMintableERC1155Token {
tokenURIs[_tokenId] = _tokenURI;
}

/**
* @dev Sets the owner for this particular token.
* Ownership of the bridged token does not allow to mint or change tokens on-chain.
* It is only needed for convenience metadata management on the Opensea marketplace.
* @param _owner new token owner.
*/
function setOwner(address _owner) external onlyOwner {
owner = _owner;
}

/**
* @dev Tells the metadata URI for the particular tokenId.
* @param _tokenId unique token id for which to return metadata URI.
Expand Down
13 changes: 13 additions & 0 deletions contracts/tokens/ERC721BridgeToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import "../interfaces/IBurnableMintableERC721Token.sol";
contract ERC721BridgeToken is ERC721, IBurnableMintableERC721Token {
address public bridgeContract;

// metadata field for Opensea, it is not a real owner
address public owner;

constructor(
string memory _name,
string memory _symbol,
Expand Down Expand Up @@ -129,6 +132,16 @@ contract ERC721BridgeToken is ERC721, IBurnableMintableERC721Token {
_setTokenURI(_tokenId, _tokenURI);
}

/**
* @dev Sets the owner for this particular token.
* Ownership of the bridged token does not allow to mint or change tokens on-chain.
* It is only needed for convenience metadata management on the Opensea marketplace.
* @param _owner new token owner.
*/
function setOwner(address _owner) external onlyOwner {
owner = _owner;
}

/**
* @dev Tells the current version of the ERC721 token interfaces.
*/
Expand Down
6 changes: 5 additions & 1 deletion contracts/upgradeable_contracts/Ownable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,14 @@ contract Ownable is EternalStorage {
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(msg.sender == owner());
_onlyOwner();
_;
}

function _onlyOwner() internal {
require(msg.sender == owner());
}

/**
* @dev Throws if called through proxy by any account other than contract itself or an upgradeability owner.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import "../../tokens/ERC721BridgeToken.sol";

/**
* @title BasicNFTOmnibridge
* @dev Commong functionality for multi-token mediator for ERC721 tokens intended to work on top of AMB bridge.
* @dev Common functionality for multi-token mediator for ERC721 tokens intended to work on top of AMB bridge.
*/
abstract contract BasicNFTOmnibridge is
Initializable,
Expand Down Expand Up @@ -337,7 +337,7 @@ abstract contract BasicNFTOmnibridge is
uint256[] memory _tokenIds,
uint256[] memory _values
) internal override {
_releaseTokens(_token, nativeTokenAddress(_token) == address(0), _recipient, _tokenIds, _values);
_releaseTokens(_token, isRegisteredAsNativeToken(_token), _recipient, _tokenIds, _values);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma abicoder v2;

import "./BasicNFTOmnibridge.sol";
import "./components/common/GasLimitManager.sol";
import "../../tokens/ERC1155BridgeToken.sol";

/**
* @title ForeignNFTOmnibridge
Expand All @@ -29,7 +30,7 @@ contract ForeignNFTOmnibridge is BasicNFTOmnibridge, GasLimitManager {
address _owner,
address _imageERC721,
address _imageERC1155
) external onlyRelevantSender returns (bool) {
) external onlyRelevantSender {
require(!isInitialized());

_setBridgeContract(_bridgeContract);
Expand All @@ -40,8 +41,31 @@ contract ForeignNFTOmnibridge is BasicNFTOmnibridge, GasLimitManager {
_setTokenImageERC1155(_imageERC1155);

setInitialize();
}

return isInitialized();
/**
* @dev Function for updating metadata on the bridged token from the other side.
* Used for permission-less updates of owner() and token URIs.
* @param _token address of the native token from the other side of the bridge.
* @param _data calldata for executing on the token contract.
*/
function updateBridgedTokenMetadata(address _token, bytes memory _data) external onlyMediator {
require(_data.length >= 4);
bytes4 selector;
assembly {
selector := shl(224, mload(add(_data, 4)))
}
// we are using this method only for calling setOwner/setTokenURI on the underlying token contract
// this check is here to prevent unintentional calls of sensitive methods
require(
selector != IBurnableMintableERC721Token.mint.selector &&
selector != IBurnableMintableERC721Token.burn.selector &&
selector != IBurnableMintableERC1155Token.mint.selector &&
selector != IBurnableMintableERC1155Token.burn.selector &&
selector != ERC1155BridgeToken.setBridgeContract.selector
);
(bool status, ) = bridgedTokenAddress(_token).call(_data);
require(status);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,20 @@ pragma abicoder v2;

import "./modules/forwarding_rules/NFTForwardingRulesConnector.sol";
import "./modules/gas_limit/SelectorTokenGasLimitConnector.sol";
import "./components/bridged/MetadataPuller.sol";
import "./components/native/MetadataPusher.sol";

/**
* @title HomeNFTOmnibridge
* @dev Home side implementation for multi-token ERC721 mediator intended to work on top of AMB bridge.
* It is designed to be used as an implementation contract of EternalStorageProxy contract.
*/
contract HomeNFTOmnibridge is NFTForwardingRulesConnector, SelectorTokenGasLimitConnector {
contract HomeNFTOmnibridge is
NFTForwardingRulesConnector,
SelectorTokenGasLimitConnector,
MetadataPuller,
MetadataPusher
{
constructor(string memory _suffix) BasicNFTOmnibridge(_suffix) {}

/**
Expand All @@ -31,7 +38,7 @@ contract HomeNFTOmnibridge is NFTForwardingRulesConnector, SelectorTokenGasLimit
address _imageERC721,
address _imageERC1155,
address _forwardingRulesManager
) external onlyRelevantSender returns (bool) {
) external onlyRelevantSender {
require(!isInitialized());

_setBridgeContract(_bridgeContract);
Expand All @@ -43,8 +50,6 @@ contract HomeNFTOmnibridge is NFTForwardingRulesConnector, SelectorTokenGasLimit
_setForwardingRulesManager(_forwardingRulesManager);

setInitialize();

return isInitialized();
}

/**
Expand Down
Loading