ETH Price: $2,340.02 (+1.08%)

Transaction Decoder

Block:
12699480 at Jun-24-2021 10:13:50 PM +UTC
Transaction Fee:
0.014583497469745497 ETH $34.13
Gas Used:
345,497 Gas / 42.210200001 Gwei

Emitted Events:

Account State Difference:

  Address   Before After State Difference Code
0x08f95081...592d1B8a8 168.347523945545336341 Eth168.437523945545336341 Eth0.09
(AntPool 2)
1,785.585608141513150856 Eth1,785.600191638982896353 Eth0.014583497469745497
0x96dC73c8...4b5177660
(Art Blocks: Deployer 1)
139.965885828569772853 Eth139.975885828569772853 Eth0.01
0xa7d8d9ef...abd5bD270
0xE487Ed5e...88df8Ad4F
(Jakes World: Deployer)
1.235156471094208087 Eth
Nonce: 394
1.12057297362446259 Eth
Nonce: 395
0.114583497469745497

Execution Trace

ETH 0.1 0x0e8bd86663e3c2418900178e96e14c51b2859957.efef39a1( )
  • GenArt721Core.projectIdToCurrencySymbol( 37 ) => ( ETH )
  • GenArt721Core.projectIdToPricePerTokenInWei( 37 ) => ( 100000000000000000 )
  • GenArt721Core.projectIdToPricePerTokenInWei( 37 ) => ( 100000000000000000 )
  • GenArt721Core.projectIdToPricePerTokenInWei( 37 ) => ( 100000000000000000 )
  • GenArt721Core.STATICCALL( )
  • GenArt721Core.STATICCALL( )
  • ETH 0.01 Art Blocks: Deployer 1.CALL( )
  • GenArt721Core.projectIdToAdditionalPayeePercentage( 37 ) => ( 0 )
  • GenArt721Core.projectIdToArtistAddress( 37 ) => ( 0x08f950816358F4306B70fB319E4F35c592d1B8a8 )
  • ETH 0.09 0x08f950816358f4306b70fb319e4f35c592d1b8a8.CALL( )
  • GenArt721Core.mint( _to=0xE487Ed5ec80ccA6e8A44F6D6f3f712088df8Ad4F, _projectId=37, _by=0xE487Ed5ec80ccA6e8A44F6D6f3f712088df8Ad4F ) => ( _tokenId=37002647 )
    • 0x03d37ad26961d79e52c3daea840c0095fb4729a7.STATICCALL( )
      • 0x55e6711385795999678c378ef9608d7b64bca3f6.STATICCALL( )
        • TetherToken.STATICCALL( )
        • 0x55e6711385795999678c378ef9608d7b64bca3f6.STATICCALL( )
          • TetherToken.STATICCALL( )
            File 1 of 2: GenArt721Core
            // File contracts/libs/IERC165.sol
            
            // File: openzeppelin-solidity/contracts/introspection/IERC165.sol
            pragma solidity ^0.5.0;
            
            /**
             * @dev Interface of the ERC165 standard, as defined in the
             * [EIP](https://eips.ethereum.org/EIPS/eip-165).
             *
             * Implementers can declare support of contract interfaces, which can then be
             * queried by others (`ERC165Checker`).
             *
             * For an implementation, see `ERC165`.
             */
            interface IERC165 {
                /**
                 * @dev Returns true if this contract implements the interface defined by
                 * `interfaceId`. See the corresponding
                 * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
                 * to learn more about how these ids are created.
                 *
                 * This function call must use less than 30 000 gas.
                 */
                function supportsInterface(bytes4 interfaceId) external view returns (bool);
            }
            
            
            // File contracts/libs/ERC165.sol
            
            // File: openzeppelin-solidity/contracts/introspection/ERC165.sol
            
            pragma solidity ^0.5.0;
            
            
            
            /**
             * @dev Implementation of the `IERC165` interface.
             *
             * Contracts may inherit from this and call `_registerInterface` to declare
             * their support of an interface.
             */
            contract ERC165 is IERC165 {
                /*
                 * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
                 */
                bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
            
                /**
                 * @dev Mapping of interface ids to whether or not it's supported.
                 */
                mapping(bytes4 => bool) private _supportedInterfaces;
            
                constructor () internal {
                    // Derived contracts need only register support for their own interfaces,
                    // we register support for ERC165 itself here
                    _registerInterface(_INTERFACE_ID_ERC165);
                }
            
                /**
                 * @dev See `IERC165.supportsInterface`.
                 *
                 * Time complexity O(1), guaranteed to always use less than 30 000 gas.
                 */
                function supportsInterface(bytes4 interfaceId) external view returns (bool) {
                    return _supportedInterfaces[interfaceId];
                }
            
                /**
                 * @dev Registers the contract as an implementer of the interface defined by
                 * `interfaceId`. Support of the actual ERC165 interface is automatic and
                 * registering its interface id is not required.
                 *
                 * See `IERC165.supportsInterface`.
                 *
                 * Requirements:
                 *
                 * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`).
                 */
                function _registerInterface(bytes4 interfaceId) internal {
                    require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
                    _supportedInterfaces[interfaceId] = true;
                }
            }
            
            
            // File contracts/libs/IERC721.sol
            
            // File: openzeppelin-solidity/contracts/token/ERC721/IERC721.sol
            
            pragma solidity ^0.5.0;
            
            
            
            /**
             * @dev Required interface of an ERC721 compliant contract.
             */
            contract 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);
            
                /**
                 * @dev Returns the number of NFTs in `owner`'s account.
                 */
                function balanceOf(address owner) public view returns (uint256 balance);
            
                /**
                 * @dev Returns the owner of the NFT specified by `tokenId`.
                 */
                function ownerOf(uint256 tokenId) public view returns (address owner);
            
                /**
                 * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to
                 * another (`to`).
                 *
                 *
                 *
                 * Requirements:
                 * - `from`, `to` cannot be zero.
                 * - `tokenId` must be owned by `from`.
                 * - If the caller is not `from`, it must be have been allowed to move this
                 * NFT by either `approve` or `setApproveForAll`.
                 */
                function safeTransferFrom(address from, address to, uint256 tokenId) public;
                /**
                 * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to
                 * another (`to`).
                 *
                 * Requirements:
                 * - If the caller is not `from`, it must be approved to move this NFT by
                 * either `approve` or `setApproveForAll`.
                 */
                function transferFrom(address from, address to, uint256 tokenId) public;
                function approve(address to, uint256 tokenId) public;
                function getApproved(uint256 tokenId) public view returns (address operator);
            
                function setApprovalForAll(address operator, bool _approved) public;
                function isApprovedForAll(address owner, address operator) public view returns (bool);
            
            
                function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public;
            }
            
            
            // File contracts/libs/SafeMath.sol
            
            // File: openzeppelin-solidity/contracts/math/SafeMath.sol
            
            pragma solidity ^0.5.0;
            
            /**
             * @dev Wrappers over Solidity's arithmetic operations with added overflow
             * checks.
             *
             * Arithmetic operations in Solidity wrap on overflow. This can easily result
             * in bugs, because programmers usually assume that an overflow raises an
             * error, which is the standard behavior in high level programming languages.
             * `SafeMath` restores this intuition by reverting the transaction when an
             * operation overflows.
             *
             * Using this library instead of the unchecked operations eliminates an entire
             * class of bugs, so it's recommended to use it always.
             */
            library SafeMath {
                /**
                 * @dev Returns the addition of two unsigned integers, reverting on
                 * overflow.
                 *
                 * Counterpart to Solidity's `+` operator.
                 *
                 * Requirements:
                 * - Addition cannot overflow.
                 */
                function add(uint256 a, uint256 b) internal pure returns (uint256) {
                    uint256 c = a + b;
                    require(c >= a, "SafeMath: addition overflow");
            
                    return c;
                }
            
                /**
                 * @dev Returns the subtraction of two unsigned integers, reverting on
                 * overflow (when the result is negative).
                 *
                 * Counterpart to Solidity's `-` operator.
                 *
                 * Requirements:
                 * - Subtraction cannot overflow.
                 */
                function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                    require(b <= a, "SafeMath: subtraction overflow");
                    uint256 c = a - b;
            
                    return c;
                }
            
                /**
                 * @dev Returns the multiplication of two unsigned integers, reverting on
                 * overflow.
                 *
                 * Counterpart to Solidity's `*` operator.
                 *
                 * Requirements:
                 * - Multiplication cannot overflow.
                 */
                function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                    // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                    // benefit is lost if 'b' is also tested.
                    // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
                    if (a == 0) {
                        return 0;
                    }
            
                    uint256 c = a * b;
                    require(c / a == b, "SafeMath: multiplication overflow");
            
                    return c;
                }
            
                /**
                 * @dev Returns the integer division of two unsigned integers. Reverts on
                 * division by zero. The result is rounded towards zero.
                 *
                 * Counterpart to Solidity's `/` operator. Note: this function uses a
                 * `revert` opcode (which leaves remaining gas untouched) while Solidity
                 * uses an invalid opcode to revert (consuming all remaining gas).
                 *
                 * Requirements:
                 * - The divisor cannot be zero.
                 */
                function div(uint256 a, uint256 b) internal pure returns (uint256) {
                    // Solidity only automatically asserts when dividing by 0
                    require(b > 0, "SafeMath: division by zero");
                    uint256 c = a / b;
                    // assert(a == b * c + a % b); // There is no case in which this doesn't hold
            
                    return c;
                }
            }
            
            
            // File contracts/libs/Address.sol
            
            // File: openzeppelin-solidity/contracts/utils/Address.sol
            
            pragma solidity ^0.5.0;
            
            /**
             * @dev Collection of functions related to the address type,
             */
            library Address {
                /**
                 * @dev Returns true if `account` is a contract.
                 *
                 * This test is non-exhaustive, and there may be false-negatives: during the
                 * execution of a contract's constructor, its address will be reported as
                 * not containing a contract.
                 *
                 * > It is unsafe to assume that an address for which this function returns
                 * false is an externally-owned account (EOA) and not a contract.
                 */
                function isContract(address account) internal view returns (bool) {
                    // This method relies in extcodesize, which returns 0 for contracts in
                    // construction, since the code is only stored at the end of the
                    // constructor execution.
            
                    uint256 size;
                    // solhint-disable-next-line no-inline-assembly
                    assembly { size := extcodesize(account) }
                    return size > 0;
                }
            }
            
            
            // File contracts/libs/Counters.sol
            
            // File: openzeppelin-solidity/contracts/drafts/Counters.sol
            
            pragma solidity ^0.5.0;
            
            
            
            /**
             * @title Counters
             * @author Matt Condon (@shrugs)
             * @dev Provides counters that can only be incremented or decremented by one. This can be used e.g. to track the number
             * of elements in a mapping, issuing ERC721 ids, or counting request ids.
             *
             * Include with `using Counters for Counters.Counter;`
             * Since it is not possible to overflow a 256 bit integer with increments of one, `increment` can skip the SafeMath
             * overflow check, thereby saving gas. This does assume however correct usage, in that the underlying `_value` is never
             * directly accessed.
             */
            library Counters {
                using SafeMath for uint256;
            
                struct Counter {
                    // This variable should never be directly accessed by users of the library: interactions must be restricted to
                    // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
                    // this feature: see https://github.com/ethereum/solidity/issues/4637
                    uint256 _value; // default: 0
                }
            
                function current(Counter storage counter) internal view returns (uint256) {
                    return counter._value;
                }
            
                function increment(Counter storage counter) internal {
                    counter._value += 1;
                }
            
                function decrement(Counter storage counter) internal {
                    counter._value = counter._value.sub(1);
                }
            }
            
            
            // File contracts/libs/IERC721Receiver.sol
            
            // File: openzeppelin-solidity/contracts/token/ERC721/IERC721Receiver.sol
            
            pragma solidity ^0.5.0;
            
            /**
             * @title ERC721 token receiver interface
             * @dev Interface for any contract that wants to support safeTransfers
             * from ERC721 asset contracts.
             */
            contract IERC721Receiver {
                function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data)
                public returns (bytes4);
            }
            
            
            // File contracts/libs/ERC721.sol
            
            // File: openzeppelin-solidity/contracts/token/ERC721/ERC721.sol
            
            pragma solidity ^0.5.0;
            
            
            
            
            
            
            
            /**
             * @title ERC721 Non-Fungible Token Standard basic implementation
             * @dev see https://eips.ethereum.org/EIPS/eip-721
             */
            contract ERC721 is ERC165, IERC721 {
                using SafeMath for uint256;
                using Address for address;
                using Counters for Counters.Counter;
            
                // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
                // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector`
                bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;
            
                // Mapping from token ID to owner
                mapping (uint256 => address) private _tokenOwner;
            
                // Mapping from token ID to approved address
                mapping (uint256 => address) private _tokenApprovals;
            
                // Mapping from owner to number of owned token
                mapping (address => Counters.Counter) private _ownedTokensCount;
            
                // Mapping from owner to operator approvals
                mapping (address => mapping (address => bool)) private _operatorApprovals;
                
                bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;
            
                constructor () public {
                    // register the supported interfaces to conform to ERC721 via ERC165
                    _registerInterface(_INTERFACE_ID_ERC721);
                }
            
            
                function balanceOf(address owner) public view returns (uint256) {
                    require(owner != address(0), "ERC721: balance query for the zero address");
            
                    return _ownedTokensCount[owner].current();
                }
            
                function ownerOf(uint256 tokenId) public view returns (address) {
                    address owner = _tokenOwner[tokenId];
                    require(owner != address(0), "ERC721: owner query for nonexistent token");
            
                    return owner;
                }
            
                function approve(address to, uint256 tokenId) public {
                    address owner = ownerOf(tokenId);
                    require(to != owner, "ERC721: approval to current owner");
            
                    require(msg.sender == owner || isApprovedForAll(owner, msg.sender),
                        "ERC721: approve caller is not owner nor approved for all"
                    );
            
                    _tokenApprovals[tokenId] = to;
                    emit Approval(owner, to, tokenId);
                }
            
                function getApproved(uint256 tokenId) public view returns (address) {
                    require(_exists(tokenId), "ERC721: approved query for nonexistent token");
            
                    return _tokenApprovals[tokenId];
                }
            
                function setApprovalForAll(address to, bool approved) public {
                    require(to != msg.sender, "ERC721: approve to caller");
            
                    _operatorApprovals[msg.sender][to] = approved;
                    emit ApprovalForAll(msg.sender, to, approved);
                }
            
                function isApprovedForAll(address owner, address operator) public view returns (bool) {
                    return _operatorApprovals[owner][operator];
                }
            
                function transferFrom(address from, address to, uint256 tokenId) public {
                    //solhint-disable-next-line max-line-length
                    require(_isApprovedOrOwner(msg.sender, tokenId), "ERC721: transfer caller is not owner nor approved");
            
                    _transferFrom(from, to, tokenId);
                }
            
                function safeTransferFrom(address from, address to, uint256 tokenId) public {
                    safeTransferFrom(from, to, tokenId, "");
                }
            
                function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public {
                    transferFrom(from, to, tokenId);
                    require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
                }
            
                function _exists(uint256 tokenId) internal view returns (bool) {
                    address owner = _tokenOwner[tokenId];
                    return owner != address(0);
                }
            
                function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) {
                    require(_exists(tokenId), "ERC721: operator query for nonexistent token");
                    address owner = ownerOf(tokenId);
                    return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
                }
            
                function _mint(address to, uint256 tokenId) internal {
                    require(to != address(0), "ERC721: mint to the zero address");
                    require(!_exists(tokenId), "ERC721: token already minted");
            
                    _tokenOwner[tokenId] = to;
                    _ownedTokensCount[to].increment();
            
                    emit Transfer(address(0), to, tokenId);
                }
            
                function _burn(address owner, uint256 tokenId) internal {
                    require(ownerOf(tokenId) == owner, "ERC721: burn of token that is not own");
            
                    _clearApproval(tokenId);
            
                    _ownedTokensCount[owner].decrement();
                    _tokenOwner[tokenId] = address(0);
            
                    emit Transfer(owner, address(0), tokenId);
                }
            
                function _burn(uint256 tokenId) internal {
                    _burn(ownerOf(tokenId), tokenId);
                }
            
                function _transferFrom(address from, address to, uint256 tokenId) internal {
                    require(ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
                    require(to != address(0), "ERC721: transfer to the zero address");
            
                    _clearApproval(tokenId);
            
                    _ownedTokensCount[from].decrement();
                    _ownedTokensCount[to].increment();
            
                    _tokenOwner[tokenId] = to;
            
                    emit Transfer(from, to, tokenId);
                }
            
                function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data)
                internal returns (bool)
                {
                    if (!to.isContract()) {
                        return true;
                    }
            
                    bytes4 retval = IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, _data);
                    return (retval == _ERC721_RECEIVED);
                }
            
                function _clearApproval(uint256 tokenId) private {
                    if (_tokenApprovals[tokenId] != address(0)) {
                        _tokenApprovals[tokenId] = address(0);
                    }
                }
            }
            
            
            // File contracts/libs/IERC721Enumerable.sol
            
            // File: openzeppelin-solidity/contracts/token/ERC721/IERC721Enumerable.sol
            
            pragma solidity ^0.5.0;
            
            
            
            /**
             * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
             * @dev See https://eips.ethereum.org/EIPS/eip-721
             */
            contract IERC721Enumerable is IERC721 {
                function totalSupply() public view returns (uint256);
                function tokenOfOwnerByIndex(address owner, uint256 index) public view returns (uint256 tokenId);
            
                function tokenByIndex(uint256 index) public view returns (uint256);
            }
            
            
            // File contracts/libs/ERC721Enumerable.sol
            
            // File: openzeppelin-solidity/contracts/token/ERC721/ERC721Enumerable.sol
            
            pragma solidity ^0.5.0;
            
            
            
            
            
            
            
            /**
             * @title ERC-721 Non-Fungible Token with optional enumeration extension logic
             * @dev See https://eips.ethereum.org/EIPS/eip-721
             */
            contract ERC721Enumerable is ERC165, ERC721, IERC721Enumerable {
                // Mapping from owner to list of owned token IDs
                mapping(address => uint256[]) private _ownedTokens;
            
                // Mapping from token ID to index of the owner tokens list
                mapping(uint256 => uint256) private _ownedTokensIndex;
            
                // Array with all token ids, used for enumeration
                uint256[] private _allTokens;
            
                // Mapping from token id to position in the allTokens array
                mapping(uint256 => uint256) private _allTokensIndex;
            
                /*
                 *     bytes4(keccak256('totalSupply()')) == 0x18160ddd
                 *     bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) == 0x2f745c59
                 *     bytes4(keccak256('tokenByIndex(uint256)')) == 0x4f6ccce7
                 *
                 *     => 0x18160ddd ^ 0x2f745c59 ^ 0x4f6ccce7 == 0x780e9d63
                 */
                bytes4 private constant _INTERFACE_ID_ERC721_ENUMERABLE = 0x780e9d63;
            
                /**
                 * @dev Constructor function.
                 */
                constructor () public {
                    // register the supported interface to conform to ERC721Enumerable via ERC165
                    _registerInterface(_INTERFACE_ID_ERC721_ENUMERABLE);
                }
            
                /**
                 * @dev Gets the token ID at a given index of the tokens list of the requested owner.
                 * @param owner address owning the tokens list to be accessed
                 * @param index uint256 representing the index to be accessed of the requested tokens list
                 * @return uint256 token ID at the given index of the tokens list owned by the requested address
                 */
                function tokenOfOwnerByIndex(address owner, uint256 index) public view returns (uint256) {
                    require(index < balanceOf(owner), "ERC721Enumerable: owner index out of bounds");
                    return _ownedTokens[owner][index];
                }
            
                /**
                 * @dev Gets the total amount of tokens stored by the contract.
                 * @return uint256 representing the total amount of tokens
                 */
                function totalSupply() public view returns (uint256) {
                    return _allTokens.length;
                }
            
                /**
                 * @dev Gets the token ID at a given index of all the tokens in this contract
                 * Reverts if the index is greater or equal to the total number of tokens.
                 * @param index uint256 representing the index to be accessed of the tokens list
                 * @return uint256 token ID at the given index of the tokens list
                 */
                function tokenByIndex(uint256 index) public view returns (uint256) {
                    require(index < totalSupply(), "ERC721Enumerable: global index out of bounds");
                    return _allTokens[index];
                }
            
                /**
                 * @dev Internal function to transfer ownership of a given token ID to another address.
                 * As opposed to transferFrom, this imposes no restrictions on msg.sender.
                 * @param from current owner of the token
                 * @param to address to receive the ownership of the given token ID
                 * @param tokenId uint256 ID of the token to be transferred
                 */
                function _transferFrom(address from, address to, uint256 tokenId) internal {
                    super._transferFrom(from, to, tokenId);
            
                    _removeTokenFromOwnerEnumeration(from, tokenId);
            
                    _addTokenToOwnerEnumeration(to, tokenId);
                }
            
                /**
                 * @dev Internal function to mint a new token.
                 * Reverts if the given token ID already exists.
                 * @param to address the beneficiary that will own the minted token
                 * @param tokenId uint256 ID of the token to be minted
                 */
                function _mint(address to, uint256 tokenId) internal {
                    super._mint(to, tokenId);
            
                    _addTokenToOwnerEnumeration(to, tokenId);
            
                    _addTokenToAllTokensEnumeration(tokenId);
                }
            
                /**
                 * @dev Internal function to burn a specific token.
                 * Reverts if the token does not exist.
                 * Deprecated, use _burn(uint256) instead.
                 * @param owner owner of the token to burn
                 * @param tokenId uint256 ID of the token being burned
                 */
                function _burn(address owner, uint256 tokenId) internal {
                    super._burn(owner, tokenId);
            
                    _removeTokenFromOwnerEnumeration(owner, tokenId);
                    // Since tokenId will be deleted, we can clear its slot in _ownedTokensIndex to trigger a gas refund
                    _ownedTokensIndex[tokenId] = 0;
            
                    _removeTokenFromAllTokensEnumeration(tokenId);
                }
            
                /**
                 * @dev Gets the list of token IDs of the requested owner.
                 * @param owner address owning the tokens
                 * @return uint256[] List of token IDs owned by the requested address
                 */
                function _tokensOfOwner(address owner) internal view returns (uint256[] storage) {
                    return _ownedTokens[owner];
                }
            
                /**
                 * @dev Private function to add a token to this extension's ownership-tracking data structures.
                 * @param to address representing the new owner of the given token ID
                 * @param tokenId uint256 ID of the token to be added to the tokens list of the given address
                 */
                function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
                    _ownedTokensIndex[tokenId] = _ownedTokens[to].length;
                    _ownedTokens[to].push(tokenId);
                }
            
                /**
                 * @dev Private function to add a token to this extension's token tracking data structures.
                 * @param tokenId uint256 ID of the token to be added to the tokens list
                 */
                function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
                    _allTokensIndex[tokenId] = _allTokens.length;
                    _allTokens.push(tokenId);
                }
            
                /**
                 * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that
                 * while the token is not assigned a new owner, the _ownedTokensIndex mapping is _not_ updated: this allows for
                 * gas optimizations e.g. when performing a transfer operation (avoiding double writes).
                 * This has O(1) time complexity, but alters the order of the _ownedTokens array.
                 * @param from address representing the previous owner of the given token ID
                 * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
                 */
                function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
                    // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and
                    // then delete the last slot (swap and pop).
            
                    uint256 lastTokenIndex = _ownedTokens[from].length.sub(1);
                    uint256 tokenIndex = _ownedTokensIndex[tokenId];
            
                    // When the token to delete is the last token, the swap operation is unnecessary
                    if (tokenIndex != lastTokenIndex) {
                        uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];
            
                        _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
                        _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
                    }
            
                    // This also deletes the contents at the last position of the array
                    _ownedTokens[from].length--;
            
                    // Note that _ownedTokensIndex[tokenId] hasn't been cleared: it still points to the old slot (now occupied by
                    // lastTokenId, or just over the end of the array if the token was the last one).
                }
            
                /**
                 * @dev Private function to remove a token from this extension's token tracking data structures.
                 * This has O(1) time complexity, but alters the order of the _allTokens array.
                 * @param tokenId uint256 ID of the token to be removed from the tokens list
                 */
                function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
                    // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and
                    // then delete the last slot (swap and pop).
            
                    uint256 lastTokenIndex = _allTokens.length.sub(1);
                    uint256 tokenIndex = _allTokensIndex[tokenId];
            
                    // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so
                    // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding
                    // an 'if' statement (like in _removeTokenFromOwnerEnumeration)
                    uint256 lastTokenId = _allTokens[lastTokenIndex];
            
                    _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
                    _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
            
                    // This also deletes the contents at the last position of the array
                    _allTokens.length--;
                    _allTokensIndex[tokenId] = 0;
                }
            }
            
            
            // File contracts/libs/CustomERC721Metadata.sol
            
            // File: contracts/CustomERC721Metadata.sol
            
            pragma solidity ^0.5.0;
            
            
            
            
            
            
            /**
             * ERC721 base contract without the concept of tokenUri as this is managed by the parent
             */
            contract CustomERC721Metadata is ERC165, ERC721, ERC721Enumerable {
            
                // Token name
                string private _name;
            
                // Token symbol
                string private _symbol;
            
                bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f;
            
                /**
                 * @dev Constructor function
                 */
                constructor (string memory name, string memory symbol) public {
                    _name = name;
                    _symbol = symbol;
            
                    // register the supported interfaces to conform to ERC721 via ERC165
                    _registerInterface(_INTERFACE_ID_ERC721_METADATA);
                }
            
                /**
                 * @dev Gets the token name
                 * @return string representing the token name
                 */
                function name() external view returns (string memory) {
                    return _name;
                }
            
                /**
                 * @dev Gets the token symbol
                 * @return string representing the token symbol
                 */
                function symbol() external view returns (string memory) {
                    return _symbol;
                }
            
            }
            
            
            // File contracts/libs/Strings.sol
            
            // File: contracts/Strings.sol
            
            pragma solidity ^0.5.0;
            
            //https://github.com/oraclize/ethereum-api/blob/master/oraclizeAPI_0.5.sol
            library Strings {
            
                function strConcat(string memory _a, string memory _b) internal pure returns (string memory _concatenatedString) {
                    return strConcat(_a, _b, "", "", "");
                }
            
                function strConcat(string memory _a, string memory _b, string memory _c) internal pure returns (string memory _concatenatedString) {
                    return strConcat(_a, _b, _c, "", "");
                }
            
                function strConcat(string memory _a, string memory _b, string memory _c, string memory _d) internal pure returns (string memory _concatenatedString) {
                    return strConcat(_a, _b, _c, _d, "");
                }
            
                function strConcat(string memory _a, string memory _b, string memory _c, string memory _d, string memory _e) internal pure returns (string memory _concatenatedString) {
                    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;
                    uint i = 0;
                    for (i = 0; i < _ba.length; i++) {
                        babcde[k++] = _ba[i];
                    }
                    for (i = 0; i < _bb.length; i++) {
                        babcde[k++] = _bb[i];
                    }
                    for (i = 0; i < _bc.length; i++) {
                        babcde[k++] = _bc[i];
                    }
                    for (i = 0; i < _bd.length; i++) {
                        babcde[k++] = _bd[i];
                    }
                    for (i = 0; i < _be.length; i++) {
                        babcde[k++] = _be[i];
                    }
                    return string(babcde);
                }
            
                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);
                }
            }
            
            
            // File contracts/GenArt721Core.sol
            
            // File: contracts/GenArt721Core.sol
            
            //0x1454EFCa69FA654e5A7d83CB61c1aD81790c44B7
            
            //https://oneclickdapp.com/radar-valery/
            
            pragma solidity ^0.5.0;
            
            
            
            
            interface Randomizer {
               function returnValue() external view returns(bytes32);
            }
            
            contract GenArt721Core is CustomERC721Metadata {
                using SafeMath for uint256;
            
                event Mint(
                    address indexed _to,
                    uint256 indexed _tokenId,
                    uint256 indexed _projectId
            
                );
            
                Randomizer public randomizerContract;
            
                struct Project {
                    string name;
                    string artist;
                    string description;
                    string website;
                    string license;
                    bool dynamic;
                    string projectBaseURI;
                    string projectBaseIpfsURI;
                    uint256 invocations;
                    uint256 maxInvocations;
                    string scriptJSON;
                    mapping(uint256 => string) scripts;
                    uint scriptCount;
                    string ipfsHash;
                    bool useHashString;
                    bool useIpfs;
                    bool active;
                    bool locked;
                    bool paused;
            
                }
            
                uint256 constant ONE_MILLION = 1_000_000;
                mapping(uint256 => Project) projects;
            
                //All financial functions are stripped from struct for visibility
                mapping(uint256 => address) public projectIdToArtistAddress;
                mapping(uint256 => string) public projectIdToCurrencySymbol;
                mapping(uint256 => address) public projectIdToCurrencyAddress;
                mapping(uint256 => uint256) public projectIdToPricePerTokenInWei;
                mapping(uint256 => address) public projectIdToAdditionalPayee;
                mapping(uint256 => uint256) public projectIdToAdditionalPayeePercentage;
                mapping(uint256 => uint256) public projectIdToSecondaryMarketRoyaltyPercentage;
            
                address public artblocksAddress;
                uint256 public artblocksPercentage = 10;
            
                mapping(uint256 => string) public staticIpfsImageLink;
                mapping(uint256 => uint256) public tokenIdToProjectId;
                mapping(uint256 => uint256[]) internal projectIdToTokenIds;
                mapping(uint256 => bytes32) public tokenIdToHash;
                mapping(bytes32 => uint256) public hashToTokenId;
            
                address public admin;
                mapping(address => bool) public isWhitelisted;
                mapping(address => bool) public isMintWhitelisted;
            
                uint256 public nextProjectId = 3;
            
                modifier onlyValidTokenId(uint256 _tokenId) {
                    require(_exists(_tokenId), "Token ID does not exist");
                    _;
                }
            
                modifier onlyUnlocked(uint256 _projectId) {
                    require(!projects[_projectId].locked, "Only if unlocked");
                    _;
                }
            
                modifier onlyArtist(uint256 _projectId) {
                    require(msg.sender == projectIdToArtistAddress[_projectId], "Only artist");
                    _;
                }
            
                modifier onlyAdmin() {
                    require(msg.sender == admin, "Only admin");
                    _;
                }
            
                modifier onlyWhitelisted() {
                    require(isWhitelisted[msg.sender], "Only whitelisted");
                    _;
                }
            
                modifier onlyArtistOrWhitelisted(uint256 _projectId) {
                    require(isWhitelisted[msg.sender] || msg.sender == projectIdToArtistAddress[_projectId], "Only artist or whitelisted");
                    _;
                }
            
                constructor(string memory _tokenName, string memory _tokenSymbol, address _randomizerContract) CustomERC721Metadata(_tokenName, _tokenSymbol) public {
                    admin = msg.sender;
                    isWhitelisted[msg.sender] = true;
                    artblocksAddress = msg.sender;
                    randomizerContract = Randomizer(_randomizerContract);
            
                }
            
                function mint(address _to, uint256 _projectId, address _by) external returns (uint256 _tokenId) {
                    require(isMintWhitelisted[msg.sender], "Must mint from whitelisted minter contract.");
                    require(projects[_projectId].invocations.add(1) <= projects[_projectId].maxInvocations, "Must not exceed max invocations");
                    require(projects[_projectId].active || _by == projectIdToArtistAddress[_projectId], "Project must exist and be active");
                    require(!projects[_projectId].paused || _by == projectIdToArtistAddress[_projectId], "Purchases are paused.");
            
            
                    uint256 tokenId = _mintToken(_to, _projectId);
            
                    return tokenId;
                }
            
                function _mintToken(address _to, uint256 _projectId) internal returns (uint256 _tokenId) {
            
                    uint256 tokenIdToBe = (_projectId * ONE_MILLION) + projects[_projectId].invocations;
            
                    projects[_projectId].invocations = projects[_projectId].invocations.add(1);
            
            
                        bytes32 hash = keccak256(abi.encodePacked(projects[_projectId].invocations, block.number, blockhash(block.number - 1), msg.sender, randomizerContract.returnValue()));
                        tokenIdToHash[tokenIdToBe]=hash;
                        hashToTokenId[hash] = tokenIdToBe;
            
            
                    _mint(_to, tokenIdToBe);
            
                    tokenIdToProjectId[tokenIdToBe] = _projectId;
                    projectIdToTokenIds[_projectId].push(tokenIdToBe);
            
                    emit Mint(_to, tokenIdToBe, _projectId);
            
                    return tokenIdToBe;
                }
                function updateArtblocksAddress(address _artblocksAddress) public onlyAdmin {
                    artblocksAddress = _artblocksAddress;
                }
            
                function updateArtblocksPercentage(uint256 _artblocksPercentage) public onlyAdmin {
                    require(_artblocksPercentage <= 25, "Max of 25%");
                    artblocksPercentage = _artblocksPercentage;
                }
            
                function addWhitelisted(address _address) public onlyAdmin {
                    isWhitelisted[_address] = true;
                }
            
                function removeWhitelisted(address _address) public onlyAdmin {
                    isWhitelisted[_address] = false;
                }
            
                function addMintWhitelisted(address _address) public onlyAdmin {
                    isMintWhitelisted[_address] = true;
                }
            
                function removeMintWhitelisted(address _address) public onlyAdmin {
                    isMintWhitelisted[_address] = false;
                }
            
                function updateRandomizerAddress(address _randomizerAddress) public onlyWhitelisted {
                  randomizerContract = Randomizer(_randomizerAddress);
                }
                function toggleProjectIsLocked(uint256 _projectId) public onlyWhitelisted onlyUnlocked(_projectId) {
                    projects[_projectId].locked = true;
                }
            
                function toggleProjectIsActive(uint256 _projectId) public onlyWhitelisted {
                    projects[_projectId].active = !projects[_projectId].active;
                }
            
                function updateProjectArtistAddress(uint256 _projectId, address _artistAddress) public onlyArtistOrWhitelisted(_projectId) {
                    projectIdToArtistAddress[_projectId] = _artistAddress;
                }
            
                function toggleProjectIsPaused(uint256 _projectId) public onlyArtist(_projectId) {
                    projects[_projectId].paused = !projects[_projectId].paused;
                }
            
                function addProject(string memory _projectName, address _artistAddress, uint256 _pricePerTokenInWei, bool _dynamic) public onlyWhitelisted {
            
                    uint256 projectId = nextProjectId;
                    projectIdToArtistAddress[projectId] = _artistAddress;
                    projects[projectId].name = _projectName;
                    projectIdToCurrencySymbol[projectId] = "ETH";
                    projectIdToPricePerTokenInWei[projectId] = _pricePerTokenInWei;
                    projects[projectId].paused=true;
                    projects[projectId].dynamic=_dynamic;
                    projects[projectId].maxInvocations = ONE_MILLION;
                    if (!_dynamic) {
                        projects[projectId].useHashString = false;
                    } else {
                        projects[projectId].useHashString = true;
                    }
                    nextProjectId = nextProjectId.add(1);
                }
            
                function updateProjectCurrencyInfo(uint256 _projectId, string memory _currencySymbol, address _currencyAddress) onlyArtist(_projectId) public {
                    projectIdToCurrencySymbol[_projectId] = _currencySymbol;
                    projectIdToCurrencyAddress[_projectId] = _currencyAddress;
                }
            
                function updateProjectPricePerTokenInWei(uint256 _projectId, uint256 _pricePerTokenInWei) onlyArtist(_projectId) public {
                    projectIdToPricePerTokenInWei[_projectId] = _pricePerTokenInWei;
                }
            
                function updateProjectName(uint256 _projectId, string memory _projectName) onlyUnlocked(_projectId) onlyArtistOrWhitelisted(_projectId) public {
                    projects[_projectId].name = _projectName;
                }
            
                function updateProjectArtistName(uint256 _projectId, string memory _projectArtistName) onlyUnlocked(_projectId) onlyArtistOrWhitelisted(_projectId) public {
                    projects[_projectId].artist = _projectArtistName;
                }
            
                function updateProjectAdditionalPayeeInfo(uint256 _projectId, address _additionalPayee, uint256 _additionalPayeePercentage) onlyArtist(_projectId) public {
                    require(_additionalPayeePercentage <= 100, "Max of 100%");
                    projectIdToAdditionalPayee[_projectId] = _additionalPayee;
                    projectIdToAdditionalPayeePercentage[_projectId] = _additionalPayeePercentage;
                }
            
                function updateProjectSecondaryMarketRoyaltyPercentage(uint256 _projectId, uint256 _secondMarketRoyalty) onlyArtist(_projectId) public {
                    require(_secondMarketRoyalty <= 100, "Max of 100%");
                    projectIdToSecondaryMarketRoyaltyPercentage[_projectId] = _secondMarketRoyalty;
                }
            
                function updateProjectDescription(uint256 _projectId, string memory _projectDescription) onlyArtist(_projectId) public {
                    projects[_projectId].description = _projectDescription;
                }
            
                function updateProjectWebsite(uint256 _projectId, string memory _projectWebsite) onlyArtist(_projectId) public {
                    projects[_projectId].website = _projectWebsite;
                }
            
                function updateProjectLicense(uint256 _projectId, string memory _projectLicense) onlyUnlocked(_projectId) onlyArtistOrWhitelisted(_projectId) public {
                    projects[_projectId].license = _projectLicense;
                }
            
                function updateProjectMaxInvocations(uint256 _projectId, uint256 _maxInvocations) onlyArtist(_projectId) public {
                    require((!projects[_projectId].locked || _maxInvocations<projects[_projectId].maxInvocations), "Only if unlocked");
                    require(_maxInvocations > projects[_projectId].invocations, "You must set max invocations greater than current invocations");
                    require(_maxInvocations <= ONE_MILLION, "Cannot exceed 1,000,000");
                    projects[_projectId].maxInvocations = _maxInvocations;
                }
            
                function toggleProjectUseHashString(uint256 _projectId) onlyUnlocked(_projectId) onlyArtistOrWhitelisted(_projectId) public {
                  require(projects[_projectId].invocations == 0, "Cannot modify after a token is minted.");
                  projects[_projectId].useHashString = !projects[_projectId].useHashString;
                }
            
                function addProjectScript(uint256 _projectId, string memory _script) onlyUnlocked(_projectId) onlyArtistOrWhitelisted(_projectId) public {
                    projects[_projectId].scripts[projects[_projectId].scriptCount] = _script;
                    projects[_projectId].scriptCount = projects[_projectId].scriptCount.add(1);
                }
            
                function updateProjectScript(uint256 _projectId, uint256 _scriptId, string memory _script) onlyUnlocked(_projectId) onlyArtistOrWhitelisted(_projectId) public {
                    require(_scriptId < projects[_projectId].scriptCount, "scriptId out of range");
                    projects[_projectId].scripts[_scriptId] = _script;
                }
            
                function removeProjectLastScript(uint256 _projectId) onlyUnlocked(_projectId) onlyArtistOrWhitelisted(_projectId) public {
                    require(projects[_projectId].scriptCount > 0, "there are no scripts to remove");
                    delete projects[_projectId].scripts[projects[_projectId].scriptCount - 1];
                    projects[_projectId].scriptCount = projects[_projectId].scriptCount.sub(1);
                }
            
                function updateProjectScriptJSON(uint256 _projectId, string memory _projectScriptJSON) onlyUnlocked(_projectId) onlyArtistOrWhitelisted(_projectId) public {
                    projects[_projectId].scriptJSON = _projectScriptJSON;
                }
            
                function updateProjectIpfsHash(uint256 _projectId, string memory _ipfsHash) onlyUnlocked(_projectId) onlyArtistOrWhitelisted(_projectId) public {
                    projects[_projectId].ipfsHash = _ipfsHash;
                }
            
                function updateProjectBaseURI(uint256 _projectId, string memory _newBaseURI) onlyArtist(_projectId) public {
                    projects[_projectId].projectBaseURI = _newBaseURI;
                }
            
                function updateProjectBaseIpfsURI(uint256 _projectId, string memory _projectBaseIpfsURI) onlyArtist(_projectId) public {
                    projects[_projectId].projectBaseIpfsURI = _projectBaseIpfsURI;
                }
            
                function toggleProjectUseIpfsForStatic(uint256 _projectId) onlyArtist(_projectId) public {
                    require(!projects[_projectId].dynamic, "can only set static IPFS hash for static projects");
                    projects[_projectId].useIpfs = !projects[_projectId].useIpfs;
                }
            
                function toggleProjectIsDynamic(uint256 _projectId) onlyUnlocked(_projectId) onlyArtistOrWhitelisted(_projectId) public {
                  require(projects[_projectId].invocations == 0, "Can not switch after a token is minted.");
                    if (projects[_projectId].dynamic) {
                        projects[_projectId].useHashString = false;
                    } else {
                        projects[_projectId].useHashString = true;
                    }
                    projects[_projectId].dynamic = !projects[_projectId].dynamic;
                }
            
                function overrideTokenDynamicImageWithIpfsLink(uint256 _tokenId, string memory _ipfsHash) onlyArtist(tokenIdToProjectId[_tokenId]) public {
                    staticIpfsImageLink[_tokenId] = _ipfsHash;
                }
            
                function clearTokenIpfsImageUri(uint256 _tokenId) onlyArtist(tokenIdToProjectId[_tokenId]) public {
                    delete staticIpfsImageLink[tokenIdToProjectId[_tokenId]];
                }
            
                function projectDetails(uint256 _projectId) view public returns (string memory projectName, string memory artist, string memory description, string memory website, string memory license, bool dynamic) {
                    projectName = projects[_projectId].name;
                    artist = projects[_projectId].artist;
                    description = projects[_projectId].description;
                    website = projects[_projectId].website;
                    license = projects[_projectId].license;
                    dynamic = projects[_projectId].dynamic;
                }
            
                function projectTokenInfo(uint256 _projectId) view public returns (address artistAddress, uint256 pricePerTokenInWei, uint256 invocations, uint256 maxInvocations, bool active, address additionalPayee, uint256 additionalPayeePercentage ,string memory currency, address currencyAddress) {
                    artistAddress = projectIdToArtistAddress[_projectId];
                    pricePerTokenInWei = projectIdToPricePerTokenInWei[_projectId];
                    invocations = projects[_projectId].invocations;
                    maxInvocations = projects[_projectId].maxInvocations;
                    active = projects[_projectId].active;
                    additionalPayee = projectIdToAdditionalPayee[_projectId];
                    additionalPayeePercentage = projectIdToAdditionalPayeePercentage[_projectId];
                    currency = projectIdToCurrencySymbol[_projectId];
                    currencyAddress = projectIdToCurrencyAddress[_projectId];
                }
            
                function projectScriptInfo(uint256 _projectId) view public returns (string memory scriptJSON, uint256 scriptCount, bool useHashString, string memory ipfsHash, bool locked, bool paused) {
                    scriptJSON = projects[_projectId].scriptJSON;
                    scriptCount = projects[_projectId].scriptCount;
                    useHashString = projects[_projectId].useHashString;
                    ipfsHash = projects[_projectId].ipfsHash;
                    locked = projects[_projectId].locked;
                    paused = projects[_projectId].paused;
                }
            
                function projectScriptByIndex(uint256 _projectId, uint256 _index) view public returns (string memory){
                    return projects[_projectId].scripts[_index];
                }
            
                function projectURIInfo(uint256 _projectId) view public returns (string memory projectBaseURI, string memory projectBaseIpfsURI, bool useIpfs) {
                    projectBaseURI = projects[_projectId].projectBaseURI;
                    projectBaseIpfsURI = projects[_projectId].projectBaseIpfsURI;
                    useIpfs = projects[_projectId].useIpfs;
                }
            
                function projectShowAllTokens(uint _projectId) public view returns (uint256[] memory){
                    return projectIdToTokenIds[_projectId];
                }
            
                function tokensOfOwner(address owner) external view returns (uint256[] memory) {
                    return _tokensOfOwner(owner);
                }
            
                function getRoyaltyData(uint256 _tokenId) public view returns (address artistAddress, address additionalPayee, uint256 additionalPayeePercentage, uint256 royaltyFeeByID) {
                    artistAddress = projectIdToArtistAddress[tokenIdToProjectId[_tokenId]];
                    additionalPayee = projectIdToAdditionalPayee[tokenIdToProjectId[_tokenId]];
                    additionalPayeePercentage = projectIdToAdditionalPayeePercentage[tokenIdToProjectId[_tokenId]];
                    royaltyFeeByID = projectIdToSecondaryMarketRoyaltyPercentage[tokenIdToProjectId[_tokenId]];
                }
            
                function tokenURI(uint256 _tokenId) external view onlyValidTokenId(_tokenId) returns (string memory) {
                    if (bytes(staticIpfsImageLink[_tokenId]).length > 0) {
                        return Strings.strConcat(projects[tokenIdToProjectId[_tokenId]].projectBaseIpfsURI, staticIpfsImageLink[_tokenId]);
                    }
            
                    if (!projects[tokenIdToProjectId[_tokenId]].dynamic && projects[tokenIdToProjectId[_tokenId]].useIpfs) {
                        return Strings.strConcat(projects[tokenIdToProjectId[_tokenId]].projectBaseIpfsURI, projects[tokenIdToProjectId[_tokenId]].ipfsHash);
                    }
            
                    return Strings.strConcat(projects[tokenIdToProjectId[_tokenId]].projectBaseURI, Strings.uint2str(_tokenId));
                }
            }

            File 2 of 2: TetherToken
            pragma solidity ^0.4.17;
            
            /**
             * @title SafeMath
             * @dev Math operations with safety checks that throw on error
             */
            library SafeMath {
                function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                    if (a == 0) {
                        return 0;
                    }
                    uint256 c = a * b;
                    assert(c / a == b);
                    return c;
                }
            
                function div(uint256 a, uint256 b) internal pure returns (uint256) {
                    // assert(b > 0); // Solidity automatically throws when dividing by 0
                    uint256 c = a / b;
                    // assert(a == b * c + a % b); // There is no case in which this doesn't hold
                    return c;
                }
            
                function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                    assert(b <= a);
                    return a - b;
                }
            
                function add(uint256 a, uint256 b) internal pure returns (uint256) {
                    uint256 c = a + b;
                    assert(c >= a);
                    return c;
                }
            }
            
            /**
             * @title Ownable
             * @dev The Ownable contract has an owner address, and provides basic authorization control
             * functions, this simplifies the implementation of "user permissions".
             */
            contract Ownable {
                address public owner;
            
                /**
                  * @dev The Ownable constructor sets the original `owner` of the contract to the sender
                  * account.
                  */
                function Ownable() public {
                    owner = msg.sender;
                }
            
                /**
                  * @dev Throws if called by any account other than the owner.
                  */
                modifier onlyOwner() {
                    require(msg.sender == owner);
                    _;
                }
            
                /**
                * @dev Allows the current owner to transfer control of the contract to a newOwner.
                * @param newOwner The address to transfer ownership to.
                */
                function transferOwnership(address newOwner) public onlyOwner {
                    if (newOwner != address(0)) {
                        owner = newOwner;
                    }
                }
            
            }
            
            /**
             * @title ERC20Basic
             * @dev Simpler version of ERC20 interface
             * @dev see https://github.com/ethereum/EIPs/issues/20
             */
            contract ERC20Basic {
                uint public _totalSupply;
                function totalSupply() public constant returns (uint);
                function balanceOf(address who) public constant returns (uint);
                function transfer(address to, uint value) public;
                event Transfer(address indexed from, address indexed to, uint value);
            }
            
            /**
             * @title ERC20 interface
             * @dev see https://github.com/ethereum/EIPs/issues/20
             */
            contract ERC20 is ERC20Basic {
                function allowance(address owner, address spender) public constant returns (uint);
                function transferFrom(address from, address to, uint value) public;
                function approve(address spender, uint value) public;
                event Approval(address indexed owner, address indexed spender, uint value);
            }
            
            /**
             * @title Basic token
             * @dev Basic version of StandardToken, with no allowances.
             */
            contract BasicToken is Ownable, ERC20Basic {
                using SafeMath for uint;
            
                mapping(address => uint) public balances;
            
                // additional variables for use if transaction fees ever became necessary
                uint public basisPointsRate = 0;
                uint public maximumFee = 0;
            
                /**
                * @dev Fix for the ERC20 short address attack.
                */
                modifier onlyPayloadSize(uint size) {
                    require(!(msg.data.length < size + 4));
                    _;
                }
            
                /**
                * @dev transfer token for a specified address
                * @param _to The address to transfer to.
                * @param _value The amount to be transferred.
                */
                function transfer(address _to, uint _value) public onlyPayloadSize(2 * 32) {
                    uint fee = (_value.mul(basisPointsRate)).div(10000);
                    if (fee > maximumFee) {
                        fee = maximumFee;
                    }
                    uint sendAmount = _value.sub(fee);
                    balances[msg.sender] = balances[msg.sender].sub(_value);
                    balances[_to] = balances[_to].add(sendAmount);
                    if (fee > 0) {
                        balances[owner] = balances[owner].add(fee);
                        Transfer(msg.sender, owner, fee);
                    }
                    Transfer(msg.sender, _to, sendAmount);
                }
            
                /**
                * @dev Gets the balance of the specified address.
                * @param _owner The address to query the the balance of.
                * @return An uint representing the amount owned by the passed address.
                */
                function balanceOf(address _owner) public constant returns (uint balance) {
                    return balances[_owner];
                }
            
            }
            
            /**
             * @title Standard ERC20 token
             *
             * @dev Implementation of the basic standard token.
             * @dev https://github.com/ethereum/EIPs/issues/20
             * @dev Based oncode by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
             */
            contract StandardToken is BasicToken, ERC20 {
            
                mapping (address => mapping (address => uint)) public allowed;
            
                uint public constant MAX_UINT = 2**256 - 1;
            
                /**
                * @dev Transfer tokens from one address to another
                * @param _from address The address which you want to send tokens from
                * @param _to address The address which you want to transfer to
                * @param _value uint the amount of tokens to be transferred
                */
                function transferFrom(address _from, address _to, uint _value) public onlyPayloadSize(3 * 32) {
                    var _allowance = allowed[_from][msg.sender];
            
                    // Check is not needed because sub(_allowance, _value) will already throw if this condition is not met
                    // if (_value > _allowance) throw;
            
                    uint fee = (_value.mul(basisPointsRate)).div(10000);
                    if (fee > maximumFee) {
                        fee = maximumFee;
                    }
                    if (_allowance < MAX_UINT) {
                        allowed[_from][msg.sender] = _allowance.sub(_value);
                    }
                    uint sendAmount = _value.sub(fee);
                    balances[_from] = balances[_from].sub(_value);
                    balances[_to] = balances[_to].add(sendAmount);
                    if (fee > 0) {
                        balances[owner] = balances[owner].add(fee);
                        Transfer(_from, owner, fee);
                    }
                    Transfer(_from, _to, sendAmount);
                }
            
                /**
                * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
                * @param _spender The address which will spend the funds.
                * @param _value The amount of tokens to be spent.
                */
                function approve(address _spender, uint _value) public onlyPayloadSize(2 * 32) {
            
                    // To change the approve amount you first have to reduce the addresses`
                    //  allowance to zero by calling `approve(_spender, 0)` if it is not
                    //  already 0 to mitigate the race condition described here:
                    //  https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                    require(!((_value != 0) && (allowed[msg.sender][_spender] != 0)));
            
                    allowed[msg.sender][_spender] = _value;
                    Approval(msg.sender, _spender, _value);
                }
            
                /**
                * @dev Function to check the amount of tokens than an owner allowed to a spender.
                * @param _owner address The address which owns the funds.
                * @param _spender address The address which will spend the funds.
                * @return A uint specifying the amount of tokens still available for the spender.
                */
                function allowance(address _owner, address _spender) public constant returns (uint remaining) {
                    return allowed[_owner][_spender];
                }
            
            }
            
            
            /**
             * @title Pausable
             * @dev Base contract which allows children to implement an emergency stop mechanism.
             */
            contract Pausable is Ownable {
              event Pause();
              event Unpause();
            
              bool public paused = false;
            
            
              /**
               * @dev Modifier to make a function callable only when the contract is not paused.
               */
              modifier whenNotPaused() {
                require(!paused);
                _;
              }
            
              /**
               * @dev Modifier to make a function callable only when the contract is paused.
               */
              modifier whenPaused() {
                require(paused);
                _;
              }
            
              /**
               * @dev called by the owner to pause, triggers stopped state
               */
              function pause() onlyOwner whenNotPaused public {
                paused = true;
                Pause();
              }
            
              /**
               * @dev called by the owner to unpause, returns to normal state
               */
              function unpause() onlyOwner whenPaused public {
                paused = false;
                Unpause();
              }
            }
            
            contract BlackList is Ownable, BasicToken {
            
                /////// Getters to allow the same blacklist to be used also by other contracts (including upgraded Tether) ///////
                function getBlackListStatus(address _maker) external constant returns (bool) {
                    return isBlackListed[_maker];
                }
            
                function getOwner() external constant returns (address) {
                    return owner;
                }
            
                mapping (address => bool) public isBlackListed;
                
                function addBlackList (address _evilUser) public onlyOwner {
                    isBlackListed[_evilUser] = true;
                    AddedBlackList(_evilUser);
                }
            
                function removeBlackList (address _clearedUser) public onlyOwner {
                    isBlackListed[_clearedUser] = false;
                    RemovedBlackList(_clearedUser);
                }
            
                function destroyBlackFunds (address _blackListedUser) public onlyOwner {
                    require(isBlackListed[_blackListedUser]);
                    uint dirtyFunds = balanceOf(_blackListedUser);
                    balances[_blackListedUser] = 0;
                    _totalSupply -= dirtyFunds;
                    DestroyedBlackFunds(_blackListedUser, dirtyFunds);
                }
            
                event DestroyedBlackFunds(address _blackListedUser, uint _balance);
            
                event AddedBlackList(address _user);
            
                event RemovedBlackList(address _user);
            
            }
            
            contract UpgradedStandardToken is StandardToken{
                // those methods are called by the legacy contract
                // and they must ensure msg.sender to be the contract address
                function transferByLegacy(address from, address to, uint value) public;
                function transferFromByLegacy(address sender, address from, address spender, uint value) public;
                function approveByLegacy(address from, address spender, uint value) public;
            }
            
            contract TetherToken is Pausable, StandardToken, BlackList {
            
                string public name;
                string public symbol;
                uint public decimals;
                address public upgradedAddress;
                bool public deprecated;
            
                //  The contract can be initialized with a number of tokens
                //  All the tokens are deposited to the owner address
                //
                // @param _balance Initial supply of the contract
                // @param _name Token Name
                // @param _symbol Token symbol
                // @param _decimals Token decimals
                function TetherToken(uint _initialSupply, string _name, string _symbol, uint _decimals) public {
                    _totalSupply = _initialSupply;
                    name = _name;
                    symbol = _symbol;
                    decimals = _decimals;
                    balances[owner] = _initialSupply;
                    deprecated = false;
                }
            
                // Forward ERC20 methods to upgraded contract if this one is deprecated
                function transfer(address _to, uint _value) public whenNotPaused {
                    require(!isBlackListed[msg.sender]);
                    if (deprecated) {
                        return UpgradedStandardToken(upgradedAddress).transferByLegacy(msg.sender, _to, _value);
                    } else {
                        return super.transfer(_to, _value);
                    }
                }
            
                // Forward ERC20 methods to upgraded contract if this one is deprecated
                function transferFrom(address _from, address _to, uint _value) public whenNotPaused {
                    require(!isBlackListed[_from]);
                    if (deprecated) {
                        return UpgradedStandardToken(upgradedAddress).transferFromByLegacy(msg.sender, _from, _to, _value);
                    } else {
                        return super.transferFrom(_from, _to, _value);
                    }
                }
            
                // Forward ERC20 methods to upgraded contract if this one is deprecated
                function balanceOf(address who) public constant returns (uint) {
                    if (deprecated) {
                        return UpgradedStandardToken(upgradedAddress).balanceOf(who);
                    } else {
                        return super.balanceOf(who);
                    }
                }
            
                // Forward ERC20 methods to upgraded contract if this one is deprecated
                function approve(address _spender, uint _value) public onlyPayloadSize(2 * 32) {
                    if (deprecated) {
                        return UpgradedStandardToken(upgradedAddress).approveByLegacy(msg.sender, _spender, _value);
                    } else {
                        return super.approve(_spender, _value);
                    }
                }
            
                // Forward ERC20 methods to upgraded contract if this one is deprecated
                function allowance(address _owner, address _spender) public constant returns (uint remaining) {
                    if (deprecated) {
                        return StandardToken(upgradedAddress).allowance(_owner, _spender);
                    } else {
                        return super.allowance(_owner, _spender);
                    }
                }
            
                // deprecate current contract in favour of a new one
                function deprecate(address _upgradedAddress) public onlyOwner {
                    deprecated = true;
                    upgradedAddress = _upgradedAddress;
                    Deprecate(_upgradedAddress);
                }
            
                // deprecate current contract if favour of a new one
                function totalSupply() public constant returns (uint) {
                    if (deprecated) {
                        return StandardToken(upgradedAddress).totalSupply();
                    } else {
                        return _totalSupply;
                    }
                }
            
                // Issue a new amount of tokens
                // these tokens are deposited into the owner address
                //
                // @param _amount Number of tokens to be issued
                function issue(uint amount) public onlyOwner {
                    require(_totalSupply + amount > _totalSupply);
                    require(balances[owner] + amount > balances[owner]);
            
                    balances[owner] += amount;
                    _totalSupply += amount;
                    Issue(amount);
                }
            
                // Redeem tokens.
                // These tokens are withdrawn from the owner address
                // if the balance must be enough to cover the redeem
                // or the call will fail.
                // @param _amount Number of tokens to be issued
                function redeem(uint amount) public onlyOwner {
                    require(_totalSupply >= amount);
                    require(balances[owner] >= amount);
            
                    _totalSupply -= amount;
                    balances[owner] -= amount;
                    Redeem(amount);
                }
            
                function setParams(uint newBasisPoints, uint newMaxFee) public onlyOwner {
                    // Ensure transparency by hardcoding limit beyond which fees can never be added
                    require(newBasisPoints < 20);
                    require(newMaxFee < 50);
            
                    basisPointsRate = newBasisPoints;
                    maximumFee = newMaxFee.mul(10**decimals);
            
                    Params(basisPointsRate, maximumFee);
                }
            
                // Called when new token are issued
                event Issue(uint amount);
            
                // Called when tokens are redeemed
                event Redeem(uint amount);
            
                // Called when contract is deprecated
                event Deprecate(address newAddress);
            
                // Called if contract ever adds fees
                event Params(uint feeBasisPoints, uint maxFee);
            }