账户
0x38...4Ff4
0x38...4Ff4

0x38...4Ff4

US$0.00
此合同的源代码已经过验证!
合同元数据
编译器
0.8.6+commit.11564f7e
语言
Solidity
合同源代码
文件 1 的 20:AddressMap.sol
pragma solidity =0.8.6;

// SPDX-License-Identifier: SimPL-2.0

import "./AddressSet.sol";

import "./Ownable.sol";

abstract contract AddressMap is Ownable {
    using AddressSet for AddressSet.Set;

    mapping(string => AddressSet.Set) internal addressMap;

    modifier checkAddressMap(string memory key) {
        require(
            addressMap[key].contains(msg.sender),
            "sender not in addressMap"
        );
        _;
    }

    function addAddressMap(
        string memory key,
        address account
    ) public onlyOwner returns (bool) {
        return addressMap[key].add(account);
    }

    function removeAddressMap(
        string memory key,
        address account
    ) public onlyOwner returns (bool) {
        return addressMap[key].remove(account);
    }

    function getAddressMapLength(
        string memory key
    ) public view returns (uint256) {
        return addressMap[key].length();
    }

    // [startIndex, endIndex)
    function getAddressMaps(
        string memory key,
        uint256 startIndex,
        uint256 endIndex
    ) public view returns (address[] memory) {
        return addressMap[key].get(startIndex, endIndex);
    }

    function containsAddressMap(
        string memory key,
        address account
    ) public view returns (bool) {
        return addressMap[key].contains(account);
    }
}
合同源代码
文件 2 的 20:AddressSet.sol
pragma solidity =0.8.6;

// SPDX-License-Identifier: SimPL-2.0

library AddressSet {
    struct Set {
        mapping(address => uint256) indexes;
        address[] addresses;
    }
    
    function add(Set storage set, address addr) internal returns(bool) {
        if (contains(set, addr)) {
            return false;
        }
        
        set.indexes[addr] = set.addresses.length;
        set.addresses.push(addr);
        
        return true;
    }
    
    function remove(Set storage set, address addr) internal returns(bool) {
        if (!contains(set, addr)) {
            return false;
        }
        
        uint256 index = set.indexes[addr];
        address tail = set.addresses[set.addresses.length - 1];
        
        set.indexes[tail] = index;
        set.indexes[addr] = 0;
        
        set.addresses[index] = tail;
        set.addresses.pop();
        
        return true;
    }
    
    function contains(Set storage set, address addr) internal view returns(bool) {
        uint256 index = set.indexes[addr];
        return index < set.addresses.length && set.addresses[index] == addr;
    }
    
    function indexOf(Set storage set, address addr) internal view returns(uint256) {
        if (contains(set, addr)) {
            return set.indexes[addr];
        } else {
            return ~uint256(0);
        }
    }
    
    function length(Set storage set) internal view returns(uint256) {
        return set.addresses.length;
    }
    
    function get(Set storage set) internal view returns(address[] memory) {
        return set.addresses;
    }
    
    function get(Set storage set, uint256 index)
        internal view returns(address) {
        
        require(index < set.addresses.length, "invalid index");
        
        return set.addresses[index];
    }
    
    // [startIndex, endIndex)
    function get(Set storage set, uint256 startIndex, uint256 endIndex)
        internal view returns(address[] memory) {
        
        if (endIndex == 0) {
            endIndex = set.addresses.length;
        }
        
        require(startIndex <= endIndex && endIndex <= set.addresses.length,
            "invalid index");
        
        address[] memory result = new address[](endIndex - startIndex);
        
        for (uint256 i = startIndex; i < endIndex; ++i) {
            result[i - startIndex] = set.addresses[i];
        }
        
        return result;
    }
}
合同源代码
文件 3 的 20:Card.sol
pragma solidity =0.8.6;

// SPDX-License-Identifier: SimPL-2.0

import "./ERC721Ex.sol";

// padding  shop    mintTime    index
// 144      16      40          56
// 112      96      56          0

abstract contract Card is ERC721Ex {
    // except mintTime and index
    uint256 public constant CARD_ID_PREFIX_MASK = uint256(~uint160(0)) << 96;
    
    function mint(address to, uint256 cardIdPre) external checkAddressMap("package") {
        uint256 cardId = (cardIdPre & CARD_ID_PREFIX_MASK) |
            (uint256(uint40(block.timestamp)) << 56) |
            uint56(totalSupply + 1);
        
        _mint(to, cardId);
    }
    
    function burn(uint256 cardId) public virtual;
    
    function batchBurn(uint256[] memory cardIds) external {
        for (uint256 i = 0; i < cardIds.length; ++i) {
            burn(cardIds[i]);
        }
    }
}
合同源代码
文件 4 的 20:Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)

pragma solidity ^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.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}
合同源代码
文件 5 的 20:ERC721.sol
pragma solidity =0.8.6;

// SPDX-License-Identifier: SimPL-2.0

import "./IERC165.sol";
import "./IERC721.sol";
import "./IERC721Metadata.sol";
import "./IERC721TokenReceiver.sol";

import "./Util.sol";

abstract contract ERC721 is IERC165, IERC721, IERC721Metadata {
    /*
     * bytes4(keccak256("supportsInterface(bytes4)")) == 0x01ffc9a7
     */
    bytes4 private constant 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
     */
    bytes4 private constant INTERFACE_ID_ERC721 = 0x80ac58cd;

    bytes4 private constant INTERFACE_ID_ERC721Metadata = 0x5b5e139f;

    string public override name;
    string public override 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(string memory _name, string memory _symbol) {
        name = _name;
        symbol = _symbol;
    }

    function balanceOf(address owner) external view override returns (uint256) {
        require(owner != address(0), "owner is zero address");
        return ownerTokens[owner].length;
    }

    // [startIndex, endIndex)
    function tokensOf(
        address owner,
        uint256 startIndex,
        uint256 endIndex
    ) external view returns (uint256[] memory) {
        require(owner != address(0), "owner is zero address");

        uint256[] storage tokens = ownerTokens[owner];
        if (endIndex == 0) {
            endIndex = tokens.length;
        }

        uint256[] memory result = new uint256[](endIndex - startIndex);
        for (uint256 i = startIndex; i < endIndex; ++i) {
            result[i - startIndex] = tokens[i];
        }

        return result;
    }

    function ownerOf(uint256 tokenId) external view override returns (address) {
        address owner = tokenOwners[tokenId];
        require(owner != address(0), "nobody own the token");
        return owner;
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external payable override {
        safeTransferFrom(from, to, tokenId, "");
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
    ) public payable override {
        _transferFrom(from, to, tokenId);

        if (to.code.length > 0) {
            require(
                IERC721TokenReceiver(to).onERC721Received(
                    msg.sender,
                    from,
                    tokenId,
                    data
                ) == IERC721TokenReceiver.onERC721Received.selector,
                "onERC721Received() return invalid"
            );
        }
    }

    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external payable override {
        _transferFrom(from, to, tokenId);
    }

    function _transferFrom(address from, 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 it
    function _removeTokenFrom(address from, 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 gas
        delete tokenOwners[tokenId];
    }

    // ensure everything is ok before call it
    function _addTokenTo(address to, uint256 tokenId) internal {
        uint256[] storage tokens = ownerTokens[to];
        tokenIndexs[tokenId] = tokens.length;
        tokens.push(tokenId);

        tokenOwners[tokenId] = to;
    }

    function approve(address to, uint256 tokenId) external payable override {
        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);
    }

    function setApprovalForAll(address to, bool approved) external override {
        approvalForAlls[msg.sender][to] = approved;
        emit ApprovalForAll(msg.sender, to, approved);
    }

    function getApproved(
        uint256 tokenId
    ) external view override returns (address) {
        require(tokenOwners[tokenId] != address(0), "nobody own then token");

        return tokenApprovals[tokenId];
    }

    function isApprovedForAll(
        address owner,
        address operator
    ) external view override returns (bool) {
        return approvalForAlls[owner][operator];
    }

    function supportsInterface(
        bytes4 interfaceID
    ) external pure override returns (bool) {
        return
            interfaceID == INTERFACE_ID_ERC165 ||
            interfaceID == INTERFACE_ID_ERC721 ||
            interfaceID == INTERFACE_ID_ERC721Metadata;
    }
}
合同源代码
文件 6 的 20:ERC721Ex.sol
pragma solidity =0.8.6;

// SPDX-License-Identifier: SimPL-2.0

import "./IERC721TokenReceiverEx.sol";

import "./String.sol";
import "./Util.sol";

import "./ERC721.sol";
import "./Member.sol";

abstract contract ERC721Ex is ERC721, Member {
    using String for string;

    uint256 public totalSupply = 0;

    string public 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);
    }

    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] memory tokenIds
    ) external {
        safeBatchTransferFrom(from, to, tokenIds, "");
    }

    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] memory tokenIds,
        bytes memory 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"
            );
        }
    }

    function batchTransferFrom(
        address from,
        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);
        }
    }

    function setUriPrefix(string memory prefix) external onlyOwner {
        uriPrefix = prefix;
    }

    function tokenURI(
        uint256 cardId
    ) external view virtual override returns (string memory) {
        bytes memory bs = abi.encodePacked(cardId);
        return uriPrefix.concat(Util.base64Encode(bs));
    }
}
合同源代码
文件 7 的 20:Hero.sol
pragma solidity =0.8.6;

// SPDX-License-Identifier: SimPL-2.0

import "./MoneyUtil.sol";

import "./Card.sol";

// country  order   skin    star    tokenAmount padding shop    mintTime    index
// 8        24      8       8       72          24      16      40          56
// 248      224     216     208     136         112     96      56          0

contract Hero is Card {
    uint256 public burnLockDuration = 2 days;

    uint256 public lossRate = 0.03e18;
    uint256 public lossRateWhite = 0.05e18;

    constructor(
        string memory _name,
        string memory _symbol
    ) ERC721(_name, _symbol) {}

    function setBurnLockDuration(uint256 duration) external onlyOwner {
        burnLockDuration = duration;
    }

    function setLossRate(uint256 rate) external onlyOwner {
        lossRate = rate;
    }

    function setLossRateWhite(uint256 rate) external onlyOwner {
        lossRateWhite = rate;
    }

    function burn(uint256 cardId) public override {
        address owner = tokenOwners[cardId];

        require(
            msg.sender == owner ||
                msg.sender == tokenApprovals[cardId] ||
                approvalForAlls[owner][msg.sender],
            "msg.sender must be owner or approved"
        );

        uint256 lr;

        if (containsAddressMap("burnWhiteList", msg.sender)) {
            lr = lossRateWhite;
        } else {
            uint256 mintTime = uint40(cardId >> 56);
            require(
                mintTime + burnLockDuration < block.timestamp,
                "hero has not unlocked"
            );

            lr = lossRate;
        }

        _burn(cardId);

        uint256 tokenAmount = uint72(cardId >> 136);
        uint256 loss = (tokenAmount * lr) / Util.DENO;

        address money = manager.members("token");
        MoneyUtil.transfer(money, address(this), owner, tokenAmount - loss);
        MoneyUtil.transfer(
            money,
            address(this),
            manager.members("cashier"),
            loss
        );
    }
}
合同源代码
文件 8 的 20:IERC165.sol
pragma solidity =0.8.6;

// SPDX-License-Identifier: SimPL-2.0

interface IERC165 {
    /// @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` otherwise
    function supportsInterface(bytes4 interfaceID) external view returns(bool);
}
合同源代码
文件 9 的 20:IERC20.sol
pragma solidity =0.8.6;

// SPDX-License-Identifier: SimPL-2.0

interface IERC20 {
    event Approval(address indexed owner, address indexed spender, uint256 value);
    event Transfer(address indexed from, address indexed to, uint256 value);
    
    function name() external view returns(string memory);
    function symbol() external view returns(string memory);
    function decimals() external view returns(uint8);
    function totalSupply() external view returns(uint256);
    function balanceOf(address owner) external view returns(uint256);
    function allowance(address owner, address spender) external view returns(uint256);
    
    function approve(address spender, uint256 value) external returns(bool);
    function transfer(address to, uint256 value) external returns(bool);
    function transferFrom(address from, address to, uint256 value) external returns(bool);
}
合同源代码
文件 10 的 20:IERC721.sol
pragma solidity =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.
interface IERC721 /* 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.
    event Transfer(address indexed _from, address indexed _to, uint256 indexed _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.
    event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);

    /// @dev This emits when an operator is enabled or disabled for an owner.
    ///  The operator can manage all NFTs of the owner.
    event ApprovalForAll(address indexed _owner, address indexed _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 zero
    function balanceOf(address _owner) external view returns(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 NFT
    function ownerOf(uint256 _tokenId) external view returns(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`
    function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes memory data) external payable;

    /// @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 transfer
    function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;

    /// @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 transfer
    function transferFrom(address _from, address _to, uint256 _tokenId) external payable;

    /// @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 approve
    function approve(address _approved, uint256 _tokenId) external payable;

    /// @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 approval
    function setApprovalForAll(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 none
    function getApproved(uint256 _tokenId) external view returns(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 otherwise
    function isApprovedForAll(address _owner, address _operator) external view returns(bool);
}
合同源代码
文件 11 的 20:IERC721Metadata.sol
pragma solidity =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.
interface IERC721Metadata /* is ERC721 */ {
    /// @notice A descriptive name for a collection of NFTs in this contract
    function name() external view returns (string memory);
    
    /// @notice An abbreviated name for NFTs in this contract
    function symbol() external view returns (string memory);
    
    /// @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":""}
    function tokenURI(uint256 _tokenId) external view returns (string memory);
}
合同源代码
文件 12 的 20:IERC721TokenReceiver.sol
pragma solidity =0.8.6;

// SPDX-License-Identifier: SimPL-2.0

/// @dev Note: the ERC-165 identifier for this interface is 0x150b7a02.
interface IERC721TokenReceiver {
    /// @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 throwing
    function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes memory _data) external returns(bytes4);
}
合同源代码
文件 13 的 20:IERC721TokenReceiverEx.sol
pragma solidity =0.8.6;

// SPDX-License-Identifier: SimPL-2.0

interface IERC721TokenReceiverEx {
    // bytes4(keccak256("onERC721ExReceived(address,address,uint256[],bytes)")) = 0x0f7b88e3
    function onERC721ExReceived(address operator, address from,
        uint256[] memory tokenIds, bytes memory data)
        external returns(bytes4);
}
合同源代码
文件 14 的 20:Manager.sol
pragma solidity =0.8.6;

// SPDX-License-Identifier: SimPL-2.0

import "./AddressSet.sol";

import "./Ownable.sol";

contract Manager is Ownable {
    using AddressSet for AddressSet.Set;

    mapping(string => address) public members;

    mapping(string => AddressSet.Set) internal permits;

    modifier onlyPermit(string memory permit) {
        require(permits[permit].contains(msg.sender), "no permit");
        _;
    }

    function setMember(string memory name, address member) external onlyOwner {
        members[name] = member;
    }

    function addPermit(
        string memory permit,
        address account
    ) external onlyOwner {
        require(permits[permit].add(account), "account existed");
    }

    function removePermit(
        string memory permit,
        address account
    ) external onlyOwner {
        require(permits[permit].remove(account), "account not existed");
    }

    function removePermitAll(string memory permit) external onlyOwner {
        delete permits[permit];
    }

    function getPermitLength(
        string memory permit
    ) external view returns (uint256) {
        return permits[permit].length();
    }

    // [startIndex, endIndex)
    function getPermitMaps(
        string memory permit,
        uint256 startIndex,
        uint256 endIndex
    ) external view returns (address[] memory) {
        return permits[permit].get(startIndex, endIndex);
    }

    function containsPermit(
        string memory permit,
        address account
    ) public view returns (bool) {
        return permits[permit].contains(account);
    }

    function requirePermit(string memory permit, address account) public view {
        require(containsPermit(permit, account), "not permit");
    }

    function getTimestamp() external view returns (uint256) {
        return block.timestamp;
    }
}
合同源代码
文件 15 的 20:Member.sol
pragma solidity =0.8.6;

// SPDX-License-Identifier: SimPL-2.0

import "./AddressMap.sol";

import "./Manager.sol";

abstract contract Member is AddressMap {
    Manager public manager;

    modifier onlyPermit(string memory permit) {
        require(manager.containsPermit(permit, msg.sender), "no permit");
        _;
    }

    function setManager(address addr) external onlyOwner {
        manager = Manager(addr);
    }
}
合同源代码
文件 16 的 20:MoneyUtil.sol
pragma solidity =0.8.6;

// SPDX-License-Identifier: SimPL-2.0

import "./IERC20.sol";

import "./SafeERC20.sol";

// address(0) for ETH

library MoneyUtil {
    function balanceOf(
        address money,
        address account
    ) internal view returns (uint256) {
        if (money == address(0)) {
            return account.balance;
        } else {
            return IERC20(money).balanceOf(account);
        }
    }

    function approve(address money, address spender, uint256 amount) internal {
        SafeERC20.safeApprove(money, spender, amount);
    }

    function transfer(
        address money,
        address from,
        address to,
        uint256 amount
    ) internal {
        if (money == address(0)) {
            if (from == address(this)) {
                payable(to).transfer(amount);
            } else if (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);
            }
        }
    }

    function receiveExceed(
        address money,
        uint256 amount
    ) internal returns (uint256) {
        if (money == address(0)) {
            require(msg.value >= amount, "receive ETH value invalid");
            return msg.value - amount;
        } else {
            transfer(money, msg.sender, address(this), amount);
            return 0;
        }
    }
}
合同源代码
文件 17 的 20:Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)

pragma solidity ^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.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed 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.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        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.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        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) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}
合同源代码
文件 18 的 20:SafeERC20.sol
pragma solidity =0.8.6;

// SPDX-License-Identifier: SimPL-2.0

import "./IERC20.sol";

library SafeERC20 {
    function transfer(address token, address to, uint256 value) internal {
        callOptionalReturn(token, abi.encodeWithSelector(
            IERC20.transfer.selector, to, value));
    }
	
    function transferFrom(address token, address from, address to, uint256 value) internal {
        callOptionalReturn(token, abi.encodeWithSelector(
            IERC20.transferFrom.selector, from, to, value));
    }
	
    function approve(address token, address spender, uint256 value) internal {
        callOptionalReturn(token, abi.encodeWithSelector(
            IERC20.approve.selector, spender, value));
    }
	
    function safeApprove(address token, address spender, uint256 value) internal {
        require((value == 0) || (IERC20(token).allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        callOptionalReturn(token, abi.encodeWithSelector(
            IERC20.approve.selector, spender, value));
    }
	
    function increaseAllowance(address token, address spender, uint256 value) internal {
        uint256 newAllowance = IERC20(token).allowance(address(this), spender) + value;
        callOptionalReturn(token, abi.encodeWithSelector(
            IERC20.approve.selector, spender, newAllowance));
    }
	
    function decreaseAllowance(address token, address spender, uint256 value) internal {
        uint256 newAllowance = IERC20(token).allowance(address(this), spender) - value;
        callOptionalReturn(token, abi.encodeWithSelector(
            IERC20.approve.selector, spender, newAllowance));
    }
	
    function callOptionalReturn(address token, bytes memory data) private {
        (bool success, bytes memory returndata) = token.call(data);
        require(success, "SafeERC20: low-level call failed");
        if (returndata.length > 0) {
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

合同源代码
文件 19 的 20:String.sol
pragma solidity =0.8.6;

// SPDX-License-Identifier: SimPL-2.0

library String {
    function equals(string memory a, string memory b)
        internal pure returns(bool) {
        
        bytes memory ba = bytes(a);
        bytes memory bb = bytes(b);
        
        if (ba.length != bb.length) {
            return false;
        }
        
        uint256 length = ba.length;
        
        for (uint256 i = 0; i < length; ++i) {
            if (ba[i] != bb[i]) {
                return false;
            }
        }
        
        return true;
    }
    
    function concat(string memory a, string memory b)
        internal pure returns(string memory) {
        
        return string(abi.encodePacked(a, b));
    }
    
    function utf8length(string memory s) internal pure returns(uint256) {
        bytes memory bs = bytes(s);
        uint256 bytelength = bs.length;
        uint256 length = 0;
        
        for (uint256 i = 0; i < bytelength; ++length) {
            bytes1 b = bs[i];
            
            if (b < 0x80) {
                i += 1;
            } else if (b < 0xE0) {
                i += 2;
            } else if (b < 0xF0) {
                i += 3;
            } else if (b < 0xF8) {
                i += 4;
            } else if (b < 0xFC) {
                i += 5;
            } else {
                i += 6;
            }
        }
        
        return length;
    }
}
合同源代码
文件 20 的 20:Util.sol
pragma solidity =0.8.6;

// SPDX-License-Identifier: SimPL-2.0

library Util {
    uint256 internal constant DENO = 1e18;

    bytes internal constant BASE64_CHARS =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";

    function randomUint(
        bytes memory seed,
        uint256 min,
        uint256 max
    ) internal pure returns (uint256) {
        if (min >= max) {
            return min;
        }

        uint256 number = uint256(keccak256(seed));
        return (number % (max - min + 1)) + min;
    }

    function randomWeight(
        bytes memory seed,
        uint256[] memory weights,
        uint256 totalWeight
    ) internal pure returns (uint256) {
        uint256 number = Util.randomUint(seed, 1, totalWeight);

        for (uint256 i = weights.length - 1; i > 0; --i) {
            if (number <= weights[i]) {
                return i;
            }

            number -= weights[i];
        }

        return 0;
    }

    function randomProb(
        bytes memory seed,
        uint256 nume,
        uint256 deno
    ) internal pure returns (bool) {
        uint256 rand = Util.randomUint(seed, 1, deno);
        return rand <= nume;
    }

    function base64Encode(
        bytes memory bs
    ) internal pure returns (string memory) {
        uint256 remain = bs.length % 3;
        uint256 length = (bs.length / 3) * 4;
        bytes memory result = new bytes(
            length + (remain != 0 ? 4 : 0) + ((3 - remain) % 3)
        );

        uint256 i = 0;
        uint256 j = 0;
        while (i < length) {
            result[i++] = Util.BASE64_CHARS[uint8(bs[j] >> 2)];
            result[i++] = Util.BASE64_CHARS[
                uint8(((bs[j] & 0x03) << 4) | (bs[j + 1] >> 4))
            ];
            result[i++] = Util.BASE64_CHARS[
                uint8(((bs[j + 1] & 0x0f) << 2) | (bs[j + 2] >> 6))
            ];
            result[i++] = Util.BASE64_CHARS[uint8(bs[j + 2] & 0x3f)];

            j += 3;
        }

        if (remain != 0) {
            result[i++] = Util.BASE64_CHARS[uint8(bs[j] >> 2)];

            if (remain == 2) {
                result[i++] = Util.BASE64_CHARS[
                    uint8(((bs[j] & 0x03) << 4) | (bs[j + 1] >> 4))
                ];
                result[i++] = Util.BASE64_CHARS[uint8((bs[j + 1] & 0x0f) << 2)];
                result[i++] = Util.BASE64_CHARS[0];
                result[i++] = 0x3d;
            } else {
                result[i++] = Util.BASE64_CHARS[uint8((bs[j] & 0x03) << 4)];
                result[i++] = Util.BASE64_CHARS[0];
                result[i++] = Util.BASE64_CHARS[0];
                result[i++] = 0x3d;
                result[i++] = 0x3d;
            }
        }

        return string(result);
    }

    function calcBuffer(
        uint256 value,
        uint256 buffer
    ) internal pure returns (uint256) {
        return (value * (DENO + buffer)) / DENO;
    }
}
设置
{
  "compilationTarget": {
    "Hero.sol": "Hero"
  },
  "evmVersion": "berlin",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "optimizer": {
    "enabled": true,
    "runs": 9999999
  },
  "remappings": []
}
ABI
[{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"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":[],"name":"CARD_ID_PREFIX_MASK","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"key","type":"string"},{"internalType":"address","name":"account","type":"address"}],"name":"addAddressMap","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"cardIds","type":"uint256[]"}],"name":"batchBurn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"batchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"cardId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"burnLockDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"key","type":"string"},{"internalType":"address","name":"account","type":"address"}],"name":"containsAddressMap","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"key","type":"string"}],"name":"getAddressMapLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"key","type":"string"},{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"endIndex","type":"uint256"}],"name":"getAddressMaps","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","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":[],"name":"lossRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lossRateWhite","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"manager","outputs":[{"internalType":"contract Manager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"cardIdPre","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"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":[{"internalType":"string","name":"key","type":"string"},{"internalType":"address","name":"account","type":"address"}],"name":"removeAddressMap","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","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":"tokenIds","type":"uint256[]"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeBatchTransferFrom","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":"payable","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":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"setBurnLockDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"rate","type":"uint256"}],"name":"setLossRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"rate","type":"uint256"}],"name":"setLossRateWhite","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"prefix","type":"string"}],"name":"setUriPrefix","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceID","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"cardId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"endIndex","type":"uint256"}],"name":"tokensOf","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"uriPrefix","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]