Skip to content

Instantly share code, notes, and snippets.

@developeruche
Created July 12, 2023 19:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save developeruche/d95ab311742a72a939887d8544e3e9ca to your computer and use it in GitHub Desktop.
Save developeruche/d95ab311742a72a939887d8544e3e9ca to your computer and use it in GitHub Desktop.
This is the bridge contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {
ERC721Enumerable
} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { INahmiiStandardERC721, Existence } from "./INahmiiStandardERC721.sol";
/**
* @title NahmiiStandardERC721
* @notice This contract is the remote representation for some token that lives on another network,
* typically an Nahmii representation of an Ethereum-based token. Standard reference
* implementation that can be extended or modified according to your needs.
*/
contract NahmiiStandardERC721 is Ownable, INahmiiStandardERC721, ERC721Enumerable {
/**
* @inheritdoc INahmiiStandardERC721
*/
uint256 public remoteChainId;
/**
* @inheritdoc INahmiiStandardERC721
*/
uint256 public layerId;
/**
* @inheritdoc INahmiiStandardERC721
*/
address public remoteToken;
/**
* @inheritdoc INahmiiStandardERC721
*/
address public bridge;
/**
* @inheritdoc INahmiiStandardERC721
*/
Existence public existence;
/**
* @inheritdoc INahmiiStandardERC721
*/
bool public native;
/**
* @notice Base token URI for this token.
*/
string public baseTokenURI;
/**
* @param _name ERC721 name.
* @param _symbol ERC721 symbol.
*/
constructor(string memory _name, string memory _symbol) ERC721(_name, _symbol) {}
/**
* @notice Modifier that prevents callers other than the bridge or
* contract owner from calling the function.
*/
modifier verifyCaller(uint256 _tokenId) {
if (native == true && (_isEven(_tokenId) == _isEven(layerId))) {
require(
msg.sender == bridge || msg.sender == owner(),
"NahmiiStandardERC721: only bridge or contract owner can call this function"
);
_;
} else {
require(
msg.sender == bridge,
"NahmiiStandardERC721: only bridge can call this function"
);
_;
}
}
/**
* @inheritdoc INahmiiStandardERC721
*/
function initialize(
address _bridge,
uint256 _remoteChainId,
address _remoteToken,
Existence _existence,
bool _native,
uint256 _layerId
) external virtual {
// State variables initialization check
require(bridge == address(0), "NahmiiStandardERC721: bridge must be uninitialized");
// Function parameters check
require(_bridge != address(0), "NahmiiStandardERC721: bridge cannot be address(0)");
require(_remoteChainId != 0, "NahmiiStandardERC721: remote chain id cannot be zero");
require(
_remoteToken != address(0),
"NahmiiStandardERC721: remote token cannot be address(0)"
);
require(_layerId != 0, "NahmiiStandardERC721: layer id cannot be zero");
remoteChainId = _remoteChainId;
remoteToken = _remoteToken;
bridge = _bridge;
existence = _existence;
native = _native;
layerId = _layerId;
// Creates a base URI in the format specified by EIP-681:
// https://eips.ethereum.org/EIPS/eip-681
baseTokenURI = string(
abi.encodePacked(
"ethereum:",
Strings.toHexString(uint160(_remoteToken), 20),
"@",
Strings.toString(_remoteChainId),
"/tokenURI?uint256="
)
);
}
/**
* @inheritdoc INahmiiStandardERC721
*/
function safeMint(address _to, uint256 _tokenId) external virtual verifyCaller(_tokenId) {
_safeMint(_to, _tokenId);
emit Mint(_to, _tokenId);
}
/**
* @inheritdoc INahmiiStandardERC721
*/
function burn(address _from, uint256 _tokenId) external virtual verifyCaller(_tokenId) {
_burn(_tokenId);
emit Burn(_from, _tokenId);
}
/**
* @notice Checks if a given interface ID is supported by this contract.
*
* @param _interfaceId The interface ID to check.
*
* @return True if the interface ID is supported, false otherwise.
*/
function supportsInterface(bytes4 _interfaceId)
public
view
virtual
override(ERC721Enumerable, IERC165)
returns (bool)
{
bytes4 iface1 = type(IERC165).interfaceId;
bytes4 iface2 = type(INahmiiStandardERC721).interfaceId;
return
_interfaceId == iface1 ||
_interfaceId == iface2 ||
super.supportsInterface(_interfaceId);
}
/**
* @notice Returns the base token URI.
*
* @return Base token URI.
*/
function _baseURI() internal view virtual override returns (string memory) {
return baseTokenURI;
}
/**
* @notice Checks that an integer value is even.
*
* @param _value Unisgned integer value to check
*
* @return True if integer value is even, false otherwise.
*/
function _isEven(uint256 _value) internal pure returns (bool) {
return _value % 2 == 0;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {
IERC721Enumerable
} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
enum Existence {
Transient,
Permanent
}
/**
* @title INahmiiStandardERC721
* @notice Interface for contracts that are compatible with the NahmiiStandardERC721 standard.
* Tokens that follow this standard can be easily transferred across the ERC721 bridge.
*/
interface INahmiiStandardERC721 is IERC721Enumerable {
/**
* @notice Emitted when a token is minted.
*
* @param account Address of the account the token was minted to.
* @param tokenId Token ID of the minted token.
*/
event Mint(address indexed account, uint256 tokenId);
/**
* @notice Emitted when a token is burned.
*
* @param account Address of the account the token was burned from.
* @param tokenId Token ID of the burned token.
*/
event Burn(address indexed account, uint256 tokenId);
/**
* @notice Chain ID of the chain where the remote token is deployed.
*/
function remoteChainId() external view returns (uint256);
/**
* @notice Address of the token on the remote domain.
*/
function remoteToken() external view returns (address);
/**
* @return Existence status.
*/
function existence() external view returns (Existence);
/**
* @notice Address of the ERC721 bridge on this network.
*/
function bridge() external view returns (address);
/**
* @notice Nature of the ERC721 token on this network.
*/
function native() external view returns (bool);
/**
* @notice Layer of the ERC721 bridge on this network.
*/
function layerId() external view returns (uint256);
/**
* @notice Mints some token ID for a user, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* @param _to Address of the user to mint the token for.
* @param _tokenId Token ID to mint.
*/
function safeMint(address _to, uint256 _tokenId) external;
/**
* @notice Burns a token ID from a user.
*
* @param _from Address of the user to burn the token from.
* @param _tokenId Token ID to burn.
*/
function burn(address _from, uint256 _tokenId) external;
/**
* @notice Initializes an ERC721 token with the provided args
*
* @param _bridge Address of the bridge on this network.
* @param _remoteChainId Chain ID where the remote token is deployed.
* @param _remoteToken Address of the corresponding token on the other network.
* @param _existence Existence status of the ERC721 token on this network.
* @param _native Nature of the ERC721 token on this network.
* @param _layerId Layer on which the token will be deployed.
*/
function initialize(
address _bridge,
uint256 _remoteChainId,
address _remoteToken,
Existence _existence,
bool _native,
uint256 _layerId
) external;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment