Skip to main content
PulseScanner.io

Address

0x320e2fa93a4010ba47edcde762802374bac8d3f7
Current Holdings
$0.00
TXs sent
not counted
First Active
2023-11-07
block 18,769,830
Last Active
386 days ago
block 24,358,200
Funded By
not identified

Net worth historyi

2 snapshots · to block 27,480,461coverage change 26 Augcoverage change 27 Augcoverage change 27 Augcoverage change 27 Augcoverage change 27 Aug
partial matchSpiralFrequenciessolc 0.8.7+commit.e28d00a7runtime partial · creation partial
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "openzeppelin-solidity/contracts/token/ERC721/ERC721.sol";
import "openzeppelin-solidity/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "openzeppelin-solidity/contracts/access/Ownable.sol";
import "openzeppelin-solidity/contracts/utils/cryptography/ECDSA.sol";
import "openzeppelin-solidity/contracts/utils/Strings.sol";

import "./common/meta-transactions/ContentMixin.sol";
import "./common/meta-transactions/NativeMetaTransaction.sol";

contract OwnableDelegateProxy {}

contract ProxyRegistry {
    mapping(address => OwnableDelegateProxy) public proxies;
}

/**
 * @title GeneticChain721
 * GeneticChainBase - ERC721 contract that whitelists a trading address, and has
 *  minting functionality.
 */
abstract contract GeneticChain721 is
    ContextMixin,
    ERC721Enumerable,
    NativeMetaTransaction,
    Ownable
{
    using ECDSA for bytes32;

    // mapping from token id to token hash
    mapping (uint256 => bytes32) private _hash;

    // only allow nonces to be used once
    mapping(string => bool) private _usedNonces;

    // track mint count per address
    mapping (address => uint256) private _mints;

    address _proxyRegistryAddress;
    uint256 private _currentTokenId = 0;
    uint256 private _seed;

    // message signer
    address private _signer = 0x9bf0E17205F269494DFc7957b9Da48f4F088478d;

    // token limits
    uint256 public publicMax;
    uint256 public privateMax;
    uint256 public tokenMax;
    uint256 public publicMinted = 0;
    uint256 public privateMinted = 0;

    modifier validTokenId(uint256 tokenId) {
        require(_exists(tokenId), "invalid token");
        _;
    }

    modifier approvedOrOwner(address operator, uint256 tokenId) {
        require(_isApprovedOrOwner(operator, tokenId));
        _;
    }

    constructor(
        string memory name,
        string memory symbol,
        uint256 publicMax_,
        uint256 privateMax_,
        uint256 seed,
        address proxyRegistryAddress)
        ERC721(name, symbol)
    {
        publicMax             = publicMax_;
        privateMax            = privateMax_;
        tokenMax              = publicMax_ + privateMax_;
        _seed                 = seed;
        _proxyRegistryAddress = proxyRegistryAddress;
        _initializeEIP712(name);
    }

    /**
     * Validate hash contains input data.
     */
    function validateHash(bytes32 msgHash, address sender, uint256 allocation, uint256 count, string memory nonce)
        private
        pure
        returns(bool)
    {
          return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32",
            keccak256(abi.encodePacked(sender, allocation, count, nonce)))) == msgHash;
    }

    /**
     * Validate message was signed by signer.
     */
    function validateSigner(bytes32 msgHash, bytes memory signature)
        private
        view
        returns(bool)
    {
        return msgHash.recover(signature) == _signer;
    }

    /**
     * @dev Mints a token to an address.
     * @param _to address of the future owner of the token
     */
    function mintTo(address _to)
        external
        onlyOwner
    {
        require(totalSupply() + 1 <= tokenMax, "exceed token supply");
        require(privateMinted + 1 <= privateMax, "exceed private supply");
        ++privateMinted;
        _mintTo(_to);
    }

    /**
     * @dev Mints multiple tokens to an address.
     * @param _to address of the future owner of the token
     */
    function batchMint(address _to, uint256 count)
        external
        onlyOwner
    {
        require(totalSupply() + count <= tokenMax, "exceed token supply");
        require(privateMinted + count <= privateMax, "exceed private supply");
        privateMinted += count;
        for (uint256 i = 0; i < count; ++i) {
            _mintTo(_to);
        }
    }

    /**
     * Mint count tokens using securely signed message.
     */
    function secureMint(bytes32 msgHash, bytes memory signature, uint256 allocation, uint256 count, string memory nonce)
        external
    {
        require(!_usedNonces[nonce], "invalid nonce");
        require(totalSupply() < tokenMax, "all tokens minted");
        require(totalSupply() + count <= tokenMax, "exceed token supply");
        require(publicMinted + count <= publicMax, "exceed public supply");
        require(_mints[msg.sender] + count <= allocation, "exceed allocation");
        require(validateSigner(msgHash, signature), "invalid signer");
        require(validateHash(msgHash, msg.sender, allocation, count, nonce), "invalid hash");
        publicMinted += count;
        _mints[msg.sender] += count;
        _usedNonces[nonce] = true;
        for (uint256 i = 0; i < count; ++i) {
            _mintTo(msg.sender);
        }
    }

    /**
     * @dev Mints a token to an address with a tokenURI.
     * @param _to address of the future owner of the token
     */
    function _mintTo(address _to)
        internal
    {
        uint256 newTokenId = totalSupply() + 1;
        _safeMint(_to, newTokenId);
        _hash[newTokenId] = _randomHash(_to, newTokenId);
    }

    function baseTokenURI()
        virtual
        public
        view
        returns (string memory);

    /**
     * @dev Returns uri of a token.  Not guarenteed token exists.
     */
    function tokenURI(uint256 tokenId)
        override
        public
        view
        returns (string memory)
    {
        return string(abi.encodePacked(baseTokenURI(), "/", Strings.toString(tokenId), "/meta"));
    }

    /**
     * @return randomly generated hash associated with valid a token.
     */
    function tokenHash(uint256 tokenId)
        public
        view
        validTokenId(tokenId)
        returns (bytes32)
    {
        return _hash[tokenId];
    }

    /**
     * Pull all money out of this contract.
     */
    function withdraw(address to, uint256 amount)
        public
        onlyOwner
    {
        require(amount > 0, "amount empty");
        require(amount <= address(this).balance, "amount exceeds balance");
        require(to != address(0), "address null");
        payable(to).transfer(amount);
    }

    /**
     * @dev Pseudo-random number generator.
     */
    function _randomHash(address _to, uint256 tokenId)
        internal
        returns (bytes32)
    {
      bytes32 hash = keccak256(
          abi.encodePacked(
              blockhash(block.number - 1),
              msg.sender,
              _seed,
              tokenId,
              _to));
      _seed = uint256(hash);
      return hash;
    }

    /**
     * Override isApprovedForAll to whitelist user's OpenSea proxy accounts
     *  to enable gas-less listings.
     */
    function isApprovedForAll(address owner, address operator)
        override
        public
        view
        returns (bool)
    {
        // whitelist OpenSea proxy contract for easy trading.
        ProxyRegistry proxyRegistry = ProxyRegistry(_proxyRegistryAddress);
        if (address(proxyRegistry.proxies(owner)) == operator) {
            return true;
        }

        return super.isApprovedForAll(owner, operator);
    }

    /**
     * This is used instead of msg.sender as transactions won't be sent by
     *  the original token owner, but by OpenSea.
     */
    function _msgSender()
        internal
        override
        view
        returns (address sender)
    {
        return ContextMixin.msgSender();
    }

}