ETH Price: $2,155.22 (+0.64%)

Transaction Decoder

Block:
12072853 at Mar-20-2021 02:01:13 AM +UTC
Transaction Fee:
0.018188892 ETH $39.20
Gas Used:
135,738 Gas / 134 Gwei

Emitted Events:

261 BAE.TransferSingle( _operator=[Receiver] 0x64256f44ee027bc405a56291a13ee91c90fd11c5, _from=0x1a56f2e94c4178c847c8689748551c3e1a149e7f, _to=[Sender] 0x44e9d011df8741be2493e99297e9ad67bb1aa85b, _id=927, _amount=1 )
262 0x64256f44ee027bc405a56291a13ee91c90fd11c5.0xa99a0659382bd454329e4478ad17e8d2248d18852f2ae8f8899759d5378c759e( 0xa99a0659382bd454329e4478ad17e8d2248d18852f2ae8f8899759d5378c759e, 000000000000000000000000000000000000000000000000000000000000039f, 0000000000000000000000000000000000000000000000000000000000000001, 0000000000000000000000000000000000000000000000000000000000000000, 000000000000000000000000000000000000000000000000011c37937e080000, 00000000000000000000000044e9d011df8741be2493e99297e9ad67bb1aa85b, 0000000000000000000000001a56f2e94c4178c847c8689748551c3e1a149e7f, 9a15940225420eda1cf2ac294464665458278c6d5539242e733094164e55707e )

Account State Difference:

  Address   Before After State Difference Code
0x1A56F2E9...E1a149E7F 0.378160707287067932 Eth0.454160707287067932 Eth0.076
0x3edf71a3...98dF047AA
0x44e86f37...e8224220b 0.030245676640159665 Eth0.031045676640159665 Eth0.0008
0x44E9d011...7bb1aa85B
(WizardX)
8.775877435938738795 Eth
Nonce: 4472
8.677688543938738795 Eth
Nonce: 4473
0.098188892
0x48608214...8291FF292 0.033952 Eth0.037152 Eth0.0032
0x64256F44...c90fD11c5
(Huobi Mining Pool 2)
1.967729839257792774 Eth1.985918731257792774 Eth0.018188892

Execution Trace

ETH 0.08 0x64256f44ee027bc405a56291a13ee91c90fd11c5.cf4b4d64( )
  • Null: 0x000...001.dfe2ebde( )
  • BAE.safeTransferFrom( _from=0x1A56F2E94C4178C847c8689748551C3E1a149E7F, _to=0x44E9d011DF8741Be2493E99297E9ad67bb1aa85B, _id=927, _amount=1, _data=0x )
    • WyvernProxyRegistry.proxies( 0x1A56F2E94C4178C847c8689748551C3E1a149E7F ) => ( 0x79Ea1C8a61453d97628a40fa86B3d21B9b0D4eAa )
    • ETH 0.0008 0x44e86f37792d4c454cc836b91c84d7fe8224220b.CALL( )
    • ETH 0.0032 0x486082148bc8dc9dee8c9e53649ea148291ff292.CALL( )
    • BAE.creators( 927 ) => ( 0x1A56F2E94C4178C847c8689748551C3E1a149E7F )
    • ETH 0.004 0x1a56f2e94c4178c847c8689748551c3e1a149e7f.CALL( )
    • ETH 0.072 0x1a56f2e94c4178c847c8689748551c3e1a149e7f.CALL( )
    • WizardX.CALL( )
      File 1 of 2: BAE
      // File: openzeppelin-solidity\contracts\ownership\Ownable.sol
      
      pragma solidity ^0.5.0;
      
      /**
       * @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 private _owner;
      
          event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);   
      
          /**
           * @dev The Ownable constructor sets the original `owner` of the contract to the sender
           * account.
           */
          constructor () internal {
              _owner = msg.sender;
              emit OwnershipTransferred(address(0), _owner);
          }
      
          /**
           * @return the address of the owner.
           */
          function owner() public view returns (address) {
              return _owner;
          }
      
          /**
           * @dev Throws if called by any account other than the owner.
           */
          modifier onlyOwner() {
              require(isOwner());
              _;
          }
      
          /**
           * @return true if `msg.sender` is the owner of the contract.
           */
          function isOwner() public view returns (bool) {
              return msg.sender == _owner;
          }
      
          /**
           * @dev Allows the current owner to relinquish control of the contract.
           * @notice Renouncing to ownership will leave the contract without an owner.
           * It will not be possible to call the functions with the `onlyOwner`
           * modifier anymore.
           */
          function renounceOwnership() public onlyOwner {
              emit OwnershipTransferred(_owner, address(0));
              _owner = address(0);
          }
      
          /**
           * @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 {
              _transferOwnership(newOwner);
          }
      
          /**
           * @dev Transfers control of the contract to a newOwner.
           * @param newOwner The address to transfer ownership to.
           */
          function _transferOwnership(address newOwner) internal {
              require(newOwner != address(0));
              emit OwnershipTransferred(_owner, newOwner);
              _owner = newOwner;
          }
      }
      
      // File: contracts\multi-token-standard\interfaces\IERC165.sol
      
      pragma solidity ^0.5.12;
      
      
      /**
       * @title ERC165
       * @dev https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md
       */
      interface IERC165 {
      
          /**
           * @notice Query if a contract implements an interface
           * @dev Interface identification is specified in ERC-165. This function
           * uses less than 30,000 gas
           * @param _interfaceId The interface identifier, as specified in ERC-165
           */
          function supportsInterface(bytes4 _interfaceId)
          external
          view
          returns (bool);
      }
      
      // File: contracts\multi-token-standard\utils\SafeMath.sol
      
      pragma solidity ^0.5.12;
      
      
      /**
       * @title SafeMath
       * @dev Unsigned math operations with safety checks that revert on error
       */
      library SafeMath {
      
        /**
         * @dev Multiplies two unsigned integers, reverts on 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#mul: OVERFLOW");
      
          return c;
        }
      
        /**
         * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
         */
        function div(uint256 a, uint256 b) internal pure returns (uint256) {
          // Solidity only automatically asserts when dividing by 0
          require(b > 0, "SafeMath#div: 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;
        }
      
        /**
         * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
         */
        function sub(uint256 a, uint256 b) internal pure returns (uint256) {
          require(b <= a, "SafeMath#sub: UNDERFLOW");
          uint256 c = a - b;
      
          return c;
        }
      
        /**
         * @dev Adds two unsigned integers, reverts on overflow.
         */
        function add(uint256 a, uint256 b) internal pure returns (uint256) {
          uint256 c = a + b;
          require(c >= a, "SafeMath#add: OVERFLOW");
      
          return c;
        }
      
        /**
         * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
         * reverts when dividing by zero.
         */
        function mod(uint256 a, uint256 b) internal pure returns (uint256) {
          require(b != 0, "SafeMath#mod: DIVISION_BY_ZERO");
          return a % b;
        }
      
      }
      
      // File: contracts\multi-token-standard\interfaces\IERC1155TokenReceiver.sol
      
      pragma solidity ^0.5.12;
      
      /**
       * @dev ERC-1155 interface for accepting safe transfers.
       */
      interface IERC1155TokenReceiver {
      
        /**
         * @notice Handle the receipt of a single ERC1155 token type
         * @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeTransferFrom` after the balance has been updated
         * This function MAY throw to revert and reject the transfer
         * Return of other amount than the magic value MUST result in the transaction being reverted
         * Note: The token contract address is always the message sender
         * @param _operator  The address which called the `safeTransferFrom` function
         * @param _from      The address which previously owned the token
         * @param _id        The id of the token being transferred
         * @param _amount    The amount of tokens being transferred
         * @param _data      Additional data with no specified format
         * @return           `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
         */
        function onERC1155Received(address _operator, address _from, uint256 _id, uint256 _amount, bytes calldata _data) external returns(bytes4);
      
        /**
         * @notice Handle the receipt of multiple ERC1155 token types
         * @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeBatchTransferFrom` after the balances have been updated
         * This function MAY throw to revert and reject the transfer
         * Return of other amount than the magic value WILL result in the transaction being reverted
         * Note: The token contract address is always the message sender
         * @param _operator  The address which called the `safeBatchTransferFrom` function
         * @param _from      The address which previously owned the token
         * @param _ids       An array containing ids of each token being transferred
         * @param _amounts   An array containing amounts of each token being transferred
         * @param _data      Additional data with no specified format
         * @return           `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
         */
        function onERC1155BatchReceived(address _operator, address _from, uint256[] calldata _ids, uint256[] calldata _amounts, bytes calldata _data) external returns(bytes4);
      
        /**
         * @notice Indicates whether a contract implements the `ERC1155TokenReceiver` functions and so can accept ERC1155 token types.
         * @param  interfaceID The ERC-165 interface ID that is queried for support.s
         * @dev This function MUST return true if it implements the ERC1155TokenReceiver interface and ERC-165 interface.
         *      This function MUST NOT consume more than 5,000 gas.
         * @return Wheter ERC-165 or ERC1155TokenReceiver interfaces are supported.
         */
        function supportsInterface(bytes4 interfaceID) external view returns (bool);
      
      }
      
      // File: contracts\multi-token-standard\interfaces\IERC1155.sol
      
      pragma solidity ^0.5.12;
      
      
      interface IERC1155 {
        // Events
      
        /**
         * @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred, including zero amount transfers as well as minting or burning
         *   Operator MUST be msg.sender
         *   When minting/creating tokens, the `_from` field MUST be set to `0x0`
         *   When burning/destroying tokens, the `_to` field MUST be set to `0x0`
         *   The total amount transferred from address 0x0 minus the total amount transferred to 0x0 may be used by clients and exchanges to be added to the "circulating supply" for a given token ID
         *   To broadcast the existence of a token ID with no initial balance, the contract SHOULD emit the TransferSingle event from `0x0` to `0x0`, with the token 
      creator as `_operator`, and a `_amount` of 0
         */
        event TransferSingle(address indexed _operator, address indexed _from, address indexed _to, uint256 _id, uint256 _amount);
      
        /**
         * @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred, including zero amount transfers as well as minting or burning
         *   Operator MUST be msg.sender
         *   When minting/creating tokens, the `_from` field MUST be set to `0x0`
         *   When burning/destroying tokens, the `_to` field MUST be set to `0x0`
         *   The total amount transferred from address 0x0 minus the total amount transferred to 0x0 may be used by clients and exchanges to be added to the "circulating supply" for a given token ID
         *   To broadcast the existence of multiple token IDs with no initial balance, this SHOULD emit the TransferBatch event from `0x0` to `0x0`, with the token creator as `_operator`, and a `_amount` of 0
         */
        event TransferBatch(address indexed _operator, address indexed _from, address indexed _to, uint256[] _ids, uint256[] _amounts);
      
        /**
         * @dev MUST emit when an approval is updated
         */
        event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
      
        /**
         * @dev MUST emit when the URI is updated for a token ID
         *   URIs are defined in RFC 3986
         *   The URI MUST point a JSON file that conforms to the "ERC-1155 Metadata JSON Schema"
         */
        event URI(string _amount, uint256 indexed _id);
      
        /**
         * @notice Transfers amount of an _id from the _from address to the _to address specified
         * @dev MUST emit TransferSingle event on success
         * Caller must be approved to manage the _from account's tokens (see isApprovedForAll)
         * MUST throw if `_to` is the zero address
         * MUST throw if balance of sender for token `_id` is lower than the `_amount` sent
         * MUST throw on any other error
         * When transfer is complete, this function MUST check if `_to` is a smart contract (code size > 0). If so, it MUST call `onERC1155Received` on `_to` and revert if the return amount is not `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
         * @param _from    Source address
         * @param _to      Target address
         * @param _id      ID of the token type
         * @param _amount  Transfered amount
         * @param _data    Additional data with no specified format, sent in call to `_to`
         */
        function safeTransferFrom(address _from, address _to, uint256 _id, uint256 _amount, bytes calldata _data) external;
      
        /**
         * @notice Send multiple types of Tokens from the _from address to the _to address (with safety call)
         * @dev MUST emit TransferBatch event on success
         * Caller must be approved to manage the _from account's tokens (see isApprovedForAll)
         * MUST throw if `_to` is the zero address
         * MUST throw if length of `_ids` is not the same as length of `_amounts`
         * MUST throw if any of the balance of sender for token `_ids` is lower than the respective `_amounts` sent
         * MUST throw on any other error
         * When transfer is complete, this function MUST check if `_to` is a smart contract (code size > 0). If so, it MUST call `onERC1155BatchReceived` on `_to` and revert if the return amount is not `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
         * Transfers and events MUST occur in the array order they were submitted (_ids[0] before _ids[1], etc)
         * @param _from     Source addresses
         * @param _to       Target addresses
         * @param _ids      IDs of each token type
         * @param _amounts  Transfer amounts per token type
         * @param _data     Additional data with no specified format, sent in call to `_to`
        */
        function safeBatchTransferFrom(address _from, address _to, uint256[] calldata _ids, uint256[] calldata _amounts, bytes calldata _data) external;
      
        /**
         * @notice Get the balance of an account's Tokens
         * @param _owner  The address of the token holder
         * @param _id     ID of the Token
         * @return        The _owner's balance of the Token type requested
         */
        function balanceOf(address _owner, uint256 _id) external view returns (uint256);
      
        /**
         * @notice Get the balance of multiple account/token pairs
         * @param _owners The addresses of the token holders
         * @param _ids    ID of the Tokens
         * @return        The _owner's balance of the Token types requested (i.e. balance for each (owner, id) pair)
         */
        function balanceOfBatch(address[] calldata _owners, uint256[] calldata _ids) external view returns (uint256[] memory);
      
        /**
         * @notice Enable or disable approval for a third party ("operator") to manage all of caller's tokens
         * @dev MUST emit the ApprovalForAll event on success
         * @param _operator  Address to add to the set of authorized operators
         * @param _approved  True if the operator is approved, false to revoke approval
         */
        function setApprovalForAll(address _operator, bool _approved) external;
      
        /**
         * @notice Queries the approval status of an operator for a given owner
         * @param _owner     The owner of the Tokens
         * @param _operator  Address of authorized operator
         * @return           True if the operator is approved, false if not
         */
        function isApprovedForAll(address _owner, address _operator) external view returns (bool isOperator);
      
      }
      
      // File: contracts\multi-token-standard\utils\Address.sol
      
      /**
       * Copyright 2018 ZeroEx Intl.
       * Licensed under the Apache License, Version 2.0 (the "License");
       * you may not use this file except in compliance with the License.
       * You may obtain a copy of the License at
       *   http://www.apache.org/licenses/LICENSE-2.0
       * Unless required by applicable law or agreed to in writing, software
       * distributed under the License is distributed on an "AS IS" BASIS,
       * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       * See the License for the specific language governing permissions and
       * limitations under the License.
       */
      
      pragma solidity ^0.5.12;
      
      
      /**
       * Utility library of inline functions on addresses
       */
      library Address {
      
        /**
         * Returns whether the target address is a contract
         * @dev This function will return false if invoked during the constructor of a contract,
         * as the code is not actually created until after the constructor finishes.
         * @param account address of the account to check
         * @return whether the target address is a contract
         */
        function isContract(address account) internal view returns (bool) {
          bytes32 codehash;
          bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
      
          // XXX Currently there is no better way to check if there is a contract in an address
          // than to check the size of the code at that address.
          // See https://ethereum.stackexchange.com/a/14016/36603
          // for more details about how this works.
          // TODO Check this again before the Serenity release, because all addresses will be
          // contracts then.
          assembly { codehash := extcodehash(account) }
          return (codehash != 0x0 && codehash != accountHash);
        }
      
      }
      
      // File: contracts\multi-token-standard\tokens\ERC1155\ERC1155.sol
      
      pragma solidity ^0.5.12;
      
      
      
      
      
      
      
      /**
       * @dev Implementation of Multi-Token Standard contract
       */
      contract ERC1155 is IERC165 {
        using SafeMath for uint256;
        using Address for address;
      
      
        /***********************************|
        |        Variables and Events       |
        |__________________________________*/
      
        // onReceive function signatures
        bytes4 constant internal ERC1155_RECEIVED_VALUE = 0xf23a6e61;
        bytes4 constant internal ERC1155_BATCH_RECEIVED_VALUE = 0xbc197c81;
      
        // Objects balances
        mapping (address => mapping(uint256 => uint256)) internal balances;
      
        // Operator Functions
        mapping (address => mapping(address => bool)) internal operators;
      
        // Events
        event TransferSingle(address indexed _operator, address indexed _from, address indexed _to, uint256 _id, uint256 _amount);
        event TransferBatch(address indexed _operator, address indexed _from, address indexed _to, uint256[] _ids, uint256[] _amounts);
        event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
        event URI(string _uri, uint256 indexed _id);
      
      
        /***********************************|
        |     Public Transfer Functions     |
        |__________________________________*/
      
        /**
         * @notice Transfers amount amount of an _id from the _from address to the _to address specified
         * @param _from    Source address
         * @param _to      Target address
         * @param _id      ID of the token type
         * @param _amount  Transfered amount
         * @param _data    Additional data with no specified format, sent in call to `_to`
         */
        function safeTransferFrom(address _from, address _to, uint256 _id, uint256 _amount, bytes memory _data)
          public
        {
          require((msg.sender == _from) || isApprovedForAll(_from, msg.sender), "ERC1155#safeTransferFrom: INVALID_OPERATOR");
          require(_to != address(0),"ERC1155#safeTransferFrom: INVALID_RECIPIENT");
          // require(_amount >= balances[_from][_id]) is not necessary since checked with safemath operations
      
          _safeTransferFrom(_from, _to, _id, _amount);
          _callonERC1155Received(_from, _to, _id, _amount, _data);
        }
      
        /**
         * @notice Send multiple types of Tokens from the _from address to the _to address (with safety call)
         * @param _from     Source addresses
         * @param _to       Target addresses
         * @param _ids      IDs of each token type
         * @param _amounts  Transfer amounts per token type
         * @param _data     Additional data with no specified format, sent in call to `_to`
         */
        function safeBatchTransferFrom(address _from, address _to, uint256[] memory _ids, uint256[] memory _amounts, bytes memory _data)
          public
        {
          // Requirements
          require((msg.sender == _from) || isApprovedForAll(_from, msg.sender), "ERC1155#safeBatchTransferFrom: INVALID_OPERATOR");
          require(_to != address(0), "ERC1155#safeBatchTransferFrom: INVALID_RECIPIENT");
      
          _safeBatchTransferFrom(_from, _to, _ids, _amounts);
          _callonERC1155BatchReceived(_from, _to, _ids, _amounts, _data);
        }
      
      
        /***********************************|
        |    Internal Transfer Functions    |
        |__________________________________*/
      
        /**
         * @notice Transfers amount amount of an _id from the _from address to the _to address specified
         * @param _from    Source address
         * @param _to      Target address
         * @param _id      ID of the token type
         * @param _amount  Transfered amount
         */
        function _safeTransferFrom(address _from, address _to, uint256 _id, uint256 _amount)
          internal
        {
          // Update balances
          balances[_from][_id] = balances[_from][_id].sub(_amount); // Subtract amount
          balances[_to][_id] = balances[_to][_id].add(_amount);     // Add amount
      
          // Emit event
          emit TransferSingle(msg.sender, _from, _to, _id, _amount);
        }
      
        /**
         * @notice Verifies if receiver is contract and if so, calls (_to).onERC1155Received(...)
         */
        function _callonERC1155Received(address _from, address _to, uint256 _id, uint256 _amount, bytes memory _data)
          internal
        {
          // Check if recipient is contract
          if (_to.isContract() && _to != address(this)) {
            bytes4 retval = IERC1155TokenReceiver(_to).onERC1155Received(msg.sender, _from, _id, _amount, _data);
            require(retval == ERC1155_RECEIVED_VALUE, "ERC1155#_callonERC1155Received: INVALID_ON_RECEIVE_MESSAGE");
          }
        }
      
        /**
         * @notice Send multiple types of Tokens from the _from address to the _to address (with safety call)
         * @param _from     Source addresses
         * @param _to       Target addresses
         * @param _ids      IDs of each token type
         * @param _amounts  Transfer amounts per token type
         */
        function _safeBatchTransferFrom(address _from, address _to, uint256[] memory _ids, uint256[] memory _amounts)
          internal
        {
          require(_ids.length == _amounts.length, "ERC1155#_safeBatchTransferFrom: INVALID_ARRAYS_LENGTH");
      
          // Number of transfer to execute
          uint256 nTransfer = _ids.length;
      
          // Executing all transfers
          for (uint256 i = 0; i < nTransfer; i++) {
            // Update storage balance of previous bin
            balances[_from][_ids[i]] = balances[_from][_ids[i]].sub(_amounts[i]);
            balances[_to][_ids[i]] = balances[_to][_ids[i]].add(_amounts[i]);
          }
      
          // Emit event
          emit TransferBatch(msg.sender, _from, _to, _ids, _amounts);
        }
      
        /**
         * @notice Verifies if receiver is contract and if so, calls (_to).onERC1155BatchReceived(...)
         */
        function _callonERC1155BatchReceived(address _from, address _to, uint256[] memory _ids, uint256[] memory _amounts, bytes memory _data)
          internal
        {
          // Pass data if recipient is contract
          if (_to.isContract() && _to != address(this)) {
            bytes4 retval = IERC1155TokenReceiver(_to).onERC1155BatchReceived(msg.sender, _from, _ids, _amounts, _data);
            require(retval == ERC1155_BATCH_RECEIVED_VALUE, "ERC1155#_callonERC1155BatchReceived: INVALID_ON_RECEIVE_MESSAGE");
          }
        }
      
      
        /***********************************|
        |         Operator Functions        |
        |__________________________________*/
      
        /**
         * @notice Enable or disable approval for a third party ("operator") to manage all of caller's tokens
         * @param _operator  Address to add to the set of authorized operators
         * @param _approved  True if the operator is approved, false to revoke approval
         */
        function setApprovalForAll(address _operator, bool _approved)
          external
        {
          // Update operator status
          operators[msg.sender][_operator] = _approved;
          emit ApprovalForAll(msg.sender, _operator, _approved);
        }
      
        /**
         * @notice Queries the approval status of an operator for a given owner
         * @param _owner     The owner of the Tokens
         * @param _operator  Address of authorized operator
         * @return True if the operator is approved, false if not
         */
        function isApprovedForAll(address _owner, address _operator)
          public view returns (bool isOperator)
        {
          return operators[_owner][_operator];
        }
      
      
        /***********************************|
        |         Balance Functions         |
        |__________________________________*/
      
        /**
         * @notice Get the balance of an account's Tokens
         * @param _owner  The address of the token holder
         * @param _id     ID of the Token
         * @return The _owner's balance of the Token type requested
         */
        function balanceOf(address _owner, uint256 _id)
          public view returns (uint256)
        {
          return balances[_owner][_id];
        }
      
        /**
         * @notice Get the balance of multiple account/token pairs
         * @param _owners The addresses of the token holders
         * @param _ids    ID of the Tokens
         * @return        The _owner's balance of the Token types requested (i.e. balance for each (owner, id) pair)
         */
        function balanceOfBatch(address[] memory _owners, uint256[] memory _ids)
          public view returns (uint256[] memory)
        {
          require(_owners.length == _ids.length, "ERC1155#balanceOfBatch: INVALID_ARRAY_LENGTH");
      
          // Variables
          uint256[] memory batchBalances = new uint256[](_owners.length);
      
          // Iterate over each owner and token ID
          for (uint256 i = 0; i < _owners.length; i++) {
            batchBalances[i] = balances[_owners[i]][_ids[i]];
          }
      
          return batchBalances;
        }
      
      
        /***********************************|
        |          ERC165 Functions         |
        |__________________________________*/
      
        /**
         * INTERFACE_SIGNATURE_ERC165 = bytes4(keccak256("supportsInterface(bytes4)"));
         */
        bytes4 constant private INTERFACE_SIGNATURE_ERC165 = 0x01ffc9a7;
      
        /**
         * INTERFACE_SIGNATURE_ERC1155 =
         * bytes4(keccak256("safeTransferFrom(address,address,uint256,uint256,bytes)")) ^
         * bytes4(keccak256("safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)")) ^
         * bytes4(keccak256("balanceOf(address,uint256)")) ^
         * bytes4(keccak256("balanceOfBatch(address[],uint256[])")) ^
         * bytes4(keccak256("setApprovalForAll(address,bool)")) ^
         * bytes4(keccak256("isApprovedForAll(address,address)"));
         */
        bytes4 constant private INTERFACE_SIGNATURE_ERC1155 = 0xd9b67a26;
      
        /**
         * @notice Query if a contract implements an interface
         * @param _interfaceID  The interface identifier, as specified in ERC-165
         * @return `true` if the contract implements `_interfaceID` and
         */
        function supportsInterface(bytes4 _interfaceID) external view returns (bool) {
          if (_interfaceID == INTERFACE_SIGNATURE_ERC165 ||
              _interfaceID == INTERFACE_SIGNATURE_ERC1155) {
            return true;
          }
          return false;
        }
      
      }
      
      // File: contracts\multi-token-standard\tokens\ERC1155\ERC1155Metadata.sol
      
      pragma solidity ^0.5.11;
      
      
      
      /**
       * @notice Contract that handles metadata related methods.
       * @dev Methods assume a deterministic generation of URI based on token IDs.
       *      Methods also assume that URI uses hex representation of token IDs.
       */
      contract ERC1155Metadata {
      
        // URI's default URI prefix
        string internal baseMetadataURI;
        event URI(string _uri, uint256 indexed _id);
      
      
        /***********************************|
        |     Metadata Public Function s    |
        |__________________________________*/
      
        /**
         * @notice A distinct Uniform Resource Identifier (URI) for a given token.
         * @dev URIs are defined in RFC 3986.
         *      URIs are assumed to be deterministically generated based on token ID
         *      Token IDs are assumed to be represented in their hex format in URIs
         * @return URI string
         */
        function uri(uint256 _id) public view returns (string memory) {
          return string(abi.encodePacked(baseMetadataURI, _uint2str(_id), ".json"));
        }
      
      
        /***********************************|
        |    Metadata Internal Functions    |
        |__________________________________*/
      
        /**
         * @notice Will emit default URI log event for corresponding token _id
         * @param _tokenIDs Array of IDs of tokens to log default URI
         */
        function _logURIs(uint256[] memory _tokenIDs) internal {
          string memory baseURL = baseMetadataURI;
          string memory tokenURI;
      
          for (uint256 i = 0; i < _tokenIDs.length; i++) {
            tokenURI = string(abi.encodePacked(baseURL, _uint2str(_tokenIDs[i]), ".json"));
            emit URI(tokenURI, _tokenIDs[i]);
          }
        }
      
        /**
         * @notice Will emit a specific URI log event for corresponding token
         * @param _tokenIDs IDs of the token corresponding to the _uris logged
         * @param _URIs    The URIs of the specified _tokenIDs
         */
        function _logURIs(uint256[] memory _tokenIDs, string[] memory _URIs) internal {
          require(_tokenIDs.length == _URIs.length, "ERC1155Metadata#_logURIs: INVALID_ARRAYS_LENGTH");
          for (uint256 i = 0; i < _tokenIDs.length; i++) {
            emit URI(_URIs[i], _tokenIDs[i]);
          }
        }
      
        /**
         * @notice Will update the base URL of token's URI
         * @param _newBaseMetadataURI New base URL of token's URI
         */
        function _setBaseMetadataURI(string memory _newBaseMetadataURI) internal {
          baseMetadataURI = _newBaseMetadataURI;
        }
      
      
        /***********************************|
        |    Utility Internal Functions     |
        |__________________________________*/
      
        /**
         * @notice Convert uint256 to string
         * @param _i Unsigned integer to convert to string
         */
        function _uint2str(uint256 _i) internal pure returns (string memory _uintAsString) {
          if (_i == 0) {
            return "0";
          }
      
          uint256 j = _i;
          uint256 ii = _i;
          uint256 len;
      
          // Get number of bytes
          while (j != 0) {
            len++;
            j /= 10;
          }
      
          bytes memory bstr = new bytes(len);
          uint256 k = len - 1;
      
          // Get each individual ASCII
          while (ii != 0) {
            bstr[k--] = byte(uint8(48 + ii % 10));
            ii /= 10;
          }
      
          // Convert to string
          return string(bstr);
        }
      
      }
      
      // File: contracts\multi-token-standard\tokens\ERC1155\ERC1155MintBurn.sol
      
      pragma solidity ^0.5.12;
      
      
      
      /**
       * @dev Multi-Fungible Tokens with minting and burning methods. These methods assume
       *      a parent contract to be executed as they are `internal` functions
       */
      contract ERC1155MintBurn is ERC1155 {
      
      
        /****************************************|
        |            Minting Functions           |
        |_______________________________________*/
      
        /**
         * @notice Mint _amount of tokens of a given id
         * @param _to      The address to mint tokens to
         * @param _id      Token id to mint
         * @param _amount  The amount to be minted
         * @param _data    Data to pass if receiver is contract
         */
        function _mint(address _to, uint256 _id, uint256 _amount, bytes memory _data)
          internal
        {
          // Add _amount
          balances[_to][_id] = balances[_to][_id].add(_amount);
      
          // Emit event
          emit TransferSingle(msg.sender, address(0x0), _to, _id, _amount);
      
          // Calling onReceive method if recipient is contract
          _callonERC1155Received(address(0x0), _to, _id, _amount, _data);
        }
      
        /**
         * @notice Mint tokens for each ids in _ids
         * @param _to       The address to mint tokens to
         * @param _ids      Array of ids to mint
         * @param _amounts  Array of amount of tokens to mint per id
         * @param _data    Data to pass if receiver is contract
         */
        function _batchMint(address _to, uint256[] memory _ids, uint256[] memory _amounts, bytes memory _data)
          internal
        {
          require(_ids.length == _amounts.length, "ERC1155MintBurn#batchMint: INVALID_ARRAYS_LENGTH");
      
          // Number of mints to execute
          uint256 nMint = _ids.length;
      
           // Executing all minting
          for (uint256 i = 0; i < nMint; i++) {
            // Update storage balance
            balances[_to][_ids[i]] = balances[_to][_ids[i]].add(_amounts[i]);
          }
      
          // Emit batch mint event
          emit TransferBatch(msg.sender, address(0x0), _to, _ids, _amounts);
      
          // Calling onReceive method if recipient is contract
          _callonERC1155BatchReceived(address(0x0), _to, _ids, _amounts, _data);
        }
      
      
        /****************************************|
        |            Burning Functions           |
        |_______________________________________*/
      
        /**
         * @notice Burn _amount of tokens of a given token id
         * @param _from    The address to burn tokens from
         * @param _id      Token id to burn
         * @param _amount  The amount to be burned
         */
        function _burn(address _from, uint256 _id, uint256 _amount)
          internal
        {
          //Substract _amount
          balances[_from][_id] = balances[_from][_id].sub(_amount);
      
          // Emit event
          emit TransferSingle(msg.sender, _from, address(0x0), _id, _amount);
        }
      
        /**
         * @notice Burn tokens of given token id for each (_ids[i], _amounts[i]) pair
         * @param _from     The address to burn tokens from
         * @param _ids      Array of token ids to burn
         * @param _amounts  Array of the amount to be burned
         */
        function _batchBurn(address _from, uint256[] memory _ids, uint256[] memory _amounts)
          internal
        {
          require(_ids.length == _amounts.length, "ERC1155MintBurn#batchBurn: INVALID_ARRAYS_LENGTH");
      
          // Number of mints to execute
          uint256 nBurn = _ids.length;
      
           // Executing all minting
          for (uint256 i = 0; i < nBurn; i++) {
            // Update storage balance
            balances[_from][_ids[i]] = balances[_from][_ids[i]].sub(_amounts[i]);
          }
      
          // Emit batch mint event
          emit TransferBatch(msg.sender, _from, address(0x0), _ids, _amounts);
        }
      
      }
      
      // File: contracts\Strings.sol
      
      pragma solidity ^0.5.11;
      
      library Strings {
        // via https://github.com/oraclize/ethereum-api/blob/master/oraclizeAPI_0.5.sol
        function strConcat(string memory _a, string memory _b, string memory _c, string memory _d, string memory _e) internal pure returns (string memory) {
            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;
            for (uint i = 0; i < _ba.length; i++) babcde[k++] = _ba[i];
            for (uint i = 0; i < _bb.length; i++) babcde[k++] = _bb[i];
            for (uint i = 0; i < _bc.length; i++) babcde[k++] = _bc[i];
            for (uint i = 0; i < _bd.length; i++) babcde[k++] = _bd[i];
            for (uint i = 0; i < _be.length; i++) babcde[k++] = _be[i];
            return string(babcde);
          }
      
          function strConcat(string memory _a, string memory _b, string memory _c, string memory _d) internal pure returns (string memory) {
              return strConcat(_a, _b, _c, _d, "");
          }
      
          function strConcat(string memory _a, string memory _b, string memory _c) internal pure returns (string memory) {
              return strConcat(_a, _b, _c, "", "");
          }
      
          function strConcat(string memory _a, string memory _b) internal pure returns (string memory) {
              return strConcat(_a, _b, "", "", "");
          }
      
          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\ERC1155Tradable.sol
      
      pragma solidity ^0.5.12;
      
      
      
      
      
      
      contract OwnableDelegateProxy { }
      
      contract ProxyRegistry {
        mapping(address => OwnableDelegateProxy) public proxies;
      }
      
      interface ERC721 {
          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);
          function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
          function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
          function approve(address _approved, uint256 _tokenId) external payable;
          function setApprovalForAll(address _operator, bool _approved) external;
          function getApproved(uint256 _tokenId) external view returns (address);
          function isApprovedForAll(address _owner, address _operator) external view returns (bool);
      }
      
      /**
       * @title ERC1155Tradable
       * ERC1155Tradable - ERC1155 contract that whitelists an operator address, has create and mint functionality, and supports useful standards from OpenZeppelin, 
        like _exists(), name(), symbol(), and totalSupply()
       */
      contract ERC1155Tradable is ERC1155, ERC1155MintBurn, ERC1155Metadata, Ownable {
        using Strings for string;
      
        event ArtCreated(uint token, uint amount, string name, address artist);
      
        uint256 printFee = 4000000000000000;
        address admin;
        address treasurer;
        bool lock = false;
        address oldContract = 0x677D8FE828Fd7143FF3CeE5883b7fC81e7c2de60;
        address proxyRegistryAddress;
        uint256 private _currentTokenID = 0;
        mapping (uint256 => address) public creators;
        mapping (uint256 => uint256) public tokenSupply;
        // Contract name
        string public name;
        // Contract symbol
        string public symbol;
      
        /**
         * @dev Require msg.sender to be the creator of the token id
         */
        modifier creatorOnly(uint256 _id) {
          require(creators[_id] == msg.sender, "ERC1155Tradable#creatorOnly: ONLY_CREATOR_ALLOWED");
          _;
        }
      
        /**
         * @dev Require msg.sender to own more than 0 of the token id
         */
        modifier ownersOnly(uint256 _id, uint256 _amount) {
          require(balances[msg.sender][_id] >= _amount, "ERC1155Tradable#ownersOnly: ONLY_OWNERS_ALLOWED");
          _;
        }
      
        /**
         * @dev Require msg.sender to be admin
         */
        modifier onlyAdmin() {
          require(msg.sender == admin, "ERC1155Tradable#ownersOnly: ONLY_ADMIN_ALLOWED");
          _;
        }
      
        constructor(
          string memory _name,
          string memory _symbol,
          address _proxyRegistryAddress
        ) public {
          name = _name;
          symbol = _symbol;
          admin = 0x486082148bc8Dc9DEe8c9E53649ea148291FF292;
          treasurer = 0xEbBFE1A7ffd8C0065eF1a87F018BaB8cf9aF1207;
          proxyRegistryAddress = _proxyRegistryAddress;
        }
      
        function uri(
          uint256 _id
        ) public view returns (string memory) {
          require(_exists(_id), "ERC721Tradable#uri: NONEXISTENT_TOKEN");
          return Strings.strConcat(
            baseMetadataURI,
            Strings.uint2str(_id)
          );
        }
      
        /**
          * @dev Returns the total quantity for a token ID
          * @param _id uint256 ID of the token to query
          * @return amount of token in existence
          */
        function totalSupply(
          uint256 _id
        ) public view returns (uint256) {
          return tokenSupply[_id];
        }
      
        /**
         * @dev Will update the base URL of token's URI
         * @param _newBaseMetadataURI New base URL of token's URI
         */
        function setBaseMetadataURI(
          string memory _newBaseMetadataURI
        ) public onlyAdmin {
          _setBaseMetadataURI(_newBaseMetadataURI);
        }
      
        /**
          * @dev Change the creator address for given tokens
          * @param _to   Address of the new creator
          * @param _ids  Array of Token IDs to change creator
          */
        function setCreator(
          address _to,
          uint256[] memory _ids
        ) public {
          require(_to != address(0), "ERC1155Tradable#setCreator: INVALID_ADDRESS.");
          for (uint256 i = 0; i < _ids.length; i++) {
            uint256 id = _ids[i];
            _setCreator(_to, id);
          }
        }
      
        /**
         * Override isApprovedForAll to whitelist user's OpenSea proxy accounts to enable gas-free listings.
         */
        function isApprovedForAll(
          address _owner,
          address _operator
        ) public view returns (bool isOperator) {
          // Whitelist OpenSea proxy contract for easy trading.
          ProxyRegistry proxyRegistry = ProxyRegistry(proxyRegistryAddress);
          if (address(proxyRegistry.proxies(_owner)) == _operator) {
            return true;
          }
      
          if (address(this) == _operator) {
            return true;
          }
      
          return ERC1155.isApprovedForAll(_owner, _operator);
        }
      
        /**
          * @dev Change the creator address for given token
          * @param _to   Address of the new creator
          * @param _id  Token IDs to change creator of
          */
        function _setCreator(address _to, uint256 _id) internal creatorOnly(_id)
        {
            creators[_id] = _to;
        }
      
        /**
          * @dev Returns whether the specified token exists by checking to see if it has a creator
          * @param _id uint256 ID of the token to query the existence of
          * @return bool whether the token exists
          */
        function _exists(
          uint256 _id
        ) internal view returns (bool) {
          return creators[_id] != address(0);
        }
      
        /**
          * @dev calculates the next token ID based on value of _currentTokenID
          * @return uint256 for the next token ID
          */
        function _getNextTokenID() private view returns (uint256) {
          return _currentTokenID.add(1);
        }
      
        /**
          * @dev increments the value of _currentTokenID
          */
        function _incrementTokenTypeId() private  {
          _currentTokenID++;
        }
      
        /**
          * @dev Creates a new token type and assigns _initialSupply to an address
          * NOTE: remove onlyOwner if you want third parties to create new tokens on your contract (which may change your IDs)
          * @param _initialSupply amount to supply the first owner
          * @param _name of artwork
          * @param _uri Optional URI for this token type
          * @param _data Data to pass if receiver is contract
          * @return The newly created token ID
          */
        function create(
          uint256 _initialSupply,
          string calldata _name,
          string calldata _uri,
          bytes calldata _data
        ) external payable returns (uint256) {
          require(_initialSupply > 0, "Cannot print 0 pieces!");
          require(msg.value >= printFee * _initialSupply, "Insufficient Balance");
      
          treasurer.call.value(msg.value)("");
          uint256 _id = _getNextTokenID();
          _incrementTokenTypeId();
          creators[_id] = msg.sender;
      
          if (bytes(_uri).length > 0) {
            emit URI(_uri, _id);
          }
      
          _mint(msg.sender, _id, _initialSupply, _data);
      
          tokenSupply[_id] = _initialSupply;
          emit ArtCreated(_id, _initialSupply, _name, msg.sender);
          return _id;
        }
      
        function toggleImports() public onlyAdmin{
          lock = !lock;
        }
      
        function importToken(uint256 _tokenIndex, string calldata _uri, bytes calldata _data) external{
          require(lock == false, "Imports Locked");
          ERC721(oldContract).transferFrom(msg.sender, address(0), _tokenIndex);
          uint256 _id = _getNextTokenID();
          _incrementTokenTypeId();
          creators[_id] = msg.sender;
      
          if (bytes(_uri).length > 0) {
            emit URI(_uri, _id);
          }
          _mint(msg.sender, _id, 1, _data);
          tokenSupply[_id] = 1;
          emit ArtCreated(_id, 1, "Imported Art", msg.sender);
        }
      
      }
      
      // File: contracts\BAE.sol
      
      // SPDX-License-Identifier: MIT
      
      pragma solidity ^0.5.12;
      
      contract BAE is ERC1155Tradable {
          event AuctionStart(address creator, uint256 token, uint256 startingBid, uint256 auctionIndex, uint256 expiry);
          event AuctionEnd(uint256 token, uint256 finalBid, address owner, address newOwner, uint256 auctionIndex);
          event AuctionReset(uint256 auctionIndex, uint256 newExpiry, uint256 newPrice);
          event Bid(address bidder, uint256 token, uint256 auctionIndex, uint256 amount);
      
          uint256 public auctionCount;
      
          uint256 public auctionFee = 5; //Out of 1000 for 100%
      
          struct auctionData{
            address owner;
            address lastBidder;
            uint256 bid;
            uint256 expiry;
            uint256 token;
          }
      
          mapping(uint256 => auctionData) public auctionList;
      
          constructor(address _proxyRegistryAddress)
          ERC1155Tradable(
            "Blockchain Art Exchange",
            "BAE",
            _proxyRegistryAddress
          ) public {
            _setBaseMetadataURI("https://api.mybae.io/tokens/");
          }
      
          function changePrintFee(uint256 _newPrice) public onlyAdmin{
            printFee = _newPrice;
          }
      
          function setAuctionFee(uint256 _newFee) public onlyAdmin{
            require(_newFee < 1000, "Fee Too High!");
            auctionFee = _newFee;
          }
      
          function createAuction(uint256 _price, uint256 _expiry, uint256 _token, uint256 _amount) public ownersOnly(_token, _amount){
            require(block.timestamp < _expiry, "Auction Date Passed");
            require(block.timestamp + (86400 * 14) > _expiry, "Auction Date Too Far");
            require(_price > 0, "Auction Price Cannot Be 0");
            for(uint x = 0; x < _amount; x++){
              safeTransferFrom(msg.sender, address(this), _token, 1, "");
              auctionList[auctionCount] = auctionData(msg.sender, address(0), _price, _expiry, _token);
              emit AuctionStart(msg.sender, _token, _price, auctionCount, _expiry);
              auctionCount++;
            }
          }
      
          function bid(uint256 _index) public payable {
            require(auctionList[_index].expiry > block.timestamp);
            require(auctionList[_index].bid + 10000000000000000 <= msg.value);
            require(msg.sender != auctionList[_index].owner);
            require(msg.sender != auctionList[_index].lastBidder);
            if(auctionList[_index].lastBidder != address(0)){
              auctionList[_index].lastBidder.call.value(auctionList[_index].bid)("");
            }
            auctionList[_index].bid = msg.value;
            auctionList[_index].lastBidder = msg.sender;
            emit Bid(msg.sender, auctionList[_index].token, _index, msg.value);
          }
      
          function buy(uint256 _index) public payable {
            require(auctionList[_index].expiry < block.timestamp);
            require(auctionList[_index].bid <= msg.value);
            require(address(0) == auctionList[_index].lastBidder);
            require(auctionList[_index].bid > 0);
            this.safeTransferFrom(address(this), msg.sender, auctionList[_index].token, 1, "");
            uint256 fee = auctionList[_index].bid * auctionFee / 1000;
            treasurer.call.value(fee)("");
            auctionList[_index].owner.call.value(auctionList[_index].bid.sub(fee))("");
            emit AuctionEnd(auctionList[_index].token, auctionList[_index].bid, auctionList[_index].owner, msg.sender, _index);
      
            auctionList[_index].lastBidder = msg.sender;
            auctionList[_index].bid = 0;
          }
      
          function resetAuction(uint256 _index, uint256 _expiry, uint256 _price) public{
            require(msg.sender == auctionList[_index].owner, "You Dont Own This Auction!");
            require(address(0) == auctionList[_index].lastBidder, "Someone Won This Auction!");
            require(auctionList[_index].expiry < block.timestamp, "Auction Is Still Running");
            require(_expiry > block.timestamp, "Auction Date Passed");
            auctionList[_index].expiry = _expiry;
            auctionList[_index].bid = _price;
            emit AuctionReset(_index, _expiry, _price);
          }
      
          function concludeAuction(uint256 _index) public{
            require(auctionList[_index].expiry < block.timestamp, "Auction Not Expired");
            require(auctionList[_index].bid != 0, "Auction Concluded");
            if(auctionList[_index].lastBidder != address(0)){
              this.safeTransferFrom(address(this), auctionList[_index].lastBidder, auctionList[_index].token, 1, "");
              uint256 fee = auctionList[_index].bid * auctionFee / 1000;
              treasurer.call.value(fee)("");
              auctionList[_index].owner.call.value(auctionList[_index].bid.sub(fee))("");
              emit AuctionEnd(auctionList[_index].token, auctionList[_index].bid, auctionList[_index].owner, auctionList[_index].lastBidder, _index);
            }
            else{
              this.safeTransferFrom(address(this), auctionList[_index].owner, auctionList[_index].token, 1, "");
              emit AuctionEnd(auctionList[_index].token, 0, auctionList[_index].owner, auctionList[_index].owner, _index);
            }
            auctionList[_index].lastBidder = address(0);
            auctionList[_index].bid = 0;
          }
      
      
      }

      File 2 of 2: WyvernProxyRegistry
      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 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 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 WyvernProxyRegistry is ProxyRegistry {
      
          string public constant name = "Project Wyvern Proxy Registry";
      
          /* Whether the initial auth address has been set. */
          bool public initialAddressSet = false;
      
          constructor ()
              public
          {
              delegateProxyImplementation = new AuthenticatedProxy();
          }
      
          /** 
           * Grant authentication to the initial Exchange protocol contract
           *
           * @dev No delay, can only be called once - after that the standard registry process with a delay must be used
           * @param authAddress Address of the contract to grant authentication
           */
          function grantInitialAuthentication (address authAddress)
              onlyOwner
              public
          {
              require(!initialAddressSet);
              initialAddressSet = true;
              contracts[authAddress] = true;
          }
      
      }
      
      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));
          }
      
      }