文件 1 的 28:Address.sol
pragma solidity ^0.7.3;
library Address {
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly {
size := extcodesize(account)
}
return size > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 2 的 28:Context.sol
pragma solidity ^0.7.3;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _txOrigin() internal view virtual returns (address) {
return tx.origin;
}
function _msgData() internal view virtual returns (bytes calldata) {
this;
return msg.data;
}
}
文件 3 的 28:ERC1155.sol
pragma solidity ^0.7.3;
import "./library/LibSafeMath.sol";
import "./library/LibAddress.sol";
import "./interface/IERC1155.sol";
import "./interface/IERC1155Receiver.sol";
import "./mixin/MixinNonFungibleToken.sol";
import "./mixin/MixinOwnable.sol";
import "./WhitelistExchangesProxy.sol";
contract ERC1155 is
IERC1155,
MixinNonFungibleToken,
Ownable
{
using LibAddress for address;
using LibSafeMath for uint256;
bytes4 constant public ERC1155_RECEIVED = 0xf23a6e61;
bytes4 constant public ERC1155_BATCH_RECEIVED = 0xbc197c81;
mapping (uint256 => mapping(address => uint256)) internal balances;
mapping (address => mapping(address => bool)) internal operatorApproval;
address public exchangesRegistry;
function setExchangesRegistry(address newExchangesRegistry) external onlyOwner() {
exchangesRegistry = newExchangesRegistry;
}
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 value,
bytes calldata data
)
override
external
{
require(
to != address(0x0),
"CANNOT_TRANSFER_TO_ADDRESS_ZERO"
);
require(
from == msg.sender || isApprovedForAll(from, msg.sender),
"INSUFFICIENT_ALLOWANCE"
);
if (isNonFungible(id)) {
require(
value == 1,
"AMOUNT_EQUAL_TO_ONE_REQUIRED"
);
require(
nfOwners[id] == from,
"NFT_NOT_OWNED_BY_FROM_ADDRESS"
);
nfOwners[id] = to;
} else {
balances[id][from] = balances[id][from].safeSub(value);
balances[id][to] = balances[id][to].safeAdd(value);
}
emit TransferSingle(msg.sender, from, to, id, value);
if (to.isContract()) {
bytes4 callbackReturnValue = IERC1155Receiver(to).onERC1155Received(
msg.sender,
from,
id,
value,
data
);
require(
callbackReturnValue == ERC1155_RECEIVED,
"BAD_RECEIVER_RETURN_VALUE"
);
}
}
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
)
override
external
{
require(
to != address(0x0),
"CANNOT_TRANSFER_TO_ADDRESS_ZERO"
);
require(
ids.length == values.length,
"TOKEN_AND_VALUES_LENGTH_MISMATCH"
);
require(
from == msg.sender || isApprovedForAll(from, msg.sender),
"INSUFFICIENT_ALLOWANCE"
);
for (uint256 i = 0; i < ids.length; ++i) {
uint256 id = ids[i];
uint256 value = values[i];
if (isNonFungible(id)) {
require(
value == 1,
"AMOUNT_EQUAL_TO_ONE_REQUIRED"
);
require(
nfOwners[id] == from,
"NFT_NOT_OWNED_BY_FROM_ADDRESS"
);
nfOwners[id] = to;
} else {
balances[id][from] = balances[id][from].safeSub(value);
balances[id][to] = balances[id][to].safeAdd(value);
}
}
emit TransferBatch(msg.sender, from, to, ids, values);
if (to.isContract()) {
bytes4 callbackReturnValue = IERC1155Receiver(to).onERC1155BatchReceived(
msg.sender,
from,
ids,
values,
data
);
require(
callbackReturnValue == ERC1155_BATCH_RECEIVED,
"BAD_RECEIVER_RETURN_VALUE"
);
}
}
function setApprovalForAll(address operator, bool approved) external override {
operatorApproval[msg.sender][operator] = approved;
emit ApprovalForAll(msg.sender, operator, approved);
}
function isApprovedForAll(address owner, address operator) public override view returns (bool) {
bool approved = operatorApproval[owner][operator];
if (!approved && exchangesRegistry != address(0)) {
return WhitelistExchangesProxy(exchangesRegistry).isAddressWhitelisted(operator) == true;
}
return approved;
}
function balanceOf(address owner, uint256 id) external override view returns (uint256) {
if (isNonFungibleItem(id)) {
return nfOwners[id] == owner ? 1 : 0;
}
return balances[id][owner];
}
function balanceOfBatch(address[] calldata owners, uint256[] calldata ids) external override view returns (uint256[] memory balances_) {
require(
owners.length == ids.length,
"OWNERS_AND_IDS_MUST_HAVE_SAME_LENGTH"
);
balances_ = new uint256[](owners.length);
for (uint256 i = 0; i < owners.length; ++i) {
uint256 id = ids[i];
if (isNonFungibleItem(id)) {
balances_[i] = nfOwners[id] == owners[i] ? 1 : 0;
} else {
balances_[i] = balances[id][owners[i]];
}
}
return balances_;
}
bytes4 constant private INTERFACE_SIGNATURE_ERC165 = 0x01ffc9a7;
bytes4 constant private INTERFACE_SIGNATURE_ERC1155 = 0xd9b67a26;
function supportsInterface(bytes4 _interfaceID) external view returns (bool) {
if (_interfaceID == INTERFACE_SIGNATURE_ERC165 ||
_interfaceID == INTERFACE_SIGNATURE_ERC1155) {
return true;
}
return false;
}
}
文件 4 的 28:ERC1155Mintable.sol
pragma solidity ^0.7.3;
import "./library/LibSafeMath.sol";
import "./library/LibAddress.sol";
import "./ERC1155.sol";
import "./interface/IERC1155Mintable.sol";
import "./mixin/MixinOwnable.sol";
import "./mixin/MixinContractURI.sol";
import "./mixin/MixinTokenURI.sol";
contract ERC1155Mintable is
IERC1155Mintable,
ERC1155,
MixinContractURI,
MixinTokenURI
{
using LibSafeMath for uint256;
using LibAddress for address;
uint256 internal nonce;
mapping (uint256 => uint256) public maxIndex;
mapping (uint256 => mapping(address => bool)) internal creatorApproval;
modifier onlyCreator(uint256 _id) {
require(creatorApproval[_id][msg.sender], "not an approved creator of id");
_;
}
function setCreatorApproval(uint256 id, address creator, bool status) external onlyCreator(id) {
creatorApproval[id][creator] = status;
}
function create(
bool isNF
)
external
override
onlyOwner()
returns (uint256 type_)
{
type_ = (++nonce << 128);
if (isNF) {
type_ = type_ | TYPE_NF_BIT;
}
creatorApproval[type_][msg.sender] = true;
emit TransferSingle(
msg.sender,
address(0x0),
address(0x0),
type_,
0
);
emit URI(uri(type_), type_);
}
function createWithType(
uint256 type_
)
external
onlyOwner()
{
creatorApproval[type_][msg.sender] = true;
emit TransferSingle(
msg.sender,
address(0x0),
address(0x0),
type_,
0
);
emit URI(uri(type_), type_);
}
function mintFungible(
uint256 id,
address[] calldata to,
uint256[] calldata quantities
)
external
override
onlyCreator(id)
{
require(
isFungible(id),
"TRIED_TO_MINT_FUNGIBLE_FOR_NON_FUNGIBLE_TOKEN"
);
for (uint256 i = 0; i < to.length; ++i) {
address dst = to[i];
uint256 quantity = quantities[i];
balances[id][dst] = quantity.safeAdd(balances[id][dst]);
emit TransferSingle(
msg.sender,
address(0x0),
dst,
id,
quantity
);
if (dst.isContract()) {
bytes4 callbackReturnValue = IERC1155Receiver(dst).onERC1155Received(
msg.sender,
msg.sender,
id,
quantity,
""
);
require(
callbackReturnValue == ERC1155_RECEIVED,
"BAD_RECEIVER_RETURN_VALUE"
);
}
}
}
function mintNonFungible(
uint256 type_,
address[] calldata to
)
external
override
onlyCreator(type_)
{
require(
isNonFungible(type_),
"TRIED_TO_MINT_NON_FUNGIBLE_FOR_FUNGIBLE_TOKEN"
);
uint256 index = maxIndex[type_] + 1;
for (uint256 i = 0; i < to.length; ++i) {
address dst = to[i];
uint256 id = type_ | index + i;
nfOwners[id] = dst;
balances[type_][dst] = balances[type_][dst].safeAdd(1);
emit TransferSingle(msg.sender, address(0x0), dst, id, 1);
if (dst.isContract()) {
bytes4 callbackReturnValue = IERC1155Receiver(dst).onERC1155Received(
msg.sender,
msg.sender,
id,
1,
""
);
require(
callbackReturnValue == ERC1155_RECEIVED,
"BAD_RECEIVER_RETURN_VALUE"
);
}
}
maxIndex[type_] = to.length.safeAdd(maxIndex[type_]);
}
}
文件 5 的 28:ERC165.sol
pragma solidity ^0.7.3;
import "./interface/IERC165.sol";
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
文件 6 的 28:ERC721.sol
pragma solidity ^0.7.3;
import "./interface/IERC721.sol";
import "./interface/IERC721Receiver.sol";
import "./interface/IERC721Metadata.sol";
import "./utils/Address.sol";
import "./utils/Context.sol";
import "./utils/Strings.sol";
import "./ERC165.sol";
contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
using Address for address;
using Strings for uint256;
string private _name;
string private _symbol;
mapping(uint256 => address) private _owners;
mapping(address => uint256) private _balances;
mapping(uint256 => address) private _tokenApprovals;
mapping(address => mapping(address => bool)) private _operatorApprovals;
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC721).interfaceId ||
interfaceId == type(IERC721Metadata).interfaceId ||
super.supportsInterface(interfaceId);
}
function balanceOf(address owner) public view virtual override returns (uint256) {
require(owner != address(0), "ERC721: balance query for the zero address");
return _balances[owner];
}
function ownerOf(uint256 tokenId) public view virtual override returns (address) {
address owner = _owners[tokenId];
require(owner != address(0), "ERC721: owner query for nonexistent token");
return owner;
}
function name() public view virtual override returns (string memory) {
return _name;
}
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
string memory baseURI = _baseURI();
return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
}
function _baseURI() internal view virtual returns (string memory) {
return "";
}
function approve(address to, uint256 tokenId) public virtual override {
address owner = ERC721.ownerOf(tokenId);
require(to != owner, "ERC721: approval to current owner");
require(
_msgSender() == owner || isApprovedForAll(owner, _msgSender()),
"ERC721: approve caller is not owner nor approved for all"
);
_approve(to, tokenId);
}
function getApproved(uint256 tokenId) public view virtual override returns (address) {
require(_exists(tokenId), "ERC721: approved query for nonexistent token");
return _tokenApprovals[tokenId];
}
function setApprovalForAll(address operator, bool approved) public virtual override {
require(operator != _msgSender(), "ERC721: approve to caller");
_operatorApprovals[_msgSender()][operator] = approved;
emit ApprovalForAll(_msgSender(), operator, approved);
}
function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
return _operatorApprovals[owner][operator];
}
function transferFrom(
address from,
address to,
uint256 tokenId
) public virtual override {
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
_transfer(from, to, tokenId);
}
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) public virtual override {
safeTransferFrom(from, to, tokenId, "");
}
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes memory _data
) public virtual override {
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
_safeTransfer(from, to, tokenId, _data);
}
function _safeTransfer(
address from,
address to,
uint256 tokenId,
bytes memory _data
) internal virtual {
_transfer(from, to, tokenId);
require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
}
function _exists(uint256 tokenId) internal view virtual returns (bool) {
return _owners[tokenId] != address(0);
}
function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
require(_exists(tokenId), "ERC721: operator query for nonexistent token");
address owner = ERC721.ownerOf(tokenId);
return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
}
function _safeMint(address to, uint256 tokenId) internal virtual {
_safeMint(to, tokenId, "");
}
function _safeMint(
address to,
uint256 tokenId,
bytes memory _data
) internal virtual {
_mint(to, tokenId);
require(
_checkOnERC721Received(address(0), to, tokenId, _data),
"ERC721: transfer to non ERC721Receiver implementer"
);
}
function _mint(address to, uint256 tokenId) internal virtual {
require(to != address(0), "ERC721: mint to the zero address");
require(!_exists(tokenId), "ERC721: token already minted");
_beforeTokenTransfer(address(0), to, tokenId);
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(address(0), to, tokenId);
}
function _burn(uint256 tokenId) internal virtual {
address owner = ERC721.ownerOf(tokenId);
_beforeTokenTransfer(owner, address(0), tokenId);
_approve(address(0), tokenId);
_balances[owner] -= 1;
delete _owners[tokenId];
emit Transfer(owner, address(0), tokenId);
}
function _transfer(
address from,
address to,
uint256 tokenId
) internal virtual {
require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
require(to != address(0), "ERC721: transfer to the zero address");
_beforeTokenTransfer(from, to, tokenId);
_approve(address(0), tokenId);
_balances[from] -= 1;
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(from, to, tokenId);
}
function _approve(address to, uint256 tokenId) internal virtual {
_tokenApprovals[tokenId] = to;
emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
}
function _setApprovalForAll(address to, address operator, bool approved) internal virtual {
_operatorApprovals[to][operator] = approved;
emit ApprovalForAll(to, operator, approved);
}
function _checkOnERC721Received(
address from,
address to,
uint256 tokenId,
bytes memory _data
) private returns (bool) {
if (to.isContract()) {
try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {
return retval == IERC721Receiver.onERC721Received.selector;
} catch (bytes memory reason) {
if (reason.length == 0) {
revert("ERC721: transfer to non ERC721Receiver implementer");
} else {
assembly {
revert(add(32, reason), mload(reason))
}
}
}
} else {
return true;
}
}
function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId
) internal virtual {}
}
文件 7 的 28:HashBaseV2.sol
pragma solidity ^0.7.3;
import "./ERC721.sol";
import "./WhitelistExchangesProxy.sol";
import "./mixin/MixinOwnable.sol";
contract HashBaseV2 is Ownable, ERC721 {
string public baseMetadataURI;
string public contractURI;
constructor (
string memory name_,
string memory symbol_
) ERC721(name_, symbol_) {
}
function setBaseMetadataURI(string memory _baseMetadataURI) public onlyOwner {
baseMetadataURI = _baseMetadataURI;
}
function setContractURI(string calldata newContractURI) external onlyOwner {
contractURI = newContractURI;
}
function _baseURI() override internal view virtual returns (string memory) {
return baseMetadataURI;
}
}
文件 8 的 28:HashRegistry.sol
pragma solidity ^0.7.3;
import "./library/LibSafeMath.sol";
import "./ERC1155Mintable.sol";
import "./mixin/MixinOwnable.sol";
contract HashRegistry is Ownable {
using LibSafeMath for uint256;
ERC1155Mintable public mintableErc1155;
mapping(uint256 => uint256) public tokenIdToTxHash;
mapping(uint256 => uint256) public txHashToTokenId;
mapping(address => bool) public permissedWriters;
constructor(
address _mintableErc1155
) {
permissedWriters[msg.sender] = true;
mintableErc1155 = ERC1155Mintable(_mintableErc1155);
}
event UpdatedRegistry(
uint256 tokenId,
uint256 txHash
);
modifier onlyIfPermissed(address writer) {
require(permissedWriters[writer] == true, "writer can't write to registry");
_;
}
function updatePermissedWriterStatus(address _writer, bool status) public onlyIfPermissed(msg.sender) {
permissedWriters[_writer] = status;
}
function writeToRegistry(uint256[] memory tokenIds, uint256[] memory txHashes) public onlyIfPermissed(msg.sender) {
require(tokenIds.length == txHashes.length, "tokenIds and txHashes size mismatch");
for (uint256 i = 0; i < tokenIds.length; ++i) {
uint256 tokenId = tokenIds[i];
uint256 txHash = txHashes[i];
require(mintableErc1155.ownerOf(tokenId) != address(0), 'token does not exist');
require(txHashToTokenId[txHash] == 0, 'txHash already exists');
require(tokenIdToTxHash[tokenId] == 0, 'tokenId already exists');
tokenIdToTxHash[tokenId] = txHash;
txHashToTokenId[txHash] = tokenId;
emit UpdatedRegistry(tokenId, txHash);
}
}
}
文件 9 的 28:HashRegistryV2.sol
pragma solidity ^0.7.3;
pragma experimental ABIEncoderV2;
import "./library/LibSafeMath.sol";
import "./mixin/MixinOwnable.sol";
import "./ERC721.sol";
import "./mixin/MixinOwnable.sol";
import "./HashRegistry.sol";
import "./ERC1155Mintable.sol";
import "./HashV2.sol";
contract HashRegistryV2 is Ownable {
uint256 constant internal TYPE_MASK = uint256(uint128(~0)) << 128;
HashV2 public immutable hashV2;
ERC1155Mintable public immutable originalHash;
HashRegistry public immutable originalHashRegistry;
mapping(uint256 => uint256) private tokenIdToTxHash_;
mapping(uint256 => uint256) private txHashToTokenId_;
mapping(address => bool) public permissedWriters;
constructor(
address originalHashRegistry_,
address originalHash_,
address hashV2_
) {
originalHashRegistry = HashRegistry(originalHashRegistry_);
originalHash = ERC1155Mintable(originalHash_);
hashV2 = HashV2(hashV2_);
}
event UpdatedRegistry(
uint256 tokenId,
uint256 txHash
);
modifier onlyIfPermissed(address writer) {
require(permissedWriters[writer] == true, "writer can't write to registry");
_;
}
function updatePermissedWriterStatus(address _writer, bool status) public onlyOwner {
permissedWriters[_writer] = status;
}
function writeToRegistry(uint256[] memory tokenIds, uint256[] memory txHashes) public onlyIfPermissed(msg.sender) {
require(tokenIds.length == txHashes.length, "tokenIds and txHashes size mismatch");
for (uint256 i = 0; i < tokenIds.length; ++i) {
uint256 tokenId = tokenIds[i];
uint256 txHash = txHashes[i];
require(txHashToTokenId_[txHash] == 0, 'txHash already exists');
require(tokenIdToTxHash_[tokenId] == 0, 'tokenId already exists');
tokenIdToTxHash_[tokenId] = txHash;
txHashToTokenId_[txHash] = tokenId;
emit UpdatedRegistry(tokenId, txHash);
}
}
function tokenIdToTxHash(uint id) public view returns (uint256) {
if (tokenIdToTxHash_[id] == 0 && originalHashRegistry.tokenIdToTxHash(id) != 0) {
return originalHashRegistry.tokenIdToTxHash(id);
}
return tokenIdToTxHash_[id];
}
function txHashToTokenId(uint txHash) public view returns (uint256) {
if (txHashToTokenId_[txHash] == 0 && originalHashRegistry.txHashToTokenId(txHash) != 0) {
return originalHashRegistry.txHashToTokenId(txHash);
}
return txHashToTokenId_[txHash];
}
function _getNonFungibleBaseType(uint256 id) pure internal returns (uint256) {
return id & TYPE_MASK;
}
function isMigrated(uint id) public view returns (bool) {
uint tokenType = _getNonFungibleBaseType(id);
try hashV2.ownerOf(id) returns (address owner) {
return owner != address(0) && (originalHash.ownerOf(id) == address(0xdead));
}
catch (bytes memory _err) {
return false;
}
}
function ownerOf(uint id) public view returns (address) {
uint tokenType = _getNonFungibleBaseType(id);
address oldOwner = originalHash.ownerOf(id);
try hashV2.ownerOf(id) returns (address owner) {
if (owner == address(0) && oldOwner != address(0)) {
return oldOwner;
}
return owner;
}
catch (bytes memory _err) {
return oldOwner;
}
}
function ownerOfByTxHash(uint txHash) public view returns (address) {
uint id = txHashToTokenId(txHash);
return ownerOf(id);
}
}
文件 10 的 28:HashV2.sol
pragma solidity ^0.7.3;
import "./ERC721.sol";
import "./mixin/MixinOwnable.sol";
import "./HashBaseV2.sol";
import "./HashRegistryV2.sol";
import "./ERC1155Mintable.sol";
contract HashV2 is HashBaseV2 {
uint256 constant internal TYPE_MASK = uint256(uint128(~0)) << 128;
HashRegistryV2 public hashRegistry;
ERC1155Mintable public immutable originalHash;
mapping(uint => uint) public tokenTypeToSupply;
mapping(uint => uint) public tokenTypeToMaxSupply;
mapping(address => bool) public minters;
constructor (
string memory name_,
string memory symbol_,
address originalHash_
) HashBaseV2(name_, symbol_) {
originalHash = ERC1155Mintable(originalHash_);
}
modifier onlyMinter() {
require(minters[msg.sender] == true, "msg.sender is not minter");
_;
}
function _getNonFungibleBaseType(uint256 id) pure internal returns (uint256) {
return id & TYPE_MASK;
}
modifier onlyUnderMaxSupply(uint tokenType, uint mintAmount) {
require(tokenTypeToSupply[tokenType] + mintAmount <= tokenTypeToMaxSupply[tokenType], 'max supply minted');
_;
}
function setHashRegistry(address _hashRegistry) public onlyOwner {
hashRegistry = HashRegistryV2(_hashRegistry);
}
function setMinterStatus(address _minter, bool status) public onlyOwner {
minters[_minter] = status;
}
function createNewSeason(uint _tokenType, uint maxSupply) public onlyOwner {
require(tokenTypeToMaxSupply[_tokenType] == 0, "can't modify already created season");
tokenTypeToMaxSupply[_tokenType] = maxSupply;
}
function mintAndApprove(address to, uint tokenType, uint[] calldata txHashes, address[] calldata operators) public onlyMinter onlyUnderMaxSupply(tokenType, txHashes.length) {
uint256[] memory tokenIds = new uint256[](txHashes.length);
for (uint256 i = 0; i < txHashes.length; ++i) {
uint256 index = tokenTypeToSupply[tokenType] + 1 + i;
uint256 tokenId = tokenType | index;
tokenIds[i] = tokenId;
_safeMint(to, tokenId);
}
hashRegistry.writeToRegistry(tokenIds, txHashes);
tokenTypeToSupply[tokenType] = tokenTypeToSupply[tokenType] + txHashes.length;
for (uint i = 0; i < operators.length; ++i) {
_setApprovalForAll(to, operators[i], true);
}
}
function migrateAndApprove(address to, uint[] calldata ids, address[] calldata operators) public {
for (uint i = 0; i < ids.length; ++i) {
originalHash.safeTransferFrom(to, address(0xdead), ids[i], 1, "");
_safeMint(to, ids[i]);
}
for (uint i = 0; i < operators.length; ++i) {
_setApprovalForAll(to, operators[i], true);
}
}
}
文件 11 的 28:IERC1155.sol
pragma solidity ^0.7.3;
interface IERC1155 {
event TransferSingle(
address indexed _operator,
address indexed _from,
address indexed _to,
uint256 _id,
uint256 _value
);
event TransferBatch(
address indexed _operator,
address indexed _from,
address indexed _to,
uint256[] _ids,
uint256[] _values
);
event ApprovalForAll(
address indexed _owner,
address indexed _operator,
bool _approved
);
event URI(
string _value,
uint256 indexed _id
);
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 value,
bytes calldata data
)
external;
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
)
external;
function setApprovalForAll(address operator, bool approved) external;
function isApprovedForAll(address owner, address operator) external view returns (bool);
function balanceOf(address owner, uint256 id) external view returns (uint256);
function balanceOfBatch(
address[] calldata owners,
uint256[] calldata ids
)
external
view
returns (uint256[] memory balances_);
}
文件 12 的 28:IERC1155Mintable.sol
pragma solidity ^0.7.3;
import "./IERC1155.sol";
interface IERC1155Mintable is
IERC1155
{
function create(
bool isNF
)
external
returns (uint256 type_);
function mintFungible(
uint256 id,
address[] calldata to,
uint256[] calldata quantities
)
external;
function mintNonFungible(
uint256 type_,
address[] calldata to
)
external;
}
文件 13 的 28:IERC1155Receiver.sol
pragma solidity ^0.7.3;
interface IERC1155Receiver {
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
)
external
returns(bytes4);
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
)
external
returns(bytes4);
}
文件 14 的 28:IERC165.sol
pragma solidity ^0.7.3;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 15 的 28:IERC721.sol
pragma solidity ^0.7.3;
import "./IERC165.sol";
interface IERC721 is IERC165 {
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
function balanceOf(address owner) external view returns (uint256 balance);
function ownerOf(uint256 tokenId) external view returns (address owner);
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external;
function transferFrom(
address from,
address to,
uint256 tokenId
) external;
function approve(address to, uint256 tokenId) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function setApprovalForAll(address operator, bool _approved) external;
function isApprovedForAll(address owner, address operator) external view returns (bool);
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external;
}
文件 16 的 28:IERC721Metadata.sol
pragma solidity ^0.7.3;
import "./IERC721.sol";
interface IERC721Metadata is IERC721 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function tokenURI(uint256 tokenId) external view returns (string memory);
}
文件 17 的 28:IERC721Receiver.sol
pragma solidity ^0.7.3;
interface IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
文件 18 的 28:LibAddress.sol
pragma solidity ^0.7.3;
library LibAddress {
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly { size := extcodesize(account) }
return size > 0;
}
}
文件 19 的 28:LibRichErrors.sol
pragma solidity ^0.7.3;
library LibRichErrors {
bytes4 internal constant STANDARD_ERROR_SELECTOR =
0x08c379a0;
function StandardError(
string memory message
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
STANDARD_ERROR_SELECTOR,
bytes(message)
);
}
function rrevert(bytes memory errorData)
internal
pure
{
assembly {
revert(add(errorData, 0x20), mload(errorData))
}
}
}
文件 20 的 28:LibSafeMath.sol
pragma solidity ^0.7.3;
import "./LibRichErrors.sol";
import "./LibSafeMathRichErrors.sol";
library LibSafeMath {
function safeMul(uint256 a, uint256 b)
internal
pure
returns (uint256)
{
if (a == 0) {
return 0;
}
uint256 c = a * b;
if (c / a != b) {
LibRichErrors.rrevert(LibSafeMathRichErrors.Uint256BinOpError(
LibSafeMathRichErrors.BinOpErrorCodes.MULTIPLICATION_OVERFLOW,
a,
b
));
}
return c;
}
function safeDiv(uint256 a, uint256 b)
internal
pure
returns (uint256)
{
if (b == 0) {
LibRichErrors.rrevert(LibSafeMathRichErrors.Uint256BinOpError(
LibSafeMathRichErrors.BinOpErrorCodes.DIVISION_BY_ZERO,
a,
b
));
}
uint256 c = a / b;
return c;
}
function safeSub(uint256 a, uint256 b)
internal
pure
returns (uint256)
{
if (b > a) {
LibRichErrors.rrevert(LibSafeMathRichErrors.Uint256BinOpError(
LibSafeMathRichErrors.BinOpErrorCodes.SUBTRACTION_UNDERFLOW,
a,
b
));
}
return a - b;
}
function safeAdd(uint256 a, uint256 b)
internal
pure
returns (uint256)
{
uint256 c = a + b;
if (c < a) {
LibRichErrors.rrevert(LibSafeMathRichErrors.Uint256BinOpError(
LibSafeMathRichErrors.BinOpErrorCodes.ADDITION_OVERFLOW,
a,
b
));
}
return c;
}
function max256(uint256 a, uint256 b)
internal
pure
returns (uint256)
{
return a >= b ? a : b;
}
function min256(uint256 a, uint256 b)
internal
pure
returns (uint256)
{
return a < b ? a : b;
}
}
文件 21 的 28:LibSafeMathRichErrors.sol
pragma solidity ^0.7.3;
library LibSafeMathRichErrors {
bytes4 internal constant UINT256_BINOP_ERROR_SELECTOR =
0xe946c1bb;
bytes4 internal constant UINT256_DOWNCAST_ERROR_SELECTOR =
0xc996af7b;
enum BinOpErrorCodes {
ADDITION_OVERFLOW,
MULTIPLICATION_OVERFLOW,
SUBTRACTION_UNDERFLOW,
DIVISION_BY_ZERO
}
enum DowncastErrorCodes {
VALUE_TOO_LARGE_TO_DOWNCAST_TO_UINT32,
VALUE_TOO_LARGE_TO_DOWNCAST_TO_UINT64,
VALUE_TOO_LARGE_TO_DOWNCAST_TO_UINT96
}
function Uint256BinOpError(
BinOpErrorCodes errorCode,
uint256 a,
uint256 b
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
UINT256_BINOP_ERROR_SELECTOR,
errorCode,
a,
b
);
}
function Uint256DowncastError(
DowncastErrorCodes errorCode,
uint256 a
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
UINT256_DOWNCAST_ERROR_SELECTOR,
errorCode,
a
);
}
}
文件 22 的 28:LibString.sol
pragma solidity ^0.7.3;
library LibString {
function strConcat(string memory _a, string memory _b, string memory _c, string memory _d, string memory _e) internal pure returns (string memory) {
bytes memory _ba = bytes(_a);
bytes memory _bb = bytes(_b);
bytes memory _bc = bytes(_c);
bytes memory _bd = bytes(_d);
bytes memory _be = bytes(_e);
string memory abcde = new string(_ba.length + _bb.length + _bc.length + _bd.length + _be.length);
bytes memory babcde = bytes(abcde);
uint k = 0;
for (uint i = 0; i < _ba.length; i++) babcde[k++] = _ba[i];
for (uint i = 0; i < _bb.length; i++) babcde[k++] = _bb[i];
for (uint i = 0; i < _bc.length; i++) babcde[k++] = _bc[i];
for (uint i = 0; i < _bd.length; i++) babcde[k++] = _bd[i];
for (uint i = 0; i < _be.length; i++) babcde[k++] = _be[i];
return string(babcde);
}
function strConcat(string memory _a, string memory _b, string memory _c, string memory _d) internal pure returns (string memory) {
return strConcat(_a, _b, _c, _d, "");
}
function strConcat(string memory _a, string memory _b, string memory _c) internal pure returns (string memory) {
return strConcat(_a, _b, _c, "", "");
}
function strConcat(string memory _a, string memory _b) internal pure returns (string memory) {
return strConcat(_a, _b, "", "", "");
}
function uint2str(uint _i) internal pure returns (string memory _uintAsString) {
if (_i == 0) {
return "0";
}
uint j = _i;
uint len;
while (j != 0) {
len++;
j /= 10;
}
bytes memory bstr = new bytes(len);
uint k = len - 1;
while (_i != 0) {
bstr[k--] = byte(uint8(48 + _i % 10));
_i /= 10;
}
return string(bstr);
}
function uint2hexstr(uint i) internal pure returns (string memory) {
if (i == 0) {
return "0";
}
uint j = i;
uint len;
while (j != 0) {
len++;
j = j >> 4;
}
uint mask = 15;
bytes memory bstr = new bytes(len);
uint k = len - 1;
while (i != 0){
uint curr = (i & mask);
bstr[k--] = curr > 9 ? byte(uint8(55 + curr)) : byte(uint8(48 + curr));
i = i >> 4;
}
return string(bstr);
}
}
文件 23 的 28:MixinContractURI.sol
pragma solidity ^0.7.3;
import "./MixinOwnable.sol";
contract MixinContractURI is Ownable {
string public contractURI;
function setContractURI(string calldata newContractURI) external onlyOwner() {
contractURI = newContractURI;
}
}
文件 24 的 28:MixinNonFungibleToken.sol
pragma solidity ^0.7.3;
contract MixinNonFungibleToken {
uint256 constant internal TYPE_MASK = uint256(uint128(~0)) << 128;
uint256 constant internal NF_INDEX_MASK = uint128(~0);
uint256 constant internal TYPE_NF_BIT = 1 << 255;
mapping (uint256 => address) internal nfOwners;
function isNonFungible(uint256 id) public pure returns(bool) {
return id & TYPE_NF_BIT == TYPE_NF_BIT;
}
function isFungible(uint256 id) public pure returns(bool) {
return id & TYPE_NF_BIT == 0;
}
function getNonFungibleIndex(uint256 id) public pure returns(uint256) {
return id & NF_INDEX_MASK;
}
function getNonFungibleBaseType(uint256 id) public pure returns(uint256) {
return id & TYPE_MASK;
}
function isNonFungibleBaseType(uint256 id) public pure returns(bool) {
return (id & TYPE_NF_BIT == TYPE_NF_BIT) && (id & NF_INDEX_MASK == 0);
}
function isNonFungibleItem(uint256 id) public pure returns(bool) {
return (id & TYPE_NF_BIT == TYPE_NF_BIT) && (id & NF_INDEX_MASK != 0);
}
function ownerOf(uint256 id) public view returns (address) {
return nfOwners[id];
}
}
文件 25 的 28:MixinOwnable.sol
pragma solidity ^0.7.3;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor () {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
function owner() public view returns (address) {
return _owner;
}
modifier onlyOwner() {
require(_owner == _msgSender(), "Ownable: caller is not the owner");
_;
}
function renounceOwnership() public onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
function transferOwnership(address newOwner) public onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
文件 26 的 28:MixinTokenURI.sol
pragma solidity ^0.7.3;
import "./MixinOwnable.sol";
import "../library/LibString.sol";
contract MixinTokenURI is Ownable {
using LibString for string;
string public baseMetadataURI = "";
function setBaseMetadataURI(string memory newBaseMetadataURI) public onlyOwner() {
baseMetadataURI = newBaseMetadataURI;
}
function uri(uint256 _id) public view returns (string memory) {
return LibString.strConcat(
baseMetadataURI,
LibString.uint2hexstr(_id)
);
}
}
文件 27 的 28:Strings.sol
pragma solidity ^0.7.3;
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
function toString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
}
文件 28 的 28:WhitelistExchangesProxy.sol
pragma solidity ^0.7.3;
import "./mixin/MixinOwnable.sol";
contract WhitelistExchangesProxy is Ownable {
mapping(address => bool) internal proxies;
bool public paused = true;
function setPaused(bool newPaused) external onlyOwner() {
paused = newPaused;
}
function updateProxyAddress(address proxy, bool status) external onlyOwner() {
proxies[proxy] = status;
}
function isAddressWhitelisted(address proxy) external view returns (bool) {
if (paused) {
return false;
} else {
return proxies[proxy];
}
}
}
{
"compilationTarget": {
"contracts/HashV2.sol": "HashV2"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"address","name":"originalHash_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseMetadataURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenType","type":"uint256"},{"internalType":"uint256","name":"maxSupply","type":"uint256"}],"name":"createNewSeason","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hashRegistry","outputs":[{"internalType":"contract HashRegistryV2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"address[]","name":"operators","type":"address[]"}],"name":"migrateAndApprove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenType","type":"uint256"},{"internalType":"uint256[]","name":"txHashes","type":"uint256[]"},{"internalType":"address[]","name":"operators","type":"address[]"}],"name":"mintAndApprove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"minters","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"originalHash","outputs":[{"internalType":"contract ERC1155Mintable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseMetadataURI","type":"string"}],"name":"setBaseMetadataURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newContractURI","type":"string"}],"name":"setContractURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_hashRegistry","type":"address"}],"name":"setHashRegistry","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_minter","type":"address"},{"internalType":"bool","name":"status","type":"bool"}],"name":"setMinterStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenTypeToMaxSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenTypeToSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]