// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)pragmasolidity ^0.8.0;/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/abstractcontractContext{
function_msgSender() internalviewvirtualreturns (address) {
returnmsg.sender;
}
function_msgData() internalviewvirtualreturns (bytescalldata) {
returnmsg.data;
}
function_contextSuffixLength() internalviewvirtualreturns (uint256) {
return0;
}
}
Contract Source Code
File 5 of 20: ERC721.sol
pragmasolidity =0.8.6;// SPDX-License-Identifier: SimPL-2.0import"./IERC165.sol";
import"./IERC721.sol";
import"./IERC721Metadata.sol";
import"./IERC721TokenReceiver.sol";
import"./Util.sol";
abstractcontractERC721isIERC165, IERC721, IERC721Metadata{
/*
* bytes4(keccak256("supportsInterface(bytes4)")) == 0x01ffc9a7
*/bytes4privateconstant INTERFACE_ID_ERC165 =0x01ffc9a7;
/*
* bytes4(keccak256("balanceOf(address)")) == 0x70a08231
* bytes4(keccak256("ownerOf(uint256)")) == 0x6352211e
* bytes4(keccak256("approve(address,uint256)")) == 0x095ea7b3
* bytes4(keccak256("getApproved(uint256)")) == 0x081812fc
* bytes4(keccak256("setApprovalForAll(address,bool)")) == 0xa22cb465
* bytes4(keccak256("isApprovedForAll(address,address)")) == 0xe985e9c5
* bytes4(keccak256("transferFrom(address,address,uint256)")) == 0x23b872dd
* bytes4(keccak256("safeTransferFrom(address,address,uint256)")) == 0x42842e0e
* bytes4(keccak256("safeTransferFrom(address,address,uint256,bytes)")) == 0xb88d4fde
*
* => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^
* 0xa22cb465 ^ 0xe985e9c ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd
*/bytes4privateconstant INTERFACE_ID_ERC721 =0x80ac58cd;
bytes4privateconstant INTERFACE_ID_ERC721Metadata =0x5b5e139f;
stringpublicoverride name;
stringpublicoverride symbol;
mapping(address=>uint256[]) internal ownerTokens;
mapping(uint256=>uint256) internal tokenIndexs;
mapping(uint256=>address) internal tokenOwners;
mapping(uint256=>address) internal tokenApprovals;
mapping(address=>mapping(address=>bool)) internal approvalForAlls;
constructor(stringmemory _name, stringmemory _symbol) {
name = _name;
symbol = _symbol;
}
functionbalanceOf(address owner) externalviewoverridereturns (uint256) {
require(owner !=address(0), "owner is zero address");
return ownerTokens[owner].length;
}
// [startIndex, endIndex)functiontokensOf(address owner,
uint256 startIndex,
uint256 endIndex
) externalviewreturns (uint256[] memory) {
require(owner !=address(0), "owner is zero address");
uint256[] storage tokens = ownerTokens[owner];
if (endIndex ==0) {
endIndex = tokens.length;
}
uint256[] memory result =newuint256[](endIndex - startIndex);
for (uint256 i = startIndex; i < endIndex; ++i) {
result[i - startIndex] = tokens[i];
}
return result;
}
functionownerOf(uint256 tokenId) externalviewoverridereturns (address) {
address owner = tokenOwners[tokenId];
require(owner !=address(0), "nobody own the token");
return owner;
}
functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId
) externalpayableoverride{
safeTransferFrom(from, to, tokenId, "");
}
functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId,
bytesmemory data
) publicpayableoverride{
_transferFrom(from, to, tokenId);
if (to.code.length>0) {
require(
IERC721TokenReceiver(to).onERC721Received(
msg.sender,
from,
tokenId,
data
) == IERC721TokenReceiver.onERC721Received.selector,
"onERC721Received() return invalid"
);
}
}
functiontransferFrom(addressfrom,
address to,
uint256 tokenId
) externalpayableoverride{
_transferFrom(from, to, tokenId);
}
function_transferFrom(addressfrom, address to, uint256 tokenId) internal{
require(from!=address(0), "from is zero address");
require(to !=address(0), "to is zero address");
require(from== tokenOwners[tokenId], "from must be owner");
require(
msg.sender==from||msg.sender== tokenApprovals[tokenId] ||
approvalForAlls[from][msg.sender],
"sender must be owner or approvaled"
);
if (tokenApprovals[tokenId] !=address(0)) {
delete tokenApprovals[tokenId];
}
_removeTokenFrom(from, tokenId);
_addTokenTo(to, tokenId);
emit Transfer(from, to, tokenId);
}
// ensure everything is ok before call itfunction_removeTokenFrom(addressfrom, uint256 tokenId) internal{
uint256 index = tokenIndexs[tokenId];
uint256[] storage tokens = ownerTokens[from];
uint256 indexLast = tokens.length-1;
// save gas// if (index != indexLast) {uint256 tokenIdLast = tokens[indexLast];
tokens[index] = tokenIdLast;
tokenIndexs[tokenIdLast] = index;
// }
tokens.pop();
// delete tokenIndexs[tokenId]; // save gasdelete tokenOwners[tokenId];
}
// ensure everything is ok before call itfunction_addTokenTo(address to, uint256 tokenId) internal{
uint256[] storage tokens = ownerTokens[to];
tokenIndexs[tokenId] = tokens.length;
tokens.push(tokenId);
tokenOwners[tokenId] = to;
}
functionapprove(address to, uint256 tokenId) externalpayableoverride{
address owner = tokenOwners[tokenId];
require(
msg.sender== owner || approvalForAlls[owner][msg.sender],
"sender must be owner or approved for all"
);
tokenApprovals[tokenId] = to;
emit Approval(owner, to, tokenId);
}
functionsetApprovalForAll(address to, bool approved) externaloverride{
approvalForAlls[msg.sender][to] = approved;
emit ApprovalForAll(msg.sender, to, approved);
}
functiongetApproved(uint256 tokenId
) externalviewoverridereturns (address) {
require(tokenOwners[tokenId] !=address(0), "nobody own then token");
return tokenApprovals[tokenId];
}
functionisApprovedForAll(address owner,
address operator
) externalviewoverridereturns (bool) {
return approvalForAlls[owner][operator];
}
functionsupportsInterface(bytes4 interfaceID
) externalpureoverridereturns (bool) {
return
interfaceID == INTERFACE_ID_ERC165 ||
interfaceID == INTERFACE_ID_ERC721 ||
interfaceID == INTERFACE_ID_ERC721Metadata;
}
}
Contract Source Code
File 6 of 20: ERC721Ex.sol
pragmasolidity =0.8.6;// SPDX-License-Identifier: SimPL-2.0import"./IERC721TokenReceiverEx.sol";
import"./String.sol";
import"./Util.sol";
import"./ERC721.sol";
import"./Member.sol";
abstractcontractERC721ExisERC721, Member{
usingStringforstring;
uint256public totalSupply =0;
stringpublic uriPrefix;
function_mint(address to, uint256 tokenId) internal{
_addTokenTo(to, tokenId);
++totalSupply;
emit Transfer(address(0), to, tokenId);
}
function_burn(uint256 tokenId) internal{
address owner = tokenOwners[tokenId];
_removeTokenFrom(owner, tokenId);
if (tokenApprovals[tokenId] !=address(0)) {
delete tokenApprovals[tokenId];
}
emit Transfer(owner, address(0), tokenId);
}
functionsafeBatchTransferFrom(addressfrom,
address to,
uint256[] memory tokenIds
) external{
safeBatchTransferFrom(from, to, tokenIds, "");
}
functionsafeBatchTransferFrom(addressfrom,
address to,
uint256[] memory tokenIds,
bytesmemory data
) public{
batchTransferFrom(from, to, tokenIds);
if (to.code.length>0) {
require(
IERC721TokenReceiverEx(to).onERC721ExReceived(
msg.sender,
from,
tokenIds,
data
) == IERC721TokenReceiverEx.onERC721ExReceived.selector,
"onERC721ExReceived() return invalid"
);
}
}
functionbatchTransferFrom(addressfrom,
address to,
uint256[] memory tokenIds
) public{
require(from!=address(0), "from is zero address");
require(to !=address(0), "to is zero address");
address sender =msg.sender;
bool approval =from== sender || approvalForAlls[from][sender];
for (uint256 i =0; i < tokenIds.length; ++i) {
uint256 tokenId = tokenIds[i];
require(from== tokenOwners[tokenId], "from must be owner");
require(
approval || sender == tokenApprovals[tokenId],
"sender must be owner or approvaled"
);
if (tokenApprovals[tokenId] !=address(0)) {
delete tokenApprovals[tokenId];
}
_removeTokenFrom(from, tokenId);
_addTokenTo(to, tokenId);
emit Transfer(from, to, tokenId);
}
}
functionsetUriPrefix(stringmemory prefix) externalonlyOwner{
uriPrefix = prefix;
}
functiontokenURI(uint256 cardId
) externalviewvirtualoverridereturns (stringmemory) {
bytesmemory bs =abi.encodePacked(cardId);
return uriPrefix.concat(Util.base64Encode(bs));
}
}
pragmasolidity =0.8.6;// SPDX-License-Identifier: SimPL-2.0interfaceIERC165{
/// @notice Query if a contract implements an interface/// @param interfaceID The interface identifier, as specified in ERC-165/// @dev Interface identification is specified in ERC-165. This function/// uses less than 30,000 gas./// @return `true` if the contract implements `interfaceID` and/// `interfaceID` is not 0xffffffff, `false` otherwisefunctionsupportsInterface(bytes4 interfaceID) externalviewreturns(bool);
}
pragmasolidity =0.8.6;// SPDX-License-Identifier: SimPL-2.0/// @title ERC-721 Non-Fungible Token Standard/// @dev See https://eips.ethereum.org/EIPS/eip-721/// Note: the ERC-165 identifier for this interface is 0x80ac58cd.interfaceIERC721/* is ERC165 */{
/// @dev This emits when ownership of any NFT changes by any mechanism./// This event emits when NFTs are created (`from` == 0) and destroyed/// (`to` == 0). Exception: during contract creation, any number of NFTs/// may be created and assigned without emitting Transfer. At the time of/// any transfer, the approved address for that NFT (if any) is reset to none.eventTransfer(addressindexed _from, addressindexed _to, uint256indexed _tokenId);
/// @dev This emits when the approved address for an NFT is changed or/// reaffirmed. The zero address indicates there is no approved address./// When a Transfer event emits, this also indicates that the approved/// address for that NFT (if any) is reset to none.eventApproval(addressindexed _owner, addressindexed _approved, uint256indexed _tokenId);
/// @dev This emits when an operator is enabled or disabled for an owner./// The operator can manage all NFTs of the owner.eventApprovalForAll(addressindexed _owner, addressindexed _operator, bool _approved);
/// @notice Count all NFTs assigned to an owner/// @dev NFTs assigned to the zero address are considered invalid, and this/// function throws for queries about the zero address./// @param _owner An address for whom to query the balance/// @return The number of NFTs owned by `_owner`, possibly zerofunctionbalanceOf(address _owner) externalviewreturns(uint256);
/// @notice Find the owner of an NFT/// @dev NFTs assigned to zero address are considered invalid, and queries/// about them do throw./// @param _tokenId The identifier for an NFT/// @return The address of the owner of the NFTfunctionownerOf(uint256 _tokenId) externalviewreturns(address);
/// @notice Transfers the ownership of an NFT from one address to another address/// @dev Throws unless `msg.sender` is the current owner, an authorized/// operator, or the approved address for this NFT. Throws if `_from` is/// not the current owner. Throws if `_to` is the zero address. Throws if/// `_tokenId` is not a valid NFT. When transfer is complete, this function/// checks if `_to` is a smart contract (code size > 0). If so, it calls/// `onERC721Received` on `_to` and throws if the return value is not/// `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`./// @param _from The current owner of the NFT/// @param _to The new owner/// @param _tokenId The NFT to transfer/// @param data Additional data with no specified format, sent in call to `_to`functionsafeTransferFrom(address _from, address _to, uint256 _tokenId, bytesmemory data) externalpayable;
/// @notice Transfers the ownership of an NFT from one address to another address/// @dev This works identically to the other function with an extra data parameter,/// except this function just sets data to ""./// @param _from The current owner of the NFT/// @param _to The new owner/// @param _tokenId The NFT to transferfunctionsafeTransferFrom(address _from, address _to, uint256 _tokenId) externalpayable;
/// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE/// TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE/// THEY MAY BE PERMANENTLY LOST/// @dev Throws unless `msg.sender` is the current owner, an authorized/// operator, or the approved address for this NFT. Throws if `_from` is/// not the current owner. Throws if `_to` is the zero address. Throws if/// `_tokenId` is not a valid NFT./// @param _from The current owner of the NFT/// @param _to The new owner/// @param _tokenId The NFT to transferfunctiontransferFrom(address _from, address _to, uint256 _tokenId) externalpayable;
/// @notice Change or reaffirm the approved address for an NFT/// @dev The zero address indicates there is no approved address./// Throws unless `msg.sender` is the current NFT owner, or an authorized/// operator of the current owner./// @param _approved The new approved NFT controller/// @param _tokenId The NFT to approvefunctionapprove(address _approved, uint256 _tokenId) externalpayable;
/// @notice Enable or disable approval for a third party ("operator") to manage/// all of `msg.sender`'s assets/// @dev Emits the ApprovalForAll event. The contract MUST allow/// multiple operators per owner./// @param _operator Address to add to the set of authorized operators/// @param _approved True if the operator is approved, false to revoke approvalfunctionsetApprovalForAll(address _operator, bool _approved) external;
/// @notice Get the approved address for a single NFT/// @dev Throws if `_tokenId` is not a valid NFT./// @param _tokenId The NFT to find the approved address for/// @return The approved address for this NFT, or the zero address if there is nonefunctiongetApproved(uint256 _tokenId) externalviewreturns(address);
/// @notice Query if an address is an authorized operator for another address/// @param _owner The address that owns the NFTs/// @param _operator The address that acts on behalf of the owner/// @return True if `_operator` is an approved operator for `_owner`, false otherwisefunctionisApprovedForAll(address _owner, address _operator) externalviewreturns(bool);
}
Contract Source Code
File 11 of 20: IERC721Metadata.sol
pragmasolidity =0.8.6;// SPDX-License-Identifier: SimPL-2.0/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension/// @dev See https://eips.ethereum.org/EIPS/eip-721/// Note: the ERC-165 identifier for this interface is 0x5b5e139f.interfaceIERC721Metadata/* is ERC721 */{
/// @notice A descriptive name for a collection of NFTs in this contractfunctionname() externalviewreturns (stringmemory);
/// @notice An abbreviated name for NFTs in this contractfunctionsymbol() externalviewreturns (stringmemory);
/// @notice A distinct Uniform Resource Identifier (URI) for a given asset./// @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC/// 3986. The URI may point to a JSON file that conforms to the "ERC721/// Metadata JSON Schema"./// {"name":"","description":"","image":""}functiontokenURI(uint256 _tokenId) externalviewreturns (stringmemory);
}
Contract Source Code
File 12 of 20: IERC721TokenReceiver.sol
pragmasolidity =0.8.6;// SPDX-License-Identifier: SimPL-2.0/// @dev Note: the ERC-165 identifier for this interface is 0x150b7a02.interfaceIERC721TokenReceiver{
/// @notice Handle the receipt of an NFT/// @dev The ERC721 smart contract calls this function on the recipient/// after a `transfer`. This function MAY throw to revert and reject the/// transfer. Return of other than the magic value MUST result in the/// transaction being reverted./// Note: the contract address is always the message sender./// @param _operator The address which called `safeTransferFrom` function/// @param _from The address which previously owned the token/// @param _tokenId The NFT identifier which is being transferred/// @param _data Additional data with no specified format/// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`/// unless throwingfunctiononERC721Received(address _operator, address _from, uint256 _tokenId, bytesmemory _data) externalreturns(bytes4);
}
pragmasolidity =0.8.6;// SPDX-License-Identifier: SimPL-2.0import"./IERC20.sol";
import"./SafeERC20.sol";
// address(0) for ETHlibraryMoneyUtil{
functionbalanceOf(address money,
address account
) internalviewreturns (uint256) {
if (money ==address(0)) {
return account.balance;
} else {
return IERC20(money).balanceOf(account);
}
}
functionapprove(address money, address spender, uint256 amount) internal{
SafeERC20.safeApprove(money, spender, amount);
}
functiontransfer(address money,
addressfrom,
address to,
uint256 amount
) internal{
if (money ==address(0)) {
if (from==address(this)) {
payable(to).transfer(amount);
} elseif (to ==address(this)) {
require(from==msg.sender, "transfer ETH from invalid");
require(msg.value== amount, "transfer ETH value invalid");
} else {
revert("transfer ETH invalid");
}
} else {
if (from==address(this)) {
SafeERC20.transfer(money, to, amount);
} else {
SafeERC20.transferFrom(money, from, to, amount);
}
}
}
functionreceiveExceed(address money,
uint256 amount
) internalreturns (uint256) {
if (money ==address(0)) {
require(msg.value>= amount, "receive ETH value invalid");
returnmsg.value- amount;
} else {
transfer(money, msg.sender, address(this), amount);
return0;
}
}
}
Contract Source Code
File 17 of 20: Ownable.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)pragmasolidity ^0.8.0;import"./Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/abstractcontractOwnableisContext{
addressprivate _owner;
eventOwnershipTransferred(addressindexed previousOwner, addressindexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/modifieronlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/functionowner() publicviewvirtualreturns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/function_checkOwner() internalviewvirtual{
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/functionrenounceOwnership() publicvirtualonlyOwner{
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/functiontransferOwnership(address newOwner) publicvirtualonlyOwner{
require(newOwner !=address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/function_transferOwnership(address newOwner) internalvirtual{
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}