POA Network merged with the Gnosis Chain. More information about the merger.

Contract Address Details

0xB2B59AeA95446e4375D04E1A0113D85c3864a0C2

Contract Name
ArianeeStore
Creator
0x860847–43debe at 0xc6760b–1a5926
Balance
0 POA ( )
Tokens
Fetching tokens...
Transactions
22,932 Transactions
Transfers
46,120 Transfers
Gas Used
6,419,846,597
Last Balance Update
28803032
Contract name:
ArianeeStore




Optimization enabled
true
Compiler version
v0.5.6+commit.b259423e




Verified at
2019-06-25T08:34:55.335977Z

Constructor Arguments

abd6e7cb50984ff9c2f3e18a2660c3353dadf4e3291deeb275dae2cd1e44fe0517ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ec91da3fd0782e51c6b3986e9e672fd566868e71f3dbc2d6c2cd6fbb3e361af2a700000000000000000000000055d536e4d6c1993d8ef2e2a4ef77f02088419420000000000000000000000000363574e6c5c71c343d7348093d84320c76d5dd29000000000000000000000000502a9c8af2441a1e276909405119fae21f3dc421000000000000000000000000000000000000000000000000016345785d8a0000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000a

Arg [0] (address) : 0x2660c3353dadf4e3291deeb275dae2cd1e44fe05
Arg [1] (address) : 0xd58478811de00f9e6eb34345acd53bf8fd09d3ec
Arg [2] (address) : 0x672fd566868e71f3dbc2d6c2cd6fbb3e361af2a7
Arg [3] (uint256) : 490019056180593367793749917294631053572167537696
Arg [4] (uint256) : 309477624673013687630376930315886218533548711209
Arg [5] (uint256) : 457669529761844218696602317839956366406530745377
Arg [6] (uint256) : 100000000000000000

              

Contract source code

// File: @0xcert/ethereum-utils-contracts/src/contracts/math/safe-math.sol

pragma solidity 0.5.6;

/**
 * @dev Math operations with safety checks that throw on error. This contract is based on the
 * source code at:
 * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol.
 */
library SafeMath
{

  /**
   * @dev Error constants.
   */
  string constant OVERFLOW = "008001";
  string constant SUBTRAHEND_GREATER_THEN_MINUEND = "008002";
  string constant DIVISION_BY_ZERO = "008003";

  /**
   * @dev Multiplies two numbers, reverts on overflow.
   * @param _factor1 Factor number.
   * @param _factor2 Factor number.
   * @return The product of the two factors.
   */
  function mul(
    uint256 _factor1,
    uint256 _factor2
  )
    internal
    pure
    returns (uint256 product)
  {
    // 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 (_factor1 == 0)
    {
      return 0;
    }

    product = _factor1 * _factor2;
    require(product / _factor1 == _factor2, OVERFLOW);
  }

  /**
   * @dev Integer division of two numbers, truncating the quotient, reverts on division by zero.
   * @param _dividend Dividend number.
   * @param _divisor Divisor number.
   * @return The quotient.
   */
  function div(
    uint256 _dividend,
    uint256 _divisor
  )
    internal
    pure
    returns (uint256 quotient)
  {
    // Solidity automatically asserts when dividing by 0, using all gas.
    require(_divisor > 0, DIVISION_BY_ZERO);
    quotient = _dividend / _divisor;
    // assert(_dividend == _divisor * quotient + _dividend % _divisor); // There is no case in which this doesn't hold.
  }

  /**
   * @dev Substracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
   * @param _minuend Minuend number.
   * @param _subtrahend Subtrahend number.
   * @return Difference.
   */
  function sub(
    uint256 _minuend,
    uint256 _subtrahend
  )
    internal
    pure
    returns (uint256 difference)
  {
    require(_subtrahend <= _minuend, SUBTRAHEND_GREATER_THEN_MINUEND);
    difference = _minuend - _subtrahend;
  }

  /**
   * @dev Adds two numbers, reverts on overflow.
   * @param _addend1 Number.
   * @param _addend2 Number.
   * @return Sum.
   */
  function add(
    uint256 _addend1,
    uint256 _addend2
  )
    internal
    pure
    returns (uint256 sum)
  {
    sum = _addend1 + _addend2;
    require(sum >= _addend1, OVERFLOW);
  }

  /**
    * @dev Divides two numbers and returns the remainder (unsigned integer modulo), reverts when
    * dividing by zero.
    * @param _dividend Number.
    * @param _divisor Number.
    * @return Remainder.
    */
  function mod(
    uint256 _dividend,
    uint256 _divisor
  )
    internal
    pure
    returns (uint256 remainder)
  {
    require(_divisor != 0, DIVISION_BY_ZERO);
    remainder = _dividend % _divisor;
  }

}

// File: @0xcert/ethereum-erc721-contracts/src/contracts/erc721.sol

pragma solidity 0.5.6;

/**
 * @dev ERC-721 non-fungible token standard.
 * See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md.
 */
interface ERC721
{

  /**
   * @dev Emits when ownership of any NFT changes by any mechanism. This event emits when NFTs are
   * created (`from` == 0) and destroyed (`to` == 0). Exception: during contract creation, any
   * number of NFTs may be created and assigned without emitting Transfer. At the time of any
   * transfer, the approved address for that NFT (if any) is reset to none.
   */
  event Transfer(
    address indexed _from,
    address indexed _to,
    uint256 indexed _tokenId
  );

  /**
   * @dev This emits when the approved address for an NFT is changed or reaffirmed. The zero
   * address indicates there is no approved address. When a Transfer event emits, this also
   * indicates that the approved address for that NFT (if any) is reset to none.
   */
  event Approval(
    address indexed _owner,
    address indexed _approved,
    uint256 indexed _tokenId
  );

  /**
   * @dev This emits when an operator is enabled or disabled for an owner. The operator can manage
   * all NFTs of the owner.
   */
  event ApprovalForAll(
    address indexed _owner,
    address indexed _operator,
    bool _approved
  );

  /**
   * @dev Transfers the ownership of an NFT from one address to another address.
   * @notice Throws unless `msg.sender` is the current owner, an authorized operator, or the
   * approved address for this NFT. Throws if `_from` is not the current owner. Throws if `_to` is
   * the zero address. Throws if `_tokenId` is not a valid NFT. When transfer is complete, this
   * function checks if `_to` is a smart contract (code size > 0). If so, it calls
   * `onERC721Received` on `_to` and throws if the return value is not
   * `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`.
   * @param _from The current owner of the NFT.
   * @param _to The new owner.
   * @param _tokenId The NFT to transfer.
   * @param _data Additional data with no specified format, sent in call to `_to`.
   */
  function safeTransferFrom(
    address _from,
    address _to,
    uint256 _tokenId,
    bytes calldata _data
  )
    external;

  /**
   * @dev Transfers the ownership of an NFT from one address to another address.
   * @notice This works identically to the other function with an extra data parameter, except this
   * function just sets data to ""
   * @param _from The current owner of the NFT.
   * @param _to The new owner.
   * @param _tokenId The NFT to transfer.
   */
  function safeTransferFrom(
    address _from,
    address _to,
    uint256 _tokenId
  )
    external;

  /**
   * @dev Throws unless `msg.sender` is the current owner, an authorized operator, or the approved
   * address for this NFT. Throws if `_from` is not the current owner. Throws if `_to` is the zero
   * address. Throws if `_tokenId` is not a valid NFT.
   * @notice The caller is responsible to confirm that `_to` is capable of receiving NFTs or else
   * they mayb be permanently lost.
   * @param _from The current owner of the NFT.
   * @param _to The new owner.
   * @param _tokenId The NFT to transfer.
   */
  function transferFrom(
    address _from,
    address _to,
    uint256 _tokenId
  )
    external;

  /**
   * @dev Set or reaffirm the approved address for an NFT.
   * @notice The zero address indicates there is no approved address. Throws unless `msg.sender` is
   * the current NFT owner, or an authorized operator of the current owner.
   * @param _approved The new approved NFT controller.
   * @param _tokenId The NFT to approve.
   */
  function approve(
    address _approved,
    uint256 _tokenId
  )
    external;

  /**
   * @dev Enables or disables approval for a third party ("operator") to manage all of
   * `msg.sender`'s assets. It also emits the ApprovalForAll event.
   * @notice The contract MUST allow multiple operators per owner.
   * @param _operator Address to add to the set of authorized operators.
   * @param _approved True if the operators is approved, false to revoke approval.
   */
  function setApprovalForAll(
    address _operator,
    bool _approved
  )
    external;

  /**
   * @dev Returns the number of NFTs owned by `_owner`. NFTs assigned to the zero address are
   * considered invalid, and this function throws for queries about the zero address.
   * @param _owner Address for whom to query the balance.
   * @return Balance of _owner.
   */
  function balanceOf(
    address _owner
  )
    external
    view
    returns (uint256);

  /**
   * @dev Returns the address of the owner of the NFT. NFTs assigned to zero address are considered
   * invalid, and queries about them do throw.
   * @param _tokenId The identifier for an NFT.
   * @return Address of _tokenId owner.
   */
  function ownerOf(
    uint256 _tokenId
  )
    external
    view
    returns (address);

  /**
   * @dev Get the approved address for a single NFT.
   * @notice Throws if `_tokenId` is not a valid NFT.
   * @param _tokenId The NFT to find the approved address for.
   * @return Address that _tokenId is approved for.
   */
  function getApproved(
    uint256 _tokenId
  )
    external
    view
    returns (address);

  /**
   * @dev Returns true if `_operator` is an approved operator for `_owner`, false otherwise.
   * @param _owner The address that owns the NFTs.
   * @param _operator The address that acts on behalf of the owner.
   * @return True if approved for all, false otherwise.
   */
  function isApprovedForAll(
    address _owner,
    address _operator
  )
    external
    view
    returns (bool);

}

// File: @0xcert/ethereum-erc721-contracts/src/contracts/erc721-metadata.sol

pragma solidity 0.5.6;

/**
 * @dev Optional metadata extension for ERC-721 non-fungible token standard.
 * See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md.
 */
interface ERC721Metadata
{

  /**
   * @dev Returns a descriptive name for a collection of NFTs in this contract.
   * @return Representing name.
   */
  function name()
    external
    view
    returns (string memory _name);

  /**
   * @dev Returns a abbreviated name for a collection of NFTs in this contract.
   * @return Representing symbol.
   */
  function symbol()
    external
    view
    returns (string memory _symbol);

  /**
   * @dev Returns a distinct Uniform Resource Identifier (URI) for a given asset. It Throws if
   * `_tokenId` is not a valid NFT. URIs are defined in RFC3986. The URI may point to a JSON file
   * that conforms to the "ERC721 Metadata JSON Schema".
   * @return URI of _tokenId.
   */
  function tokenURI(uint256 _tokenId)
    external
    view
    returns (string memory);

}

// File: @0xcert/ethereum-erc721-contracts/src/contracts/erc721-enumerable.sol

pragma solidity 0.5.6;

/**
 * @dev Optional enumeration extension for ERC-721 non-fungible token standard.
 * See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md.
 */
interface ERC721Enumerable
{

  /**
   * @dev Returns a count of valid NFTs tracked by this contract, where each one of them has an
   * assigned and queryable owner not equal to the zero address.
   * @return Total supply of NFTs.
   */
  function totalSupply()
    external
    view
    returns (uint256);

  /**
   * @dev Returns the token identifier for the `_index`th NFT. Sort order is not specified.
   * @param _index A counter less than `totalSupply()`.
   * @return Token id.
   */
  function tokenByIndex(
    uint256 _index
  )
    external
    view
    returns (uint256);

  /**
   * @dev Returns the token identifier for the `_index`th NFT assigned to `_owner`. Sort order is
   * not specified. It throws if `_index` >= `balanceOf(_owner)` or if `_owner` is the zero address,
   * representing invalid NFTs.
   * @param _owner An address where we are interested in NFTs owned by them.
   * @param _index A counter less than `balanceOf(_owner)`.
   * @return Token id.
   */
  function tokenOfOwnerByIndex(
    address _owner,
    uint256 _index
  )
    external
    view
    returns (uint256);

}

// File: @0xcert/ethereum-erc721-contracts/src/contracts/erc721-token-receiver.sol

pragma solidity 0.5.6;

/**
 * @dev ERC-721 interface for accepting safe transfers.
 * See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md.
 */
interface ERC721TokenReceiver
{

  /**
   * @dev Handle the receipt of a NFT. The ERC721 smart contract calls this function on the
   * recipient after a `transfer`. This function MAY throw to revert and reject the transfer. Return
   * of other than the magic value MUST result in the transaction being reverted.
   * Returns `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` unless throwing.
   * @notice The contract address is always the message sender. A wallet/broker/auction application
   * MUST implement the wallet interface if it will accept safe transfers.
   * @param _operator The address which called `safeTransferFrom` function.
   * @param _from The address which previously owned the token.
   * @param _tokenId The NFT identifier which is being transferred.
   * @param _data Additional data with no specified format.
   * @return Returns `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
   */
  function onERC721Received(
    address _operator,
    address _from,
    uint256 _tokenId,
    bytes calldata _data
  )
    external
    returns(bytes4);

}

// File: @0xcert/ethereum-utils-contracts/src/contracts/utils/erc165.sol

pragma solidity 0.5.6;

/**
 * @dev A standard for detecting smart contract interfaces.
 * See: https://eips.ethereum.org/EIPS/eip-165.
 */
interface ERC165
{

  /**
   * @dev Checks if the smart contract implements a specific interface.
   * @notice 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: @0xcert/ethereum-utils-contracts/src/contracts/utils/supports-interface.sol

pragma solidity 0.5.6;


/**
 * @dev Implementation of standard to publish supported interfaces.
 */
contract SupportsInterface is
  ERC165
{

  /**
   * @dev Mapping of supported intefraces.
   * @notice You must not set element 0xffffffff to true.
   */
  mapping(bytes4 => bool) internal supportedInterfaces;

  /**
   * @dev Contract constructor.
   */
  constructor()
    public
  {
    supportedInterfaces[0x01ffc9a7] = true; // ERC165
  }

  /**
   * @dev Function to check which interfaces are suported by this contract.
   * @param _interfaceID Id of the interface.
   */
  function supportsInterface(
    bytes4 _interfaceID
  )
    external
    view
    returns (bool)
  {
    return supportedInterfaces[_interfaceID];
  }

}

// File: @0xcert/ethereum-utils-contracts/src/contracts/utils/address-utils.sol

pragma solidity 0.5.6;

/**
 * @dev Utility library of inline functions on addresses.
 */
library AddressUtils
{

  /**
   * @dev Returns whether the target address is a contract.
   * @param _addr Address to check.
   * @return True if _addr is a contract, false if not.
   */
  function isContract(
    address _addr
  )
    internal
    view
    returns (bool addressCheck)
  {
    uint256 size;

    /**
     * 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 { size := extcodesize(_addr) } // solhint-disable-line
    addressCheck = size > 0;
  }

}

// File: @0xcert/ethereum-erc721-contracts/src/contracts/nf-token-metadata-enumerable.sol

pragma solidity 0.5.6;








/**
 * @dev Optional metadata enumerable implementation for ERC-721 non-fungible token standard.
 */
contract NFTokenMetadataEnumerable is
  ERC721,
  ERC721Metadata,
  ERC721Enumerable,
  SupportsInterface
{
  using SafeMath for uint256;
  using AddressUtils for address;

  /**
   * @dev Error constants.
   */
  string constant ZERO_ADDRESS = "006001";
  string constant NOT_VALID_NFT = "006002";
  string constant NOT_OWNER_OR_OPERATOR = "006003";
  string constant NOT_OWNER_APPROWED_OR_OPERATOR = "006004";
  string constant NOT_ABLE_TO_RECEIVE_NFT = "006005";
  string constant NFT_ALREADY_EXISTS = "006006";
  string constant INVALID_INDEX = "006007";

  /**
   * @dev Magic value of a smart contract that can recieve NFT.
   * Equal to: bytes4(keccak256("onERC721Received(address,address,uint256,bytes)")).
   */
  bytes4 constant MAGIC_ON_ERC721_RECEIVED = 0x150b7a02;

  /**
   * @dev A descriptive name for a collection of NFTs.
   */
  string internal nftName;

  /**
   * @dev An abbreviated name for NFTs.
   */
  string internal nftSymbol;

  /**
   * @dev URI base for NFT metadata. NFT URI is made from base + NFT id.
   */
  string public uriBase;

  /**
   * @dev Array of all NFT IDs.
   */
  uint256[] internal tokens;

  /**
   * @dev Mapping from token ID its index in global tokens array.
   */
  mapping(uint256 => uint256) internal idToIndex;

  /**
   * @dev Mapping from owner to list of owned NFT IDs.
   */
  mapping(address => uint256[]) internal ownerToIds;

  /**
   * @dev Mapping from NFT ID to its index in the owner tokens list.
   */
  mapping(uint256 => uint256) internal idToOwnerIndex;

  /**
   * @dev A mapping from NFT ID to the address that owns it.
   */
  mapping (uint256 => address) internal idToOwner;

  /**
   * @dev Mapping from NFT ID to approved address.
   */
  mapping (uint256 => address) internal idToApproval;

  /**
   * @dev Mapping from owner address to mapping of operator addresses.
   */
  mapping (address => mapping (address => bool)) internal ownerToOperators;

  /**
   * @dev Emits when ownership of any NFT changes by any mechanism. This event emits when NFTs are
   * created (`from` == 0) and destroyed (`to` == 0). Exception: during contract creation, any
   * number of NFTs may be created and assigned without emitting Transfer. At the time of any
   * transfer, the approved address for that NFT (if any) is reset to none.
   * @param _from Sender of NFT (if address is zero address it indicates token creation).
   * @param _to Receiver of NFT (if address is zero address it indicates token destruction).
   * @param _tokenId The NFT that got transfered.
   */
  event Transfer(
    address indexed _from,
    address indexed _to,
    uint256 indexed _tokenId
  );

  /**
   * @dev This emits when the approved address for an NFT is changed or reaffirmed. The zero
   * address indicates there is no approved address. When a Transfer event emits, this also
   * indicates that the approved address for that NFT (if any) is reset to none.
   * @param _owner Owner of NFT.
   * @param _approved Address that we are approving.
   * @param _tokenId NFT which we are approving.
   */
  event Approval(
    address indexed _owner,
    address indexed _approved,
    uint256 indexed _tokenId
  );

  /**
   * @dev This emits when an operator is enabled or disabled for an owner. The operator can manage
   * all NFTs of the owner.
   * @param _owner Owner of NFT.
   * @param _operator Address to which we are setting operator rights.
   * @param _approved Status of operator rights(true if operator rights are given and false if
   * revoked).
   */
  event ApprovalForAll(
    address indexed _owner,
    address indexed _operator,
    bool _approved
  );

  /**
   * @dev Contract constructor.
   * @notice When implementing this contract don't forget to set nftName, nftSymbol and uriBase.
   */
  constructor()
    public
  {
    supportedInterfaces[0x80ac58cd] = true; // ERC721
    supportedInterfaces[0x5b5e139f] = true; // ERC721Metadata
    supportedInterfaces[0x780e9d63] = true; // ERC721Enumerable
  }

  /**
   * @dev Transfers the ownership of an NFT from one address to another address.
   * @notice Throws unless `msg.sender` is the current owner, an authorized operator, or the
   * approved address for this NFT. Throws if `_from` is not the current owner. Throws if `_to` is
   * the zero address. Throws if `_tokenId` is not a valid NFT. When transfer is complete, this
   * function checks if `_to` is a smart contract (code size > 0). If so, it calls
   * `onERC721Received` on `_to` and throws if the return value is not
   * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
   * @param _from The current owner of the NFT.
   * @param _to The new owner.
   * @param _tokenId The NFT to transfer.
   * @param _data Additional data with no specified format, sent in call to `_to`.
   */
  function safeTransferFrom(
    address _from,
    address _to,
    uint256 _tokenId,
    bytes calldata _data
  )
    external
  {
    _safeTransferFrom(_from, _to, _tokenId, _data);
  }

  /**
   * @dev Transfers the ownership of an NFT from one address to another address.
   * @notice This works identically to the other function with an extra data parameter, except this
   * function just sets data to "".
   * @param _from The current owner of the NFT.
   * @param _to The new owner.
   * @param _tokenId The NFT to transfer.
   */
  function safeTransferFrom(
    address _from,
    address _to,
    uint256 _tokenId
  )
    external
  {
    _safeTransferFrom(_from, _to, _tokenId, "");
  }

  /**
   * @dev Throws unless `msg.sender` is the current owner, an authorized operator, or the approved
   * address for this NFT. Throws if `_from` is not the current owner. Throws if `_to` is the zero
   * address. Throws if `_tokenId` is not a valid NFT.
   * @notice The caller is responsible to confirm that `_to` is capable of receiving NFTs or else
   * they maybe be permanently lost.
   * @param _from The current owner of the NFT.
   * @param _to The new owner.
   * @param _tokenId The NFT to transfer.
   */
  function transferFrom(
    address _from,
    address _to,
    uint256 _tokenId
  )
    external
  {
    _transferFrom(_from, _to, _tokenId);
  }

  /**
   * @dev Set or reaffirm the approved address for an NFT.
   * @notice The zero address indicates there is no approved address. Throws unless `msg.sender` is
   * the current NFT owner, or an authorized operator of the current owner.
   * @param _approved Address to be approved for the given NFT ID.
   * @param _tokenId ID of the token to be approved.
   */
  function approve(
    address _approved,
    uint256 _tokenId
  )
    external
  {
    // can operate
    address tokenOwner = idToOwner[_tokenId];
    require(
      tokenOwner == msg.sender || ownerToOperators[tokenOwner][msg.sender],
      NOT_OWNER_OR_OPERATOR
    );

    idToApproval[_tokenId] = _approved;
    emit Approval(tokenOwner, _approved, _tokenId);
  }

  /**
   * @dev Enables or disables approval for a third party ("operator") to manage all of
   * `msg.sender`'s assets. It also emits the ApprovalForAll event.
   * @notice This works even if sender doesn't own any tokens at the time.
   * @param _operator Address to add to the set of authorized operators.
   * @param _approved True if the operators is approved, false to revoke approval.
   */
  function setApprovalForAll(
    address _operator,
    bool _approved
  )
    external
  {
    ownerToOperators[msg.sender][_operator] = _approved;
    emit ApprovalForAll(msg.sender, _operator, _approved);
  }

  /**
   * @dev Returns the number of NFTs owned by `_owner`. NFTs assigned to the zero address are
   * considered invalid, and this function throws for queries about the zero address.
   * @param _owner Address for whom to query the balance.
   * @return Balance of _owner.
   */
  function balanceOf(
    address _owner
  )
    external
    view
    returns (uint256)
  {
    require(_owner != address(0), ZERO_ADDRESS);
    return ownerToIds[_owner].length;
  }

  /**
   * @dev Returns the address of the owner of the NFT. NFTs assigned to zero address are considered
   * invalid, and queries about them do throw.
   * @param _tokenId The identifier for an NFT.
   * @return Address of _tokenId owner.
   */
  function ownerOf(
    uint256 _tokenId
  )
    external
    view
    returns (address _owner)
  {
    _owner = idToOwner[_tokenId];
    require(_owner != address(0), NOT_VALID_NFT);
  }

  /**
   * @dev Get the approved address for a single NFT.
   * @notice Throws if `_tokenId` is not a valid NFT.
   * @param _tokenId ID of the NFT to query the approval of.
   * @return Address that _tokenId is approved for.
   */
  function getApproved(
    uint256 _tokenId
  )
    external
    view
    returns (address)
  {
    require(idToOwner[_tokenId] != address(0), NOT_VALID_NFT);
    return idToApproval[_tokenId];
  }

  /**
   * @dev Checks if `_operator` is an approved operator for `_owner`.
   * @param _owner The address that owns the NFTs.
   * @param _operator The address that acts on behalf of the owner.
   * @return True if approved for all, false otherwise.
   */
  function isApprovedForAll(
    address _owner,
    address _operator
  )
    external
    view
    returns (bool)
  {
    return ownerToOperators[_owner][_operator];
  }

  /**
   * @dev Returns the count of all existing NFTs.
   * @return Total supply of NFTs.
   */
  function totalSupply()
    external
    view
    returns (uint256)
  {
    return tokens.length;
  }

  /**
   * @dev Returns NFT ID by its index.
   * @param _index A counter less than `totalSupply()`.
   * @return Token id.
   */
  function tokenByIndex(
    uint256 _index
  )
    external
    view
    returns (uint256)
  {
    require(_index < tokens.length, INVALID_INDEX);
    return tokens[_index];
  }

  /**
   * @dev returns the n-th NFT ID from a list of owner's tokens.
   * @param _owner Token owner's address.
   * @param _index Index number representing n-th token in owner's list of tokens.
   * @return Token id.
   */
  function tokenOfOwnerByIndex(
    address _owner,
    uint256 _index
  )
    external
    view
    returns (uint256)
  {
    require(_index < ownerToIds[_owner].length, INVALID_INDEX);
    return ownerToIds[_owner][_index];
  }

  /**
   * @dev Returns a descriptive name for a collection of NFTs.
   * @return Representing name.
   */
  function name()
    external
    view
    returns (string memory _name)
  {
    _name = nftName;
  }

  /**
   * @dev Returns an abbreviated name for NFTs.
   * @return Representing symbol.
   */
  function symbol()
    external
    view
    returns (string memory _symbol)
  {
    _symbol = nftSymbol;
  }

  /**
   * @notice A distinct Uniform Resource Identifier (URI) for a given asset.
   * @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC 3986. The URI may point
   * to a JSON file that conforms to the "ERC721 Metadata JSON Schema".
   * @param _tokenId Id for which we want URI.
   * @return URI of _tokenId.
   */
  function tokenURI(
    uint256 _tokenId
  )
    external
    view
    returns (string memory)
  {
    require(idToOwner[_tokenId] != address(0), NOT_VALID_NFT);
    if (bytes(uriBase).length > 0)
    {
      return string(abi.encodePacked(uriBase, _uint2str(_tokenId)));
    }
    return "";
  }

  /**
   * @dev Set a distinct URI (RFC 3986) base for all nfts.
   * @notice this is a internal function which should be called from user-implemented external
   * function. Its purpose is to show and properly initialize data structures when using this
   * implementation.
   * @param _uriBase String representing RFC 3986 URI base.
   */
  function _setUriBase(
    string memory _uriBase
  )
    internal
  {
    uriBase = _uriBase;
  }

  /**
   * @dev Creates a new NFT.
   * @notice This is a private function which should be called from user-implemented external
   * function. Its purpose is to show and properly initialize data structures when using this
   * implementation.
   * @param _to The address that will own the created NFT.
   * @param _tokenId of the NFT to be created by the msg.sender.
   */
  function _create(
    address _to,
    uint256 _tokenId
  )
    internal
  {
    require(_to != address(0), ZERO_ADDRESS);
    require(idToOwner[_tokenId] == address(0), NFT_ALREADY_EXISTS);

    // add NFT
    idToOwner[_tokenId] = _to;

    uint256 length = ownerToIds[_to].push(_tokenId);
    idToOwnerIndex[_tokenId] = length - 1;

    // add to tokens array
    length = tokens.push(_tokenId);
    idToIndex[_tokenId] = length - 1;

    emit Transfer(address(0), _to, _tokenId);
  }

  /**
   * @dev Destroys a NFT.
   * @notice This is a private function which should be called from user-implemented external
   * destroy function. Its purpose is to show and properly initialize data structures when using this
   * implementation.
   * @param _tokenId ID of the NFT to be destroyed.
   */
  function _destroy(
    uint256 _tokenId
  )
    internal
  {
    // valid NFT
    address _owner = idToOwner[_tokenId];
    require(_owner != address(0), NOT_VALID_NFT);

    // clear approval
    if (idToApproval[_tokenId] != address(0))
    {
      delete idToApproval[_tokenId];
    }

    // remove NFT
    assert(ownerToIds[_owner].length > 0);

    uint256 tokenToRemoveIndex = idToOwnerIndex[_tokenId];
    uint256 lastTokenIndex = ownerToIds[_owner].length - 1;
    uint256 lastToken;
    if (lastTokenIndex != tokenToRemoveIndex)
    {
      lastToken = ownerToIds[_owner][lastTokenIndex];
      ownerToIds[_owner][tokenToRemoveIndex] = lastToken;
      idToOwnerIndex[lastToken] = tokenToRemoveIndex;
    }

    delete idToOwner[_tokenId];
    delete idToOwnerIndex[_tokenId];
    ownerToIds[_owner].length--;

    // remove from tokens array
    assert(tokens.length > 0);

    uint256 tokenIndex = idToIndex[_tokenId];
    lastTokenIndex = tokens.length - 1;
    lastToken = tokens[lastTokenIndex];

    tokens[tokenIndex] = lastToken;

    tokens.length--;
    // Consider adding a conditional check for the last token in order to save GAS.
    idToIndex[lastToken] = tokenIndex;
    idToIndex[_tokenId] = 0;

    emit Transfer(_owner, address(0), _tokenId);
  }

  /**
   * @dev Helper methods that actually does the transfer.
   * @param _from The current owner of the NFT.
   * @param _to The new owner.
   * @param _tokenId The NFT to transfer.
   */
  function _transferFrom(
    address _from,
    address _to,
    uint256 _tokenId
  )
    internal
  {
    // valid NFT
    require(_from != address(0), ZERO_ADDRESS);
    require(idToOwner[_tokenId] == _from, NOT_VALID_NFT);
    require(_to != address(0), ZERO_ADDRESS);

    // can transfer
    require(
      _from == msg.sender
      || idToApproval[_tokenId] == msg.sender
      || ownerToOperators[_from][msg.sender],
      NOT_OWNER_APPROWED_OR_OPERATOR
    );

    // clear approval
    if (idToApproval[_tokenId] != address(0))
    {
      delete idToApproval[_tokenId];
    }

    // remove NFT
    assert(ownerToIds[_from].length > 0);

    uint256 tokenToRemoveIndex = idToOwnerIndex[_tokenId];
    uint256 lastTokenIndex = ownerToIds[_from].length - 1;

    if (lastTokenIndex != tokenToRemoveIndex)
    {
      uint256 lastToken = ownerToIds[_from][lastTokenIndex];
      ownerToIds[_from][tokenToRemoveIndex] = lastToken;
      idToOwnerIndex[lastToken] = tokenToRemoveIndex;
    }

    ownerToIds[_from].length--;

    // add NFT
    idToOwner[_tokenId] = _to;
    uint256 length = ownerToIds[_to].push(_tokenId);
    idToOwnerIndex[_tokenId] = length - 1;

    emit Transfer(_from, _to, _tokenId);
  }

  /**
   * @dev Helper function that actually does the safeTransfer.
   * @param _from The current owner of the NFT.
   * @param _to The new owner.
   * @param _tokenId The NFT to transfer.
   * @param _data Additional data with no specified format, sent in call to `_to`.
   */
  function _safeTransferFrom(
    address _from,
    address _to,
    uint256 _tokenId,
    bytes memory _data
  )
    internal
  {
    if (_to.isContract())
    {
      require(
        ERC721TokenReceiver(_to)
          .onERC721Received(msg.sender, _from, _tokenId, _data) == MAGIC_ON_ERC721_RECEIVED,
        NOT_ABLE_TO_RECEIVE_NFT
      );
    }

    _transferFrom(_from, _to, _tokenId);
  }

  /**
   * @dev Helper function that changes uint to string representation.
   * @return String representation.
   */
  function _uint2str(
    uint256 _i
  )
    internal
    pure
    returns (string memory str)
  {
    if (_i == 0)
    {
      return "0";
    }
    uint256 j = _i;
    uint256 length;
    while (j != 0)
    {
      length++;
      j /= 10;
    }
    bytes memory bstr = new bytes(length);
    uint256 k = length - 1;
    j = _i;
    while (j != 0)
    {
      bstr[k--] = byte(uint8(48 + j % 10));
      j /= 10;
    }
    str = string(bstr);
  }

}

// File: @0xcert/ethereum-erc20-contracts/src/contracts/erc20.sol

pragma solidity 0.5.6;

/**
 * @title A standard interface for tokens.
 * @dev This interface uses the official ERC-20 specification from
 * https://eips.ethereum.org/EIPS/eip-20 with the additional requirement that
 * the functions specificed as optional have become required.
 */
interface ERC20
{

  /**
   * @dev Returns the name of the token.
   * @return Token name.
   */
  function name()
    external
    view
    returns (string memory _name);

  /**
   * @dev Returns the symbol of the token.
   * @return Token symbol.
   */
  function symbol()
    external
    view
    returns (string memory _symbol);

  /**
   * @dev Returns the number of decimals the token uses.
   * @return Number of decimals.
   */
  function decimals()
    external
    view
    returns (uint8 _decimals);

  /**
   * @dev Returns the total token supply.
   * @return Total supply.
   */
  function totalSupply()
    external
    view
    returns (uint256 _totalSupply);

  /**
   * @dev Returns the account balance of another account with address _owner.
   * @param _owner The address from which the balance will be retrieved.
   * @return Balance of _owner.
   */
  function balanceOf(
    address _owner
  )
    external
    view
    returns (uint256 _balance);

  /**
   * @dev Transfers _value amount of tokens to address _to, and MUST fire the Transfer event. The
   * function SHOULD throw if the message caller's account balance does not have enough tokens to
   * spend.
   * @param _to The address of the recipient.
   * @param _value The amount of token to be transferred.
   * @return Success of operation.
   */
  function transfer(
    address _to,
    uint256 _value
  )
    external
    returns (bool _success);

  /**
   * @dev Transfers _value amount of tokens from address _from to address _to, and MUST fire the
   * Transfer event.
   * @param _from The address of the sender.
   * @param _to The address of the recipient.
   * @param _value The amount of token to be transferred.
   * @return Success of operation.
   */
  function transferFrom(
    address _from,
    address _to,
    uint256 _value
  )
    external
    returns (bool _success);

  /**
   * @dev Allows _spender to withdraw from your account multiple times, up to
   * the _value amount. If this function is called again it overwrites the current
   * allowance with _value.
   * @param _spender The address of the account able to transfer the tokens.
   * @param _value The amount of tokens to be approved for transfer.
   * @return Success of operation.
   */
  function approve(
    address _spender,
    uint256 _value
  )
    external
    returns (bool _success);

  /**
   * @dev Returns the amount which _spender is still allowed to withdraw from _owner.
   * @param _owner The address of the account owning tokens.
   * @param _spender The address of the account able to transfer the tokens.
   * @return Remaining allowance.
   */
  function allowance(
    address _owner,
    address _spender
  )
    external
    view
    returns (uint256 _remaining);

  /**
   * @dev Triggers when tokens are transferred, including zero value transfers.
   */
  event Transfer(
    address indexed _from,
    address indexed _to,
    uint256 _value
  );

  /**
   * @dev Triggers on any successful call to approve(address _spender, uint256 _value).
   */
  event Approval(
    address indexed _owner,
    address indexed _spender,
    uint256 _value
  );

}

// File: @0xcert/ethereum-erc20-contracts/src/contracts/token.sol

pragma solidity 0.5.6;




/**
 * @title ERC20 standard token implementation.
 * @dev This interface uses the official ERC-20 specification from
 * https://eips.ethereum.org/EIPS/eip-20 and also implements every optional
 * function.
 */
contract Token is
  ERC20,
  SupportsInterface
{
  using SafeMath for uint256;

  /**
   * @dev Error constants.
   */
  string constant NOT_ENOUGH_BALANCE = "001001";
  string constant NOT_ENOUGH_ALLOWANCE = "001002";

  /**
   * Token name.
   */
  string internal tokenName;

  /**
   * Token symbol.
   */
  string internal tokenSymbol;

  /**
   * Number of decimals.
   */
  uint8 internal tokenDecimals;

  /**
   * Total supply of tokens.
   */
  uint256 internal tokenTotalSupply;

  /**
   * Balance information map.
   */
  mapping (address => uint256) internal balances;

  /**
   * Token allowance mapping.
   */
  mapping (address => mapping (address => uint256)) internal allowed;

  /**
   * @dev Trigger when tokens are transferred, including zero value transfers.
   */
  event Transfer(
    address indexed _from,
    address indexed _to,
    uint256 _value
  );

  /**
   * @dev Trigger on any successful call to approve(address _spender, uint256 _value).
   */
  event Approval(
    address indexed _owner,
    address indexed _spender,
    uint256 _value
  );

  /**
   * @dev Contract constructor.
   */
  constructor()
    public
  {
    supportedInterfaces[0x36372b07] = true; // ERC20
    supportedInterfaces[0x06fdde03] = true; // ERC20 name
    supportedInterfaces[0x95d89b41] = true; // ERC20 symbol
    supportedInterfaces[0x313ce567] = true; // ERC20 decimals
  }

  /**
   * @dev Returns the name of the token.
   */
  function name()
    external
    view
    returns (string memory _name)
  {
    _name = tokenName;
  }

  /**
   * @dev Returns the symbol of the token.
   */
  function symbol()
    external
    view
    returns (string memory _symbol)
  {
    _symbol = tokenSymbol;
  }

  /**
   * @dev Returns the number of decimals the token uses.
   */
  function decimals()
    external
    view
    returns (uint8 _decimals)
  {
    _decimals = tokenDecimals;
  }

  /**
   * @dev Returns the total token supply.
   */
  function totalSupply()
    external
    view
    returns (uint256 _totalSupply)
  {
    _totalSupply = tokenTotalSupply;
  }

  /**
   * @dev Returns the account balance of another account with address _owner.
   * @param _owner The address from which the balance will be retrieved.
   */
  function balanceOf(
    address _owner
  )
    external
    view
    returns (uint256 _balance)
  {
    _balance = balances[_owner];
  }

  /**
   * @dev Returns the amount which _spender is still allowed to withdraw from _owner.
   * @param _owner The address of the account owning tokens.
   * @param _spender The address of the account able to transfer the tokens.
   */
  function allowance(
    address _owner,
    address _spender
  )
    external
    view
    returns (uint256 _remaining)
  {
    _remaining = allowed[_owner][_spender];
  }

  /**
   * @dev Transfers _value amount of tokens to address _to, and MUST fire the Transfer event. The
   * function SHOULD throw if the message caller's account balance does not have enough tokens to
   * spend.
   * @param _to The address of the recipient.
   * @param _value The amount of token to be transferred.
   */
  function transfer(
    address _to,
    uint256 _value
  )
    public
    returns (bool _success)
  {
    require(_value <= balances[msg.sender], NOT_ENOUGH_BALANCE);

    balances[msg.sender] = balances[msg.sender].sub(_value);
    balances[_to] = balances[_to].add(_value);

    emit Transfer(msg.sender, _to, _value);
    _success = true;
  }

  /**
   * @dev Allows _spender to withdraw from your account multiple times, up to the _value amount. If
   * this function is called again it overwrites the current allowance with _value.
   * @notice To prevent attack vectors like the one described here:
   * https://docs.google.com/document/d/1YLPtQxZu1UAvO9cZ1O2RPXBbT0mooh4DYKjA_jp-RLM/edit and
   * discussed here: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729, clients
   * SHOULD make sure to create user interfaces in such a way that they set the allowance first to 0
   * before setting it to another value for the same spender. THOUGH The contract itself shouldn’t
   * enforce it, to allow backwards compatibility with contracts deployed before.
   * @param _spender The address of the account able to transfer the tokens.
   * @param _value The amount of tokens to be approved for transfer.
   */
  function approve(
    address _spender,
    uint256 _value
  )
    public
    returns (bool _success)
  {
    allowed[msg.sender][_spender] = _value;

    emit Approval(msg.sender, _spender, _value);
    _success = true;
  }

  /**
   * @dev Transfers _value amount of tokens from address _from to address _to, and MUST fire the
   * Transfer event.
   * @param _from The address of the sender.
   * @param _to The address of the recipient.
   * @param _value The amount of token to be transferred.
   */
  function transferFrom(
    address _from,
    address _to,
    uint256 _value
  )
    public
    returns (bool _success)
  {
    require(_value <= balances[_from], NOT_ENOUGH_BALANCE);
    require(_value <= allowed[_from][msg.sender], NOT_ENOUGH_ALLOWANCE);

    balances[_from] = balances[_from].sub(_value);
    balances[_to] = balances[_to].add(_value);
    allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);

    emit Transfer(_from, _to, _value);
    _success = true;
  }

}

// File: @0xcert/ethereum-utils-contracts/src/contracts/permission/ownable.sol

pragma solidity 0.5.6;

/**
 * @dev The contract has an owner address, and provides basic authorization control whitch
 * simplifies the implementation of user permissions. This contract is based on the source code at:
 * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/ownership/Ownable.sol
 */
contract Ownable
{

  /**
   * @dev Error constants.
   */
  string constant NOT_OWNER = "018001";
  string constant ZERO_ADDRESS = "018002";

  /**
   * @dev Address of the owner.
   */
  address public owner;

  /**
   * @dev An event which is triggered when the owner is changed.
   * @param previousOwner The address of the previous owner.
   * @param newOwner The address of the new owner.
   */
  event OwnershipTransferred(
    address indexed previousOwner,
    address indexed newOwner
  );

  /**
   * @dev The 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, NOT_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), ZERO_ADDRESS);
    emit OwnershipTransferred(owner, _newOwner);
    owner = _newOwner;
  }

}

// File: contracts/Pausable.sol

pragma solidity 0.5.6;

/**
 * @title Pausable
 * @dev Base contract which allows children to implement an emergency stop mechanism.
 */
contract Pausable is Ownable {
    event Pause();
    event Unpause();

    bool public paused = false;

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     */
    modifier whenNotPaused() {
        require(!paused);
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     */
    modifier whenPaused() {
        require(paused);
        _;
    }

    /**
     * @dev called by the owner to pause, triggers stopped state
     */
    function pause() onlyOwner whenNotPaused public {
        paused = true;
        emit Pause();
    }

    /**
     * @dev called by the owner to unpause, returns to normal state
     */
    function unpause() onlyOwner whenPaused public {
        paused = false;
        emit Unpause();
    }
}

// File: contracts/arianeeStore.sol

pragma solidity 0.5.6;

/**
 * @title Interface for contracts conforming to ERC-20
 */
contract ERC20Interface {
    function transferFrom(address from, address to, uint tokens) public returns (bool success);
    function transfer(address to, uint tokens) public returns (bool success);
    function balanceOf(address owner) public view returns (uint256);
}


/**
 * @title Interface for contracts conforming to ERC-721
 */
contract ERC721Interface {
    function reserveToken(uint256 id, address _to, uint256 _rewards) external;
    function hydrateToken(uint256 _tokenId, bytes32 _imprint, string memory _uri, address _encryptedInitialKey, uint256 _tokenRecoveryTimestamp, bool _initialKeyIsRequestKey, address _owner) public returns(uint256);
    function requestToken(uint256 _tokenId, bytes32 _hash, bool _keepRequestToken, address _newOwner, bytes calldata _signature) external returns(uint256);
    function getRewards(uint256 _tokenId) external view returns(uint256);
}


/**
 * @title Interface to interact with ArianneCreditHistory
 */
contract ArianeeCreditHistory {
    function addCreditHistory(address _spender, uint256 _price, uint256 _quantity, uint256 _type) external;
    function consumeCredits(address _spender, uint256 _type, uint256 _quantity) external returns(uint256);
    function arianeeStoreAddress() external returns(address);
}






/// @title Contract managing the Arianee economy.
contract ArianeeStore is Pausable {
    using SafeMath for uint256;
    using AddressUtils for address;

    /**
     * Interface for all the connected contracts.
     */
    ERC20Interface public acceptedToken;
    ERC721Interface public nonFungibleRegistry;
    ArianeeCreditHistory public creditHistory;

    /**
     * @dev Mapping of the credit price in $cent.
     */
    mapping(uint256 => uint256) internal creditPricesUSD;

    /**
     * @dev Mapping of the credit price in Aria.
     */
    mapping(uint256 => uint256) internal creditPrices;

    /**
     * @dev Current exchange rate Aria/$
     */
    uint256 public ariaUSDExchange;

    /**
     * @dev % of rewards dispatch.
     */
    mapping (uint8=>uint8) internal dispatchPercent;

    /**
     * @dev Address needed in contract execution.
     */
    address public authorizedExchangeAddress;
    address public protocolInfraAddress;
    address public arianeeProjectAddress;

    /**
     * @dev This emits when a new address is set.
     */
    event SetAddress(string _addressType, address _newAddress);

    /**
     * @dev This emits when a credit's price is changed (in USD)
     */
    event NewCreditPrice(uint256 _creditType, uint256 _price);

    /**
     * @dev This emits when the Aria/USD price is changed.
     */
    event NewAriaUSDExchange(uint256 _ariaUSDExchange);

    /**
     * @dev This emits when credits are buyed.
     */
    event CreditBuyed(address buyer, address _receiver, uint256 _creditType, uint256 quantity);

    /**
     * @dev This emits when a new dispatch percent is set.
     */
    event NewDispatchPercent(uint8 _percentInfra, uint8 _percentBrandsProvider, uint8 _percentOwnerProvider, uint8 _arianeeProject, uint8 _assetHolder);

    /**
     * @dev This emit when credits are spended.
     */
    event CreditSpended(uint256 _type,uint256 _quantity);

    /**
     * @dev Initialize this contract. Acts as a constructor
     * @param _acceptedToken - Address of the ERC20 accepted for this store
     * @param _nonFungibleRegistry - Address of the NFT address
     */
    constructor(
        ERC20 _acceptedToken,
        ERC721 _nonFungibleRegistry,
        address _creditHistoryAddress,
        uint256 _ariaUSDExchange,
        uint256 _creditPricesUSD0,
        uint256 _creditPricesUSD1,
        uint256 _creditPricesUSD2

    )
    public
    {
        acceptedToken = ERC20Interface(address(_acceptedToken));
        nonFungibleRegistry = ERC721Interface(address(_nonFungibleRegistry));
        creditHistory = ArianeeCreditHistory(address(_creditHistoryAddress));

        ariaUSDExchange = _ariaUSDExchange;
        creditPricesUSD[0] = _creditPricesUSD0;
        creditPricesUSD[1] = _creditPricesUSD1;
        creditPricesUSD[2] = _creditPricesUSD2;
        _updateCreditPrice();
    }


    /**
     * @notice Change address of the authorized exchange address.
     * @notice This account is the only that can change the Aria/$ exchange rate.
     * @param _authorizedExchangeAddress new address of the authorized echange address.
     */
    function setAuthorizedExchangeAddress(address _authorizedExchangeAddress) external onlyOwner(){
        authorizedExchangeAddress = _authorizedExchangeAddress;
        emit SetAddress("authorizedExchange", _authorizedExchangeAddress);
    }

    /**
     * @notice Change address of the protocol infrastructure.
     * @param _protocolInfraAddress new address of the protocol intfrastructure receiver.
     */
    function setProtocolInfraAddress(address _protocolInfraAddress) external onlyOwner() {
        protocolInfraAddress = _protocolInfraAddress;
        emit SetAddress("protocolInfra", _protocolInfraAddress);
    }

    /**
     * @notice Change address of the Arianee project address.
     * @param _arianeeProjectAddress new address of the Arianee project receiver.
     */
    function setArianeeProjectAddress(address _arianeeProjectAddress) external onlyOwner() {
        arianeeProjectAddress = _arianeeProjectAddress;
        emit SetAddress("arianeeProject", _arianeeProjectAddress);
    }

    /**
     * @notice Public function change the price of a credit type
     * @notice Can only be called by the owner of the contract
     * @param _creditType uint256 credit type to change the price
     * @param _price uint256 new price
     */
    function setCreditPrice(uint256 _creditType, uint256 _price) external onlyOwner() {
        creditPricesUSD[_creditType] = _price;
        _updateCreditPrice();

        emit NewCreditPrice(_creditType, _price);
    }

    /**
     * @notice Update Aria/USD change
     * @notice Can only be called by the authorized exchange address.
     * @param _ariaUSDExchange price of 1 $cent in aria.
    */
    function setAriaUSDExchange(uint256 _ariaUSDExchange) external {
        require(msg.sender == authorizedExchangeAddress);
        ariaUSDExchange = _ariaUSDExchange;
        _updateCreditPrice();

        emit NewAriaUSDExchange(_ariaUSDExchange);
    }

    /**
     * @notice Buy new credit against Aria
     * @param _creditType uint256 credit type to buy
     * @param _quantity uint256 quantity to buy
     * @param _to receiver of the credits
     */
    function buyCredit(uint256 _creditType, uint256 _quantity, address _to) external whenNotPaused() {

        uint256 tokens = _quantity.mul(creditPrices[_creditType]);

        // Transfer required token quantity to buy quantity credit
        require(acceptedToken.transferFrom(
                msg.sender,
                address(this),
                tokens
            ));

        creditHistory.addCreditHistory(_to, creditPrices[_creditType], _quantity, _creditType);

        emit CreditBuyed(msg.sender, _to, _creditType, _quantity);

    }

    /**
     * @notice Hydrate token and dispatch rewards.
     * @notice Reserve token if token not reserved.
     * @param _tokenId ID of the NFT to modify.
     * @param _imprint Proof of the certification.
     * @param _uri URI of the JSON certification.
     * @param _encryptedInitialKey Initial encrypted key.
     * @param _tokenRecoveryTimestamp Limit date for the issuer to be able to transfer back the NFT.
     * @param _initialKeyIsRequestKey If true set initial key as request key.
     * @param _providerBrand address of the provider of the interface.
     */
    function hydrateToken(
        uint256 _tokenId,
        bytes32 _imprint,
        string calldata _uri,
        address _encryptedInitialKey,
        uint256 _tokenRecoveryTimestamp,
        bool _initialKeyIsRequestKey,
        address _providerBrand
    )
        external whenNotPaused()
    {
        if(nonFungibleRegistry.getRewards(_tokenId) == 0){
            reserveToken(_tokenId, msg.sender);
        }
        uint256 _reward = nonFungibleRegistry.hydrateToken(_tokenId, _imprint, _uri, _encryptedInitialKey, _tokenRecoveryTimestamp, _initialKeyIsRequestKey,  msg.sender);
        _dispatchRewardsAtHydrate(_providerBrand, _reward);
    }

    /**
     * @notice Request a nft and dispatch rewards.
     * @param _tokenId ID of the NFT to transfer.
     * @param _hash Hash of tokenId + newOwner address.
     * @param _keepRequestToken If false erase the access token of the NFT.
     * @param _providerOwner address of the provider of the interface.
     */
    function requestToken(
        uint256 _tokenId,
        bytes32 _hash,
        bool _keepRequestToken,
        address _providerOwner,
        bytes calldata _signature
    )
        external whenNotPaused()
    {
        uint256 _reward = nonFungibleRegistry.requestToken(_tokenId, _hash, _keepRequestToken, msg.sender, _signature);
        _dispatchRewardsAtRequest(_providerOwner, _reward);
    }

    /**
     * @notice Change the percent of rewards per actor.
     * @notice Can only be called by owner.
     * @param _percentInfra Percent get by the infrastructure maintener.
     * @param _percentBrandsProvider Percent get by the brand software provider.
     * @param _percentOwnerProvider Percent get by the owner software provider.
     * @param _arianeeProject Percent get by the Arianee fondation.
     * @param _assetHolder Percent get by the asset owner.
     */
    function setDispatchPercent(
        uint8 _percentInfra,
        uint8 _percentBrandsProvider,
        uint8 _percentOwnerProvider,
        uint8 _arianeeProject,
        uint8 _assetHolder
    )
        external onlyOwner()
    {
        require(_percentInfra+_percentBrandsProvider+_percentOwnerProvider+_arianeeProject+_assetHolder == 100);
        dispatchPercent[0] = _percentInfra;
        dispatchPercent[1] = _percentBrandsProvider;
        dispatchPercent[2] = _percentOwnerProvider;
        dispatchPercent[3] = _arianeeProject;
        dispatchPercent[4] = _assetHolder;

        emit NewDispatchPercent(_percentInfra, _percentBrandsProvider, _percentOwnerProvider, _arianeeProject, _assetHolder);
    }

    /**
     * @notice Get all Arias from the previous store.
     * @notice Can only be called by the owner.
     * @param _oldStoreAddress address of the previous store.
     */
    function getAriaFromOldStore(address _oldStoreAddress) onlyOwner() external {
        ArianeeStore oldStore = ArianeeStore(address(_oldStoreAddress));
        oldStore.withdrawArias();
    }

    /**
     * @notice Withdraw all arias to the new store.
     * @notice Can only be called by the new store.
     */
    function withdrawArias() external {
        require(address(this) != creditHistory.arianeeStoreAddress());
        require(msg.sender == creditHistory.arianeeStoreAddress());
        acceptedToken.transfer(address(creditHistory.arianeeStoreAddress()),acceptedToken.balanceOf(address(this)));
    }

    /**
     * @notice The USD credit price per type.
     * @param _creditType for which we want the USD price.
     * @return price in USD.
     */
    function creditPriceUSD(uint256 _creditType) external view returns(uint256 _creditPriceUSD) {
        _creditPriceUSD = creditPricesUSD[_creditType];
    }

    /**
     * @notice dispatch for rewards.
     * @param _receiver for which we want the % of rewards.
     * @return % of rewards.
     */
    function percentOfDispatch(uint8 _receiver) external view returns(uint8 _percent){
        _percent = dispatchPercent[_receiver];
    }

    /**
     * @notice Send the price a of a credit in aria
     * @param _creditType uint256
     * @return returne the price of the credit type.
     */
    function getCreditPrice(uint256 _creditType) external view returns (uint256) {
        return creditPrices[_creditType];
    }

    /**
     * @dev Allow or not a transfer in the SmartAsset contract.
     * @dev not used for now.
     * @param _to Receiver of the NFT.
     * @param _from Actual owner of the NFT.
     * @param _tokenId id of the token.
     * @return true.
     */
    function canTransfer(address _to,address _from,uint256 _tokenId) external pure returns(bool){
        return true;
    }

    /**
     * @dev Allow or not the destroy of a token in the SmartAsset contract.
     * @dev not used for now.
     * @param _tokenId id of the token.
     * @param _sender address asking the destroy.
     * @return false.
     */
    function canDestroy(uint256 _tokenId, address _sender) external pure returns(bool){
      return false;
    }

    /**
     * @notice Reserve ArianeeSmartAsset
     * @param _id uint256 id of the NFT
     * @param _to address receiver of the token.
     */
    function reserveToken(uint256 _id, address _to) public whenNotPaused() {
        uint256 rewards = _spendSmartAssetsCreditFunction(0, 1);
        nonFungibleRegistry.reserveToken(_id, _to, rewards);
    }

    /**
     * @dev Internal function update creditPrice.
     * @notice creditPrice need to be >100
     */
    function _updateCreditPrice() internal{
        require(creditPricesUSD[0] * ariaUSDExchange >=100);
        require(creditPricesUSD[1] * ariaUSDExchange >=100);
        require(creditPricesUSD[2] * ariaUSDExchange >=100);
        creditPrices[0] = creditPricesUSD[0] * ariaUSDExchange;
        creditPrices[1] = creditPricesUSD[1] * ariaUSDExchange;
        creditPrices[2] = creditPricesUSD[2] * ariaUSDExchange;
    }

    /**
     * @dev Spend credits
     * @param _type credit type used.
     * @param _quantity of credit to spend.
     */
    function _spendSmartAssetsCreditFunction(uint256 _type, uint256 _quantity) internal returns (uint256) {
        uint256 rewards = creditHistory.consumeCredits(msg.sender, _type, _quantity);
        emit CreditSpended(_type, _quantity);
        return rewards;
    }

    /**
     * @dev Dispatch rewards at creation.
     * @param _providerBrand address of the provider of the interface.
     * @param _reward reward for this token.
     */
    function _dispatchRewardsAtHydrate(address _providerBrand, uint256 _reward) internal {
        acceptedToken.transfer(protocolInfraAddress,(_reward/100)*dispatchPercent[0]);
        acceptedToken.transfer(arianeeProjectAddress,(_reward/100)*dispatchPercent[3]);
        acceptedToken.transfer(_providerBrand,(_reward/100)*dispatchPercent[1]);
    }

    /**
     * @dev Dispatch rewards at client reception
     * @param _providerOwner address of the provider of the interface.
     * @param _reward reward for this token.
     */
    function _dispatchRewardsAtRequest(address _providerOwner, uint256 _reward) internal {
        acceptedToken.transfer(_providerOwner,(_reward/100)*dispatchPercent[2]);
        acceptedToken.transfer(msg.sender,(_reward/100)*dispatchPercent[4]);
    }

}
        

Contract ABI

[{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint8","name":"_percent"}],"name":"percentOfDispatch","inputs":[{"type":"uint8","name":"_receiver"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"buyCredit","inputs":[{"type":"uint256","name":"_creditType"},{"type":"uint256","name":"_quantity"},{"type":"address","name":"_to"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setAriaUSDExchange","inputs":[{"type":"uint256","name":"_ariaUSDExchange"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"getAriaFromOldStore","inputs":[{"type":"address","name":"_oldStoreAddress"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"nonFungibleRegistry","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"reserveToken","inputs":[{"type":"uint256","name":"_id"},{"type":"address","name":"_to"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"creditHistory","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"ariaUSDExchange","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setAuthorizedExchangeAddress","inputs":[{"type":"address","name":"_authorizedExchangeAddress"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"unpause","inputs":[],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setDispatchPercent","inputs":[{"type":"uint8","name":"_percentInfra"},{"type":"uint8","name":"_percentBrandsProvider"},{"type":"uint8","name":"_percentOwnerProvider"},{"type":"uint8","name":"_arianeeProject"},{"type":"uint8","name":"_assetHolder"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"acceptedToken","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"arianeeProjectAddress","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"paused","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setArianeeProjectAddress","inputs":[{"type":"address","name":"_arianeeProjectAddress"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"protocolInfraAddress","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"withdrawArias","inputs":[],"constant":false},{"type":"function","stateMutability":"pure","payable":false,"outputs":[{"type":"bool","name":""}],"name":"canDestroy","inputs":[{"type":"uint256","name":"_tokenId"},{"type":"address","name":"_sender"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"pause","inputs":[],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setProtocolInfraAddress","inputs":[{"type":"address","name":"_protocolInfraAddress"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"owner","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"_creditPriceUSD"}],"name":"creditPriceUSD","inputs":[{"type":"uint256","name":"_creditType"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"requestToken","inputs":[{"type":"uint256","name":"_tokenId"},{"type":"bytes32","name":"_hash"},{"type":"bool","name":"_keepRequestToken"},{"type":"address","name":"_providerOwner"},{"type":"bytes","name":"_signature"}],"constant":false},{"type":"function","stateMutability":"pure","payable":false,"outputs":[{"type":"bool","name":""}],"name":"canTransfer","inputs":[{"type":"address","name":"_to"},{"type":"address","name":"_from"},{"type":"uint256","name":"_tokenId"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"hydrateToken","inputs":[{"type":"uint256","name":"_tokenId"},{"type":"bytes32","name":"_imprint"},{"type":"string","name":"_uri"},{"type":"address","name":"_encryptedInitialKey"},{"type":"uint256","name":"_tokenRecoveryTimestamp"},{"type":"bool","name":"_initialKeyIsRequestKey"},{"type":"address","name":"_providerBrand"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"_newOwner"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"authorizedExchangeAddress","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getCreditPrice","inputs":[{"type":"uint256","name":"_creditType"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setCreditPrice","inputs":[{"type":"uint256","name":"_creditType"},{"type":"uint256","name":"_price"}],"constant":false},{"type":"constructor","stateMutability":"nonpayable","payable":false,"inputs":[{"type":"address","name":"_acceptedToken"},{"type":"address","name":"_nonFungibleRegistry"},{"type":"address","name":"_creditHistoryAddress"},{"type":"uint256","name":"_ariaUSDExchange"},{"type":"uint256","name":"_creditPricesUSD0"},{"type":"uint256","name":"_creditPricesUSD1"},{"type":"uint256","name":"_creditPricesUSD2"}]},{"type":"event","name":"SetAddress","inputs":[{"type":"string","name":"_addressType","indexed":false},{"type":"address","name":"_newAddress","indexed":false}],"anonymous":false},{"type":"event","name":"NewCreditPrice","inputs":[{"type":"uint256","name":"_creditType","indexed":false},{"type":"uint256","name":"_price","indexed":false}],"anonymous":false},{"type":"event","name":"NewAriaUSDExchange","inputs":[{"type":"uint256","name":"_ariaUSDExchange","indexed":false}],"anonymous":false},{"type":"event","name":"CreditBuyed","inputs":[{"type":"address","name":"buyer","indexed":false},{"type":"address","name":"_receiver","indexed":false},{"type":"uint256","name":"_creditType","indexed":false},{"type":"uint256","name":"quantity","indexed":false}],"anonymous":false},{"type":"event","name":"NewDispatchPercent","inputs":[{"type":"uint8","name":"_percentInfra","indexed":false},{"type":"uint8","name":"_percentBrandsProvider","indexed":false},{"type":"uint8","name":"_percentOwnerProvider","indexed":false},{"type":"uint8","name":"_arianeeProject","indexed":false},{"type":"uint8","name":"_assetHolder","indexed":false}],"anonymous":false},{"type":"event","name":"CreditSpended","inputs":[{"type":"uint256","name":"_type","indexed":false},{"type":"uint256","name":"_quantity","indexed":false}],"anonymous":false},{"type":"event","name":"Pause","inputs":[],"anonymous":false},{"type":"event","name":"Unpause","inputs":[],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","indexed":true},{"type":"address","name":"newOwner","indexed":true}],"anonymous":false}]
            

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106101625760e060020a600035046302ce237d811461016757806308ea00b41461019d57806313454142146101d157806317cb63b3146101ee5780632be7983314610214578063325cdebb1461023857806336a48f86146102645780633c25e4bc1461026c5780633d928843146102865780633f4ba83a146102ac57806341f45107146102b4578063451c3d80146102f65780634ade3f4f146102fe5780635c975abb146103065780636c60d174146103225780637413ccdb146103485780637a2f130d1461035057806382300d89146103585780638456cb59146103845780638a9379a41461038c5780638da5cb5b146103b2578063a5868f6e146103ba578063e261ed77146103d7578063e46638e614610468578063ec046d0a1461049e578063f2fde38b14610537578063f8a59b2f1461055d578063f9405d6a14610565578063fb55e75014610582575b600080fd5b6101876004803603602081101561017d57600080fd5b503560ff166105a5565b6040805160ff9092168252519081900360200190f35b6101cf600480360360608110156101b357600080fd5b5080359060208101359060400135600160a060020a03166105bd565b005b6101cf600480360360208110156101e757600080fd5b5035610768565b6101cf6004803603602081101561020457600080fd5b5035600160a060020a03166107c2565b61021c6108dc565b60408051600160a060020a039092168252519081900360200190f35b6101cf6004803603604081101561024e57600080fd5b5080359060200135600160a060020a03166108eb565b61021c61098e565b61027461099d565b60408051918252519081900360200190f35b6101cf6004803603602081101561029c57600080fd5b5035600160a060020a03166109a3565b6101cf610a8f565b6101cf600480360360a08110156102ca57600080fd5b5060ff813581169160208101358216916040820135811691606081013582169160809091013516610b5c565b61021c610ce2565b61021c610cf1565b61030e610d00565b604080519115158252519081900360200190f35b6101cf6004803603602081101561033857600080fd5b5035600160a060020a0316610d10565b61021c610df8565b6101cf610e07565b61030e6004803603604081101561036e57600080fd5b5080359060200135600160a060020a03166110a3565b6101cf6110ac565b6101cf600480360360208110156103a257600080fd5b5035600160a060020a0316611180565b61021c611267565b610274600480360360208110156103d057600080fd5b5035611276565b6101cf600480360360a08110156103ed57600080fd5b8135916020810135916040820135151591600160a060020a036060820135169181019060a081016080820135602060020a81111561042a57600080fd5b82018360208201111561043c57600080fd5b803590602001918460018302840111602060020a8311171561045d57600080fd5b509092509050611288565b61030e6004803603606081101561047e57600080fd5b50600160a060020a0381358116916020810135909116906040013561137b565b6101cf600480360360e08110156104b457600080fd5b813591602081013591810190606081016040820135602060020a8111156104da57600080fd5b8201836020820111156104ec57600080fd5b803590602001918460018302840111602060020a8311171561050d57600080fd5b9193509150600160a060020a03813581169160208101359160408201351515916060013516611384565b6101cf6004803603602081101561054d57600080fd5b5035600160a060020a0316611525565b61021c611677565b6102746004803603602081101561057b57600080fd5b5035611686565b6101cf6004803603604081101561059857600080fd5b5080359060200135611698565b60ff9081166000908152600760205260409020541690565b60005460a060020a900460ff16156105d457600080fd5b6000838152600560205260408120546105f490849063ffffffff61176e16565b6001546040805160e060020a6323b872dd028152336004820152306024820152604481018490529051929350600160a060020a03909116916323b872dd916064808201926020929091908290030181600087803b15801561065457600080fd5b505af1158015610668573d6000803e3d6000fd5b505050506040513d602081101561067e57600080fd5b505161068957600080fd5b60035460008581526005602052604080822054815160e560020a6304beb95f028152600160a060020a0387811660048301526024820192909252604481018890526064810189905291519316926397d72be09260848084019391929182900301818387803b1580156106fa57600080fd5b505af115801561070e573d6000803e3d6000fd5b505060408051338152600160a060020a03861660208201528082018890526060810187905290517f62a35ca2927f9e65174b34ac5f6cdf575a908436b7b7a8d277c4441dc5bdc20b9350908190036080019150a150505050565b600854600160a060020a0316331461077f57600080fd5b600681905561078c611805565b6040805182815290517ff9aed9ae30ea401e16b1e0b0b3f113790b9263da6d646a31bf444b8812337ada9181900360200190a150565b600054604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a0316331461087c5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610841578181015183820152602001610829565b50505050905090810190601f16801561086e5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50600081905080600160a060020a0316637a2f130d6040518163ffffffff1660e060020a028152600401600060405180830381600087803b1580156108c057600080fd5b505af11580156108d4573d6000803e3d6000fd5b505050505050565b600254600160a060020a031681565b60005460a060020a900460ff161561090257600080fd5b600061091060006001611932565b6002546040805160e060020a632526c93302815260048101879052600160a060020a038681166024830152604482018590529151939450911691632526c9339160648082019260009290919082900301818387803b15801561097157600080fd5b505af1158015610985573d6000803e3d6000fd5b50505050505050565b600354600160a060020a031681565b60065481565b600054604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a03163314610a205760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610841578181015183820152602001610829565b5060088054600160a060020a038316600160a060020a03199091168117909155604080516020810192909252808252601282820152607060020a71617574686f72697a656445786368616e676502606083015251600080516020611d6a8339815191529181900360800190a150565b600054604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a03163314610b0c5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610841578181015183820152602001610829565b5060005460a060020a900460ff16610b2357600080fd5b6000805460a060020a60ff02191681556040517f7805862f689e2f13df9f062ff482ad3ad112aca9e0847911ed832e158c525b339190a1565b600054604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a03163314610bd95760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610841578181015183820152602001610829565b5080828486880101010160ff16606414610bf257600080fd5b60076020908152600080516020611e0a833981519152805460ff80891660ff199283168117909355600080516020611dca83398151915280548983169084168117909155600080516020611dea83398151915280548984169085168117909155600080516020611d8a833981519152805489851690861681179091556004600052600080516020611daa83398151915280549489169490951684179094556040805195865295850191909152838501526060830191909152608082015290517f24f15f956103bdaece452475d6b89351ed807e7f772bfa25d0a702d0aef717359181900360a00190a15050505050565b600154600160a060020a031681565b600a54600160a060020a031681565b60005460a060020a900460ff1681565b600054604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a03163314610d8d5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610841578181015183820152602001610829565b50600a8054600160a060020a038316600160a060020a03199091168117909155604080516020810192909252808252600e82820152609260020a6d185c9a585b9959541c9bda9958dd02606083015251600080516020611d6a8339815191529181900360800190a150565b600954600160a060020a031681565b600360009054906101000a9004600160a060020a0316600160a060020a031663f153fcd36040518163ffffffff1660e060020a028152600401602060405180830381600087803b158015610e5a57600080fd5b505af1158015610e6e573d6000803e3d6000fd5b505050506040513d6020811015610e8457600080fd5b5051600160a060020a0316301415610e9b57600080fd5b600360009054906101000a9004600160a060020a0316600160a060020a031663f153fcd36040518163ffffffff1660e060020a028152600401602060405180830381600087803b158015610eee57600080fd5b505af1158015610f02573d6000803e3d6000fd5b505050506040513d6020811015610f1857600080fd5b5051600160a060020a03163314610f2e57600080fd5b6001546003546040805160e060020a63f153fcd30281529051600160a060020a039384169363a9059cbb93169163f153fcd39160048083019260209291908290030181600087803b158015610f8257600080fd5b505af1158015610f96573d6000803e3d6000fd5b505050506040513d6020811015610fac57600080fd5b50516001546040805160e060020a6370a082310281523060048201529051600160a060020a03909216916370a0823191602480820192602092909190829003018186803b158015610ffc57600080fd5b505afa158015611010573d6000803e3d6000fd5b505050506040513d602081101561102657600080fd5b50516040805160e060020a63ffffffff8616028152600160a060020a03909316600484015260248301919091525160448083019260209291908290030181600087803b15801561107557600080fd5b505af1158015611089573d6000803e3d6000fd5b505050506040513d602081101561109f57600080fd5b5050565b60005b92915050565b600054604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a031633146111295760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610841578181015183820152602001610829565b5060005460a060020a900460ff161561114157600080fd5b6000805460a060020a60ff02191660a060020a1781556040517f6985a02210a168e66602d3235cb6db0e70f92b3ba4d376a33c0f3d9434bff6259190a1565b600054604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a031633146111fd5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610841578181015183820152602001610829565b5060098054600160a060020a038316600160a060020a03199091168117909155604080516020810192909252808252600d82820152609860020a6c70726f746f636f6c496e66726102606083015251600080516020611d6a8339815191529181900360800190a150565b600054600160a060020a031681565b60009081526004602052604090205490565b60005460a060020a900460ff161561129f57600080fd5b60025460405160e060020a63e261ed7702815260048101888152602482018890528615156044830152336064830181905260a06084840190815260a48401869052600094600160a060020a03169363e261ed77938c938c938c9391928b928b929060c401848480828437600081840152601f19601f820116905080830192505050975050505050505050602060405180830381600087803b15801561134357600080fd5b505af1158015611357573d6000803e3d6000fd5b505050506040513d602081101561136d57600080fd5b505190506109858482611a05565b60019392505050565b60005460a060020a900460ff161561139b57600080fd5b6002546040805160e260020a633036004b028152600481018b90529051600160a060020a039092169163c0d8012c91602480820192602092909190829003018186803b1580156113ea57600080fd5b505afa1580156113fe573d6000803e3d6000fd5b505050506040513d602081101561141457600080fd5b50516114245761142488336108eb565b60025460405160e160020a6376023685028152600481018a8152602482018a9052600160a060020a0387811660648401526084830187905285151560a48401523360c4840181905260e06044850190815260e485018b9052600095929092169363ec046d0a938e938e938e938e938e938e938e939092919061010401888880828437600081840152601f19601f8201169050808301925050509950505050505050505050602060405180830381600087803b1580156114e257600080fd5b505af11580156114f6573d6000803e3d6000fd5b505050506040513d602081101561150c57600080fd5b5051905061151a8282611b78565b505050505050505050565b600054604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a031633146115a25760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610841578181015183820152602001610829565b50604080518082019091526006815260d160020a6518189c181819026020820152600160a060020a03821661161b5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610841578181015183820152602001610829565b5060008054604051600160a060020a03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a360008054600160a060020a031916600160a060020a0392909216919091179055565b600854600160a060020a031681565b60009081526005602052604090205490565b600054604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a031633146117155760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610841578181015183820152602001610829565b50600082815260046020526040902081905561172f611805565b604080518381526020810183905281517f71b1f750acedc2820fab40f6e63fafee8132dd4748daa2e27a2d7471b3836fdc929181900390910190a15050565b60008261177d575060006110a6565b508181028183828161178b57fe5b041460405180604001604052806006815260200160d060020a6530303830303102815250906117fe5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610841578181015183820152602001610829565b5092915050565b600654600080526004602052600080516020611d4a8339815191525460649102101561183057600080fd5b60065460016000526004602052600080516020611d2a8339815191525460649102101561185c57600080fd5b60065460026000526004602052600080516020611e2a8339815191525460649102101561188857600080fd5b600654600080516020611d4a8339815191525481027f05b8ccbb9d4d8fb16ea74ce3c29a41f1b461fbdaff4714a0d9a8eb05499746bc55600080516020611d2a8339815191525481027f1471eb6eb2c5e789fc3de43f8ce62938c7d1836ec861730447e2ada8fd81017b556002600052600080516020611e2a833981519152546005602052027f89832631fb3c3307a103ba2c84ab569c64d6182a18893dcd163f0f1c2090733a55565b6003546040805160e060020a63d60b1e19028152336004820152602481018590526044810184905290516000928392600160a060020a039091169163d60b1e199160648082019260209290919082900301818787803b15801561199457600080fd5b505af11580156119a8573d6000803e3d6000fd5b505050506040513d60208110156119be57600080fd5b5051604080518681526020810186905281519293507f58cdf94a6ca56387bf662b90bd43503d0412c7c4a5b33584cc2e6c3834ac6130929081900390910190a19392505050565b60015460026000526007602052600080516020611dea83398151915254600160a060020a039091169063a9059cbb90849060ff1660648504026040518363ffffffff1660e060020a0281526004018083600160a060020a0316600160a060020a0316815260200182815260200192505050602060405180830381600087803b158015611a9057600080fd5b505af1158015611aa4573d6000803e3d6000fd5b505050506040513d6020811015611aba57600080fd5b505060015460046000526007602052600080516020611daa83398151915254600160a060020a039091169063a9059cbb90339060ff166064855b04026040518363ffffffff1660e060020a0281526004018083600160a060020a0316600160a060020a0316815260200182815260200192505050602060405180830381600087803b158015611b4857600080fd5b505af1158015611b5c573d6000803e3d6000fd5b505050506040513d6020811015611b7257600080fd5b50505050565b600154600954600080526007602052600080516020611e0a83398151915254600160a060020a039283169263a9059cbb92169060ff1660648504026040518363ffffffff1660e060020a0281526004018083600160a060020a0316600160a060020a0316815260200182815260200192505050602060405180830381600087803b158015611c0557600080fd5b505af1158015611c19573d6000803e3d6000fd5b505050506040513d6020811015611c2f57600080fd5b5050600154600a5460036000526007602052600080516020611d8a83398151915254600160a060020a039283169263a9059cbb92169060ff1660648504026040518363ffffffff1660e060020a0281526004018083600160a060020a0316600160a060020a0316815260200182815260200192505050602060405180830381600087803b158015611cbf57600080fd5b505af1158015611cd3573d6000803e3d6000fd5b505050506040513d6020811015611ce957600080fd5b5050600180546000919091526007602052600080516020611dca83398151915254600160a060020a039091169063a9059cbb90849060ff16606485611af456feabd6e7cb50984ff9c2f3e18a2660c3353dadf4e3291deeb275dae2cd1e44fe0517ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ecb5fa77bd6bc3d862c73fa2474bfb96a0f76d38b622c54ff2a0188be82fb965113be6fd20d5acfde5b873b48692cd31f4d3c7e8ee8a813af4696af8859e5ca6c6b805995a7ec585a251200611a61d179cfd7fb105e1ab17dc415a7336783786f7b39221ace053465ec3453ce2b36430bd138b997ecea25c1043da0c366812b828b7c774451310d1be4108bc180d1b52823cb0ee0274a6c0081bcaf94f115fb96d6d5257204ebe7d88fd91ae87941cb2dd9d8062b64ae5a2bd2d28ec40b9fbf6df91da3fd0782e51c6b3986e9e672fd566868e71f3dbc2d6c2cd6fbb3e361af2a7a165627a7a72305820dd5aefded396e72c5feb870449979ca24619e1a1de0f52445876168edc16a8710029