ETH Price: $2,493.12 (-0.17%)

Transaction Decoder

Block:
14444322 at Mar-23-2022 07:01:35 PM +UTC
Transaction Fee:
0.017217447059577285 ETH $42.93
Gas Used:
338,697 Gas / 50.834365405 Gwei

Account State Difference:

  Address   Before After State Difference Code
(F2Pool Old)
5,457.50737010111715913 Eth5,457.50804749511715913 Eth0.000677394
0xa7d8d9ef...abd5bD270
0xD76040b0...64b5B771A
0.25167727519816368 Eth
Nonce: 1521
0.234459828138586395 Eth
Nonce: 1522
0.017217447059577285

Execution Trace

OwnableDelegateProxy.3f801f91( )
  • AuthenticatedProxy.proxyAssert( dest=0xC99f70bFD82fb7c8f8191fdfbFB735606b15e5c5, howToCall=1, calldata=0x68F0BCAA0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001C000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000004000000000000000000000000A7D8D9EF8D8CE8992DF33D8B8CF4AEBABD5BD270000000000000000000000000A7D8D9EF8D8CE8992DF33D8B8CF4AEBABD5BD270000000000000000000000000A7D8D9EF8D8CE8992DF33D8B8CF4AEBABD5BD270000000000000000000000000A7D8D9EF8D8CE8992DF33D8B8CF4AEBABD5BD2700000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000019023B872DD000000000000000000000000D76040B01FA18843F8983DBB1B40D3A64B5B771A00000000000000000000000053314ED80D217744EAA3CFA13FEA6692D08627AC0000000000000000000000000000000000000000000000000000000010CEFBC423B872DD000000000000000000000000D76040B01FA18843F8983DBB1B40D3A64B5B771A00000000000000000000000053314ED80D217744EAA3CFA13FEA6692D08627AC0000000000000000000000000000000000000000000000000000000010CEFC7123B872DD000000000000000000000000D76040B01FA18843F8983DBB1B40D3A64B5B771A00000000000000000000000053314ED80D217744EAA3CFA13FEA6692D08627AC0000000000000000000000000000000000000000000000000000000010CEFCE023B872DD000000000000000000000000D76040B01FA18843F8983DBB1B40D3A64B5B771A00000000000000000000000053314ED80D217744EAA3CFA13FEA6692D08627AC0000000000000000000000000000000000000000000000000000000010CEFE6E00000000000000000000000000000000 )
    • WyvernAtomicizer.atomicize( addrs=[0xa7d8d9ef8D8Ce8992Df33D8b8CF4Aebabd5bD270, 0xa7d8d9ef8D8Ce8992Df33D8b8CF4Aebabd5bD270, 0xa7d8d9ef8D8Ce8992Df33D8b8CF4Aebabd5bD270, 0xa7d8d9ef8D8Ce8992Df33D8b8CF4Aebabd5bD270], values=[0, 0, 0, 0], calldataLengths=[100, 100, 100, 100], calldatas=0x23B872DD000000000000000000000000D76040B01FA18843F8983DBB1B40D3A64B5B771A00000000000000000000000053314ED80D217744EAA3CFA13FEA6692D08627AC0000000000000000000000000000000000000000000000000000000010CEFBC423B872DD000000000000000000000000D76040B01FA18843F8983DBB1B40D3A64B5B771A00000000000000000000000053314ED80D217744EAA3CFA13FEA6692D08627AC0000000000000000000000000000000000000000000000000000000010CEFC7123B872DD000000000000000000000000D76040B01FA18843F8983DBB1B40D3A64B5B771A00000000000000000000000053314ED80D217744EAA3CFA13FEA6692D08627AC0000000000000000000000000000000000000000000000000000000010CEFCE023B872DD000000000000000000000000D76040B01FA18843F8983DBB1B40D3A64B5B771A00000000000000000000000053314ED80D217744EAA3CFA13FEA6692D08627AC0000000000000000000000000000000000000000000000000000000010CEFE6E )
      • GenArt721Core.transferFrom( from=0xD76040b01fa18843F8983Dbb1B40d3a64b5B771A, to=0x53314ED80D217744eaA3CfA13feA6692d08627AC, tokenId=282000324 )
      • GenArt721Core.transferFrom( from=0xD76040b01fa18843F8983Dbb1B40d3a64b5B771A, to=0x53314ED80D217744eaA3CfA13feA6692d08627AC, tokenId=282000497 )
      • GenArt721Core.transferFrom( from=0xD76040b01fa18843F8983Dbb1B40d3a64b5B771A, to=0x53314ED80D217744eaA3CfA13feA6692d08627AC, tokenId=282000608 )
      • GenArt721Core.transferFrom( from=0xD76040b01fa18843F8983Dbb1B40d3a64b5B771A, to=0x53314ED80D217744eaA3CfA13feA6692d08627AC, tokenId=282001006 )
        File 1 of 4: OwnableDelegateProxy
        contract OwnedUpgradeabilityStorage {
        
          // Current implementation
          address internal _implementation;
        
          // Owner of the contract
          address private _upgradeabilityOwner;
        
          /**
           * @dev Tells the address of the owner
           * @return the address of the owner
           */
          function upgradeabilityOwner() public view returns (address) {
            return _upgradeabilityOwner;
          }
        
          /**
           * @dev Sets the address of the owner
           */
          function setUpgradeabilityOwner(address newUpgradeabilityOwner) internal {
            _upgradeabilityOwner = newUpgradeabilityOwner;
          }
        
          /**
          * @dev Tells the address of the current implementation
          * @return address of the current implementation
          */
          function implementation() public view returns (address) {
            return _implementation;
          }
        
          /**
          * @dev Tells the proxy type (EIP 897)
          * @return Proxy type, 2 for forwarding proxy
          */
          function proxyType() public pure returns (uint256 proxyTypeId) {
            return 2;
          }
        }
        
        
        
        contract Proxy {
        
          /**
          * @dev Tells the address of the implementation where every call will be delegated.
          * @return address of the implementation to which it will be delegated
          */
          function implementation() public view returns (address);
        
          /**
          * @dev Tells the type of proxy (EIP 897)
          * @return Type of proxy, 2 for upgradeable proxy
          */
          function proxyType() public pure returns (uint256 proxyTypeId);
        
          /**
          * @dev Fallback function allowing to perform a delegatecall to the given implementation.
          * This function will return whatever the implementation call returns
          */
          function () payable public {
            address _impl = implementation();
            require(_impl != address(0));
        
            assembly {
              let ptr := mload(0x40)
              calldatacopy(ptr, 0, calldatasize)
              let result := delegatecall(gas, _impl, ptr, calldatasize, 0, 0)
              let size := returndatasize
              returndatacopy(ptr, 0, size)
        
              switch result
              case 0 { revert(ptr, size) }
              default { return(ptr, size) }
            }
          }
        }
        
        contract OwnedUpgradeabilityProxy is Proxy, OwnedUpgradeabilityStorage {
          /**
          * @dev Event to show ownership has been transferred
          * @param previousOwner representing the address of the previous owner
          * @param newOwner representing the address of the new owner
          */
          event ProxyOwnershipTransferred(address previousOwner, address newOwner);
        
          /**
          * @dev This event will be emitted every time the implementation gets upgraded
          * @param implementation representing the address of the upgraded implementation
          */
          event Upgraded(address indexed implementation);
        
          /**
          * @dev Upgrades the implementation address
          * @param implementation representing the address of the new implementation to be set
          */
          function _upgradeTo(address implementation) internal {
            require(_implementation != implementation);
            _implementation = implementation;
            emit Upgraded(implementation);
          }
        
          /**
          * @dev Throws if called by any account other than the owner.
          */
          modifier onlyProxyOwner() {
            require(msg.sender == proxyOwner());
            _;
          }
        
          /**
           * @dev Tells the address of the proxy owner
           * @return the address of the proxy owner
           */
          function proxyOwner() public view returns (address) {
            return upgradeabilityOwner();
          }
        
          /**
           * @dev Allows the current owner to transfer control of the contract to a newOwner.
           * @param newOwner The address to transfer ownership to.
           */
          function transferProxyOwnership(address newOwner) public onlyProxyOwner {
            require(newOwner != address(0));
            emit ProxyOwnershipTransferred(proxyOwner(), newOwner);
            setUpgradeabilityOwner(newOwner);
          }
        
          /**
           * @dev Allows the upgradeability owner to upgrade the current implementation of the proxy.
           * @param implementation representing the address of the new implementation to be set.
           */
          function upgradeTo(address implementation) public onlyProxyOwner {
            _upgradeTo(implementation);
          }
        
          /**
           * @dev Allows the upgradeability owner to upgrade the current implementation of the proxy
           * and delegatecall the new implementation for initialization.
           * @param implementation representing the address of the new implementation to be set.
           * @param data represents the msg.data to bet sent in the low level call. This parameter may include the function
           * signature of the implementation to be called with the needed payload
           */
          function upgradeToAndCall(address implementation, bytes data) payable public onlyProxyOwner {
            upgradeTo(implementation);
            require(address(this).delegatecall(data));
          }
        }
        
        
        contract OwnableDelegateProxy is OwnedUpgradeabilityProxy {
        
            constructor(address owner, address initialImplementation, bytes calldata)
                public
            {
                setUpgradeabilityOwner(owner);
                _upgradeTo(initialImplementation);
                require(initialImplementation.delegatecall(calldata));
            }
        
        }

        File 2 of 4: 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 3 of 4: AuthenticatedProxy
        pragma solidity ^0.4.13;
        
        contract Ownable {
          address public owner;
        
        
          event OwnershipRenounced(address indexed previousOwner);
          event OwnershipTransferred(
            address indexed previousOwner,
            address indexed newOwner
          );
        
        
          /**
           * @dev The Ownable constructor sets the original `owner` of the contract to the sender
           * account.
           */
          constructor() 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 {
            require(newOwner != address(0));
            emit OwnershipTransferred(owner, newOwner);
            owner = newOwner;
          }
        
          /**
           * @dev Allows the current owner to relinquish control of the contract.
           */
          function renounceOwnership() public onlyOwner {
            emit OwnershipRenounced(owner);
            owner = address(0);
          }
        }
        
        contract ERC20Basic {
          function totalSupply() public view returns (uint256);
          function balanceOf(address who) public view returns (uint256);
          function transfer(address to, uint256 value) public returns (bool);
          event Transfer(address indexed from, address indexed to, uint256 value);
        }
        
        contract ERC20 is ERC20Basic {
          function allowance(address owner, address spender)
            public view returns (uint256);
        
          function transferFrom(address from, address to, uint256 value)
            public returns (bool);
        
          function approve(address spender, uint256 value) public returns (bool);
          event Approval(
            address indexed owner,
            address indexed spender,
            uint256 value
          );
        }
        
        contract ProxyRegistry is Ownable {
        
            /* DelegateProxy implementation contract. Must be initialized. */
            address public delegateProxyImplementation;
        
            /* Authenticated proxies by user. */
            mapping(address => OwnableDelegateProxy) public proxies;
        
            /* Contracts pending access. */
            mapping(address => uint) public pending;
        
            /* Contracts allowed to call those proxies. */
            mapping(address => bool) public contracts;
        
            /* Delay period for adding an authenticated contract.
               This mitigates a particular class of potential attack on the Wyvern DAO (which owns this registry) - if at any point the value of assets held by proxy contracts exceeded the value of half the WYV supply (votes in the DAO),
               a malicious but rational attacker could buy half the Wyvern and grant themselves access to all the proxy contracts. A delay period renders this attack nonthreatening - given two weeks, if that happened, users would have
               plenty of time to notice and transfer their assets.
            */
            uint public DELAY_PERIOD = 2 weeks;
        
            /**
             * Start the process to enable access for specified contract. Subject to delay period.
             *
             * @dev ProxyRegistry owner only
             * @param addr Address to which to grant permissions
             */
            function startGrantAuthentication (address addr)
                public
                onlyOwner
            {
                require(!contracts[addr] && pending[addr] == 0);
                pending[addr] = now;
            }
        
            /**
             * End the process to nable access for specified contract after delay period has passed.
             *
             * @dev ProxyRegistry owner only
             * @param addr Address to which to grant permissions
             */
            function endGrantAuthentication (address addr)
                public
                onlyOwner
            {
                require(!contracts[addr] && pending[addr] != 0 && ((pending[addr] + DELAY_PERIOD) < now));
                pending[addr] = 0;
                contracts[addr] = true;
            }
        
            /**
             * Revoke access for specified contract. Can be done instantly.
             *
             * @dev ProxyRegistry owner only
             * @param addr Address of which to revoke permissions
             */    
            function revokeAuthentication (address addr)
                public
                onlyOwner
            {
                contracts[addr] = false;
            }
        
            /**
             * Register a proxy contract with this registry
             *
             * @dev Must be called by the user which the proxy is for, creates a new AuthenticatedProxy
             * @return New AuthenticatedProxy contract
             */
            function registerProxy()
                public
                returns (OwnableDelegateProxy proxy)
            {
                require(proxies[msg.sender] == address(0));
                proxy = new OwnableDelegateProxy(msg.sender, delegateProxyImplementation, abi.encodeWithSignature("initialize(address,address)", msg.sender, address(this)));
                proxies[msg.sender] = proxy;
                return proxy;
            }
        
        }
        
        contract TokenRecipient {
            event ReceivedEther(address indexed sender, uint amount);
            event ReceivedTokens(address indexed from, uint256 value, address indexed token, bytes extraData);
        
            /**
             * @dev Receive tokens and generate a log event
             * @param from Address from which to transfer tokens
             * @param value Amount of tokens to transfer
             * @param token Address of token
             * @param extraData Additional data to log
             */
            function receiveApproval(address from, uint256 value, address token, bytes extraData) public {
                ERC20 t = ERC20(token);
                require(t.transferFrom(from, this, value));
                emit ReceivedTokens(from, value, token, extraData);
            }
        
            /**
             * @dev Receive Ether and generate a log event
             */
            function () payable public {
                emit ReceivedEther(msg.sender, msg.value);
            }
        }
        
        contract OwnedUpgradeabilityStorage {
        
          // Current implementation
          address internal _implementation;
        
          // Owner of the contract
          address private _upgradeabilityOwner;
        
          /**
           * @dev Tells the address of the owner
           * @return the address of the owner
           */
          function upgradeabilityOwner() public view returns (address) {
            return _upgradeabilityOwner;
          }
        
          /**
           * @dev Sets the address of the owner
           */
          function setUpgradeabilityOwner(address newUpgradeabilityOwner) internal {
            _upgradeabilityOwner = newUpgradeabilityOwner;
          }
        
          /**
          * @dev Tells the address of the current implementation
          * @return address of the current implementation
          */
          function implementation() public view returns (address) {
            return _implementation;
          }
        
          /**
          * @dev Tells the proxy type (EIP 897)
          * @return Proxy type, 2 for forwarding proxy
          */
          function proxyType() public pure returns (uint256 proxyTypeId) {
            return 2;
          }
        }
        
        contract AuthenticatedProxy is TokenRecipient, OwnedUpgradeabilityStorage {
        
            /* Whether initialized. */
            bool initialized = false;
        
            /* Address which owns this proxy. */
            address public user;
        
            /* Associated registry with contract authentication information. */
            ProxyRegistry public registry;
        
            /* Whether access has been revoked. */
            bool public revoked;
        
            /* Delegate call could be used to atomically transfer multiple assets owned by the proxy contract with one order. */
            enum HowToCall { Call, DelegateCall }
        
            /* Event fired when the proxy access is revoked or unrevoked. */
            event Revoked(bool revoked);
        
            /**
             * Initialize an AuthenticatedProxy
             *
             * @param addrUser Address of user on whose behalf this proxy will act
             * @param addrRegistry Address of ProxyRegistry contract which will manage this proxy
             */
            function initialize (address addrUser, ProxyRegistry addrRegistry)
                public
            {
                require(!initialized);
                initialized = true;
                user = addrUser;
                registry = addrRegistry;
            }
        
            /**
             * Set the revoked flag (allows a user to revoke ProxyRegistry access)
             *
             * @dev Can be called by the user only
             * @param revoke Whether or not to revoke access
             */
            function setRevoke(bool revoke)
                public
            {
                require(msg.sender == user);
                revoked = revoke;
                emit Revoked(revoke);
            }
        
            /**
             * Execute a message call from the proxy contract
             *
             * @dev Can be called by the user, or by a contract authorized by the registry as long as the user has not revoked access
             * @param dest Address to which the call will be sent
             * @param howToCall Which kind of call to make
             * @param calldata Calldata to send
             * @return Result of the call (success or failure)
             */
            function proxy(address dest, HowToCall howToCall, bytes calldata)
                public
                returns (bool result)
            {
                require(msg.sender == user || (!revoked && registry.contracts(msg.sender)));
                if (howToCall == HowToCall.Call) {
                    result = dest.call(calldata);
                } else if (howToCall == HowToCall.DelegateCall) {
                    result = dest.delegatecall(calldata);
                }
                return result;
            }
        
            /**
             * Execute a message call and assert success
             * 
             * @dev Same functionality as `proxy`, just asserts the return value
             * @param dest Address to which the call will be sent
             * @param howToCall What kind of call to make
             * @param calldata Calldata to send
             */
            function proxyAssert(address dest, HowToCall howToCall, bytes calldata)
                public
            {
                require(proxy(dest, howToCall, calldata));
            }
        
        }
        
        contract Proxy {
        
          /**
          * @dev Tells the address of the implementation where every call will be delegated.
          * @return address of the implementation to which it will be delegated
          */
          function implementation() public view returns (address);
        
          /**
          * @dev Tells the type of proxy (EIP 897)
          * @return Type of proxy, 2 for upgradeable proxy
          */
          function proxyType() public pure returns (uint256 proxyTypeId);
        
          /**
          * @dev Fallback function allowing to perform a delegatecall to the given implementation.
          * This function will return whatever the implementation call returns
          */
          function () payable public {
            address _impl = implementation();
            require(_impl != address(0));
        
            assembly {
              let ptr := mload(0x40)
              calldatacopy(ptr, 0, calldatasize)
              let result := delegatecall(gas, _impl, ptr, calldatasize, 0, 0)
              let size := returndatasize
              returndatacopy(ptr, 0, size)
        
              switch result
              case 0 { revert(ptr, size) }
              default { return(ptr, size) }
            }
          }
        }
        
        contract OwnedUpgradeabilityProxy is Proxy, OwnedUpgradeabilityStorage {
          /**
          * @dev Event to show ownership has been transferred
          * @param previousOwner representing the address of the previous owner
          * @param newOwner representing the address of the new owner
          */
          event ProxyOwnershipTransferred(address previousOwner, address newOwner);
        
          /**
          * @dev This event will be emitted every time the implementation gets upgraded
          * @param implementation representing the address of the upgraded implementation
          */
          event Upgraded(address indexed implementation);
        
          /**
          * @dev Upgrades the implementation address
          * @param implementation representing the address of the new implementation to be set
          */
          function _upgradeTo(address implementation) internal {
            require(_implementation != implementation);
            _implementation = implementation;
            emit Upgraded(implementation);
          }
        
          /**
          * @dev Throws if called by any account other than the owner.
          */
          modifier onlyProxyOwner() {
            require(msg.sender == proxyOwner());
            _;
          }
        
          /**
           * @dev Tells the address of the proxy owner
           * @return the address of the proxy owner
           */
          function proxyOwner() public view returns (address) {
            return upgradeabilityOwner();
          }
        
          /**
           * @dev Allows the current owner to transfer control of the contract to a newOwner.
           * @param newOwner The address to transfer ownership to.
           */
          function transferProxyOwnership(address newOwner) public onlyProxyOwner {
            require(newOwner != address(0));
            emit ProxyOwnershipTransferred(proxyOwner(), newOwner);
            setUpgradeabilityOwner(newOwner);
          }
        
          /**
           * @dev Allows the upgradeability owner to upgrade the current implementation of the proxy.
           * @param implementation representing the address of the new implementation to be set.
           */
          function upgradeTo(address implementation) public onlyProxyOwner {
            _upgradeTo(implementation);
          }
        
          /**
           * @dev Allows the upgradeability owner to upgrade the current implementation of the proxy
           * and delegatecall the new implementation for initialization.
           * @param implementation representing the address of the new implementation to be set.
           * @param data represents the msg.data to bet sent in the low level call. This parameter may include the function
           * signature of the implementation to be called with the needed payload
           */
          function upgradeToAndCall(address implementation, bytes data) payable public onlyProxyOwner {
            upgradeTo(implementation);
            require(address(this).delegatecall(data));
          }
        }
        
        contract OwnableDelegateProxy is OwnedUpgradeabilityProxy {
        
            constructor(address owner, address initialImplementation, bytes calldata)
                public
            {
                setUpgradeabilityOwner(owner);
                _upgradeTo(initialImplementation);
                require(initialImplementation.delegatecall(calldata));
            }
        
        }

        File 4 of 4: WyvernAtomicizer
        pragma solidity ^0.4.13;
        
        library WyvernAtomicizer {
        
            function atomicize (address[] addrs, uint[] values, uint[] calldataLengths, bytes calldatas)
                public
            {
                require(addrs.length == values.length && addrs.length == calldataLengths.length);
        
                uint j = 0;
                for (uint i = 0; i < addrs.length; i++) {
                    bytes memory calldata = new bytes(calldataLengths[i]);
                    for (uint k = 0; k < calldataLengths[i]; k++) {
                        calldata[k] = calldatas[j];
                        j++;
                    }
                    require(addrs[i].call.value(values[i])(calldata));
                }
            }
        
        }