ETH Price: $1,971.95 (-1.96%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Purchase For134561632021-10-20 18:17:451593 days ago1634753865IN
0x70FF3c8A...a9AF591Ad
0 ETH0.0023422367.5578426
Purchase For134330652021-10-17 3:32:481597 days ago1634441568IN
0x70FF3c8A...a9AF591Ad
0 ETH0.0017253749.80026395
Purchase For134330652021-10-17 3:32:481597 days ago1634441568IN
0x70FF3c8A...a9AF591Ad
0 ETH0.0017306549.95255163
Purchase For134325792021-10-17 1:38:561597 days ago1634434736IN
0x70FF3c8A...a9AF591Ad
0 ETH0.001746850.40125752
Purchase For134325792021-10-17 1:38:561597 days ago1634434736IN
0x70FF3c8A...a9AF591Ad
0 ETH0.0027207278.55655552
Purchase For134325792021-10-17 1:38:561597 days ago1634434736IN
0x70FF3c8A...a9AF591Ad
0 ETH0.001746250.40125752
Purchase For134325792021-10-17 1:38:561597 days ago1634434736IN
0x70FF3c8A...a9AF591Ad
0 ETH0.0017571150.73385058
Purchase For134096242021-10-13 11:01:301600 days ago1634122890IN
0x70FF3c8A...a9AF591Ad
0 ETH0.0023438467.60445534
Purchase For134096242021-10-13 11:01:301600 days ago1634122890IN
0x70FF3c8A...a9AF591Ad
0 ETH0.0026064475.17864548
Purchase For134058142021-10-12 20:28:581601 days ago1634070538IN
0x70FF3c8A...a9AF591Ad
0 ETH0.0017723351.12007128
Purchase For134043312021-10-12 15:02:331601 days ago1634050953IN
0x70FF3c8A...a9AF591Ad
0 ETH0.0026478176.42479198
Purchase For134043262021-10-12 15:01:261601 days ago1634050886IN
0x70FF3c8A...a9AF591Ad
0 ETH0.0084177678.39524235
Purchase For134043222021-10-12 15:00:541601 days ago1634050854IN
0x70FF3c8A...a9AF591Ad
0 ETH0.0099388876.88109745
Purchase For134043192021-10-12 14:59:461601 days ago1634050786IN
0x70FF3c8A...a9AF591Ad
0 ETH0.0064363857.37753962
Purchase For134042932021-10-12 14:55:531601 days ago1634050553IN
0x70FF3c8A...a9AF591Ad
0 ETH0.0093416383.27659169
Purchase For134042872021-10-12 14:54:031601 days ago1634050443IN
0x70FF3c8A...a9AF591Ad
0 ETH0.008802578.47049935
Purchase For134042702021-10-12 14:49:581601 days ago1634050198IN
0x70FF3c8A...a9AF591Ad
0 ETH0.006611258.93597488
Purchase For134042692021-10-12 14:49:521601 days ago1634050192IN
0x70FF3c8A...a9AF591Ad
0 ETH0.0033901597.74979285
Purchase For134042692021-10-12 14:49:521601 days ago1634050192IN
0x70FF3c8A...a9AF591Ad
0 ETH0.002429970.06239155
Purchase For134042692021-10-12 14:49:521601 days ago1634050192IN
0x70FF3c8A...a9AF591Ad
0 ETH0.0023626668.12379916
Purchase For134042692021-10-12 14:49:521601 days ago1634050192IN
0x70FF3c8A...a9AF591Ad
0 ETH0.0021877663.08069996
Purchase For134042692021-10-12 14:49:521601 days ago1634050192IN
0x70FF3c8A...a9AF591Ad
0 ETH0.002096460.44647881
Purchase For134042692021-10-12 14:49:521601 days ago1634050192IN
0x70FF3c8A...a9AF591Ad
0 ETH0.0025318773.0024964
Purchase For134042692021-10-12 14:49:521601 days ago1634050192IN
0x70FF3c8A...a9AF591Ad
0 ETH0.0027812880.19404168
Purchase For134042692021-10-12 14:49:521601 days ago1634050192IN
0x70FF3c8A...a9AF591Ad
0 ETH0.0021559562.16340421
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
TokenLaunchpadVouchersSale

Compiler Version
v0.7.6+commit.7338295f

Optimization Enabled:
Yes with 2000 runs

Other Settings:
default evmVersion, MIT license
/**
 *Submitted for verification at Etherscan.io on 2021-10-12
*/

// Sources flattened with hardhat v2.6.5 https://hardhat.org

// File @animoca/ethereum-contracts-core-1.1.2/contracts/utils/types/AddressIsContract.sol@v1.1.2

// SPDX-License-Identifier: MIT

// Partially derived from OpenZeppelin:
// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/406c83649bd6169fc1b578e08506d78f0873b276/contracts/utils/Address.sol

pragma solidity >=0.7.6 <0.8.0;

/**
 * @dev Upgrades the address type to check if it is a contract.
 */
library AddressIsContract {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        assembly {
            size := extcodesize(account)
        }
        return size > 0;
    }
}


// File @animoca/ethereum-contracts-core-1.1.2/contracts/utils/ERC20Wrapper.sol@v1.1.2

pragma solidity >=0.7.6 <0.8.0;

/**
 * @title ERC20Wrapper
 * Wraps ERC20 functions to support non-standard implementations which do not return a bool value.
 * Calls to the wrapped functions revert only if they throw or if they return false.
 */
library ERC20Wrapper {
    using AddressIsContract for address;

    function wrappedTransfer(
        IWrappedERC20 token,
        address to,
        uint256 value
    ) internal {
        _callWithOptionalReturnData(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function wrappedTransferFrom(
        IWrappedERC20 token,
        address from,
        address to,
        uint256 value
    ) internal {
        _callWithOptionalReturnData(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    function wrappedApprove(
        IWrappedERC20 token,
        address spender,
        uint256 value
    ) internal {
        _callWithOptionalReturnData(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function _callWithOptionalReturnData(IWrappedERC20 token, bytes memory callData) internal {
        address target = address(token);
        require(target.isContract(), "ERC20Wrapper: non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory data) = target.call(callData);
        if (success) {
            if (data.length != 0) {
                require(abi.decode(data, (bool)), "ERC20Wrapper: operation failed");
            }
        } else {
            // revert using a standard revert message
            if (data.length == 0) {
                revert("ERC20Wrapper: operation failed");
            }

            // revert using the revert message coming from the call
            assembly {
                let size := mload(data)
                revert(add(32, data), size)
            }
        }
    }
}

interface IWrappedERC20 {
    function transfer(address to, uint256 value) external returns (bool);

    function transferFrom(
        address from,
        address to,
        uint256 value
    ) external returns (bool);

    function approve(address spender, uint256 value) external returns (bool);
}


// File @animoca/ethereum-contracts-core-1.1.2/contracts/algo/EnumMap.sol@v1.1.2

// Derived from OpenZeppelin:
// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/406c83649bd6169fc1b578e08506d78f0873b276/contracts/utils/structs/EnumerableMap.sol

pragma solidity >=0.7.6 <0.8.0;

/**
 * @dev Library for managing an enumerable variant of Solidity's
 * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`]
 * type.
 *
 * Maps have the following properties:
 *
 * - Entries are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Entries are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumMap for EnumMap.Map;
 *
 *     // Declare a set state variable
 *     EnumMap.Map private myMap;
 * }
 * ```
 */
library EnumMap {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Map type with
    // bytes32 keys and values.
    // This means that we can only create new EnumMaps for types that fit
    // in bytes32.

    struct MapEntry {
        bytes32 key;
        bytes32 value;
    }

    struct Map {
        // Storage of map keys and values
        MapEntry[] entries;
        // Position of the entry defined by a key in the `entries` array, plus 1
        // because index 0 means a key is not in the map.
        mapping(bytes32 => uint256) indexes;
    }

    /**
     * @dev Adds a key-value pair to a map, or updates the value for an existing
     * key. O(1).
     *
     * Returns true if the key was added to the map, that is if it was not
     * already present.
     */
    function set(
        Map storage map,
        bytes32 key,
        bytes32 value
    ) internal returns (bool) {
        // We read and store the key's index to prevent multiple reads from the same storage slot
        uint256 keyIndex = map.indexes[key];

        if (keyIndex == 0) {
            // Equivalent to !contains(map, key)
            map.entries.push(MapEntry({key: key, value: value}));
            // The entry is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            map.indexes[key] = map.entries.length;
            return true;
        } else {
            map.entries[keyIndex - 1].value = value;
            return false;
        }
    }

    /**
     * @dev Removes a key-value pair from a map. O(1).
     *
     * Returns true if the key was removed from the map, that is if it was present.
     */
    function remove(Map storage map, bytes32 key) internal returns (bool) {
        // We read and store the key's index to prevent multiple reads from the same storage slot
        uint256 keyIndex = map.indexes[key];

        if (keyIndex != 0) {
            // Equivalent to contains(map, key)
            // To delete a key-value pair from the entries array in O(1), we swap the entry to delete with the last one
            // in the array, and then remove the last entry (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = keyIndex - 1;
            uint256 lastIndex = map.entries.length - 1;

            // When the entry to delete is the last one, the swap operation is unnecessary. However, since this occurs
            // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.

            MapEntry storage lastEntry = map.entries[lastIndex];

            // Move the last entry to the index where the entry to delete is
            map.entries[toDeleteIndex] = lastEntry;
            // Update the index for the moved entry
            map.indexes[lastEntry.key] = toDeleteIndex + 1; // All indexes are 1-based

            // Delete the slot where the moved entry was stored
            map.entries.pop();

            // Delete the index for the deleted slot
            delete map.indexes[key];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the key is in the map. O(1).
     */
    function contains(Map storage map, bytes32 key) internal view returns (bool) {
        return map.indexes[key] != 0;
    }

    /**
     * @dev Returns the number of key-value pairs in the map. O(1).
     */
    function length(Map storage map) internal view returns (uint256) {
        return map.entries.length;
    }

    /**
     * @dev Returns the key-value pair stored at position `index` in the map. O(1).
     *
     * Note that there are no guarantees on the ordering of entries inside the
     * array, and it may change when more entries are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Map storage map, uint256 index) internal view returns (bytes32, bytes32) {
        require(map.entries.length > index, "EnumMap: index out of bounds");

        MapEntry storage entry = map.entries[index];
        return (entry.key, entry.value);
    }

    /**
     * @dev Returns the value associated with `key`.  O(1).
     *
     * Requirements:
     *
     * - `key` must be in the map.
     */
    function get(Map storage map, bytes32 key) internal view returns (bytes32) {
        uint256 keyIndex = map.indexes[key];
        require(keyIndex != 0, "EnumMap: nonexistent key"); // Equivalent to contains(map, key)
        return map.entries[keyIndex - 1].value; // All indexes are 1-based
    }
}


// File @animoca/ethereum-contracts-core-1.1.2/contracts/algo/EnumSet.sol@v1.1.2

// Derived from OpenZeppelin:
// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/406c83649bd6169fc1b578e08506d78f0873b276/contracts/utils/structs/EnumerableSet.sol

pragma solidity >=0.7.6 <0.8.0;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumSet for EnumSet.Set;
 *
 *     // Declare a set state variable
 *     EnumSet.Set private mySet;
 * }
 * ```
 */
library EnumSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] values;
        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping(bytes32 => uint256) indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Set storage set, bytes32 value) internal returns (bool) {
        if (!contains(set, value)) {
            set.values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set.indexes[value] = set.values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Set storage set, bytes32 value) internal returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set.indexes[value];

        if (valueIndex != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set.values.length - 1;

            // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs
            // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.

            bytes32 lastvalue = set.values[lastIndex];

            // Move the last value to the index where the value to delete is
            set.values[toDeleteIndex] = lastvalue;
            // Update the index for the moved value
            set.indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based

            // Delete the slot where the moved value was stored
            set.values.pop();

            // Delete the index for the deleted slot
            delete set.indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Set storage set, bytes32 value) internal view returns (bool) {
        return set.indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function length(Set storage set) internal view returns (uint256) {
        return set.values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Set storage set, uint256 index) internal view returns (bytes32) {
        require(set.values.length > index, "EnumSet: index out of bounds");
        return set.values[index];
    }
}


// File @animoca/ethereum-contracts-core-1.1.2/contracts/metatx/ManagedIdentity.sol@v1.1.2

pragma solidity >=0.7.6 <0.8.0;

/*
 * Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner.
 */
abstract contract ManagedIdentity {
    function _msgSender() internal view virtual returns (address payable) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes memory) {
        return msg.data;
    }
}


// File @animoca/ethereum-contracts-core-1.1.2/contracts/access/IERC173.sol@v1.1.2

pragma solidity >=0.7.6 <0.8.0;

/**
 * @title ERC-173 Contract Ownership Standard
 * Note: the ERC-165 identifier for this interface is 0x7f5828d0
 */
interface IERC173 {
    /**
     * Event emited when ownership of a contract changes.
     * @param previousOwner the previous owner.
     * @param newOwner the new owner.
     */
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * Get the address of the owner
     * @return The address of the owner.
     */
    function owner() external view returns (address);

    /**
     * Set the address of the new owner of the contract
     * Set newOwner to address(0) to renounce any ownership.
     * @dev Emits an {OwnershipTransferred} event.
     * @param newOwner The address of the new owner of the contract. Using the zero address means renouncing ownership.
     */
    function transferOwnership(address newOwner) external;
}


// File @animoca/ethereum-contracts-core-1.1.2/contracts/access/Ownable.sol@v1.1.2

pragma solidity >=0.7.6 <0.8.0;


/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is ManagedIdentity, IERC173 {
    address internal _owner;

    /**
     * Initializes the contract, setting the deployer as the initial owner.
     * @dev Emits an {IERC173-OwnershipTransferred(address,address)} event.
     */
    constructor(address owner_) {
        _owner = owner_;
        emit OwnershipTransferred(address(0), owner_);
    }

    /**
     * Gets the address of the current contract owner.
     */
    function owner() public view virtual override returns (address) {
        return _owner;
    }

    /**
     * See {IERC173-transferOwnership(address)}
     * @dev Reverts if the sender is not the current contract owner.
     * @param newOwner the address of the new owner. Use the zero address to renounce the ownership.
     */
    function transferOwnership(address newOwner) public virtual override {
        _requireOwnership(_msgSender());
        _owner = newOwner;
        emit OwnershipTransferred(_owner, newOwner);
    }

    /**
     * @dev Reverts if `account` is not the contract owner.
     * @param account the account to test.
     */
    function _requireOwnership(address account) internal virtual {
        require(account == this.owner(), "Ownable: not the owner");
    }
}


// File @animoca/ethereum-contracts-core-1.1.2/contracts/payment/PayoutWallet.sol@v1.1.2

pragma solidity >=0.7.6 <0.8.0;


/**
    @title PayoutWallet
    @dev adds support for a payout wallet
    Note: .
 */
abstract contract PayoutWallet is ManagedIdentity, Ownable {
    event PayoutWalletSet(address payoutWallet_);

    address payable public payoutWallet;

    constructor(address owner, address payable payoutWallet_) Ownable(owner) {
        require(payoutWallet_ != address(0), "Payout: zero address");
        payoutWallet = payoutWallet_;
        emit PayoutWalletSet(payoutWallet_);
    }

    function setPayoutWallet(address payable payoutWallet_) public {
        _requireOwnership(_msgSender());
        require(payoutWallet_ != address(0), "Payout: zero address");
        payoutWallet = payoutWallet_;
        emit PayoutWalletSet(payoutWallet);
    }
}


// File @animoca/ethereum-contracts-core-1.1.2/contracts/lifecycle/Startable.sol@v1.1.2

pragma solidity >=0.7.6 <0.8.0;

/**
 * Contract module which allows derived contracts to implement a mechanism for
 * activating, or 'starting', a contract.
 *
 * This module is used through inheritance. It will make available the modifiers
 * `whenNotStarted` and `whenStarted`, which can be applied to the functions of
 * your contract. Those functions will only be 'startable' once the modifiers
 * are put in place.
 */
abstract contract Startable is ManagedIdentity {
    event Started(address account);

    uint256 private _startedAt;

    /**
     * Modifier to make a function callable only when the contract has not started.
     */
    modifier whenNotStarted() {
        require(_startedAt == 0, "Startable: started");
        _;
    }

    /**
     * Modifier to make a function callable only when the contract has started.
     */
    modifier whenStarted() {
        require(_startedAt != 0, "Startable: not started");
        _;
    }

    /**
     * Constructor.
     */
    constructor() {}

    /**
     * Returns the timestamp when the contract entered the started state.
     * @return The timestamp when the contract entered the started state.
     */
    function startedAt() public view returns (uint256) {
        return _startedAt;
    }

    /**
     * Triggers the started state.
     * @dev Emits the Started event when the function is successfully called.
     */
    function _start() internal virtual whenNotStarted {
        _startedAt = block.timestamp;
        emit Started(_msgSender());
    }
}


// File @animoca/ethereum-contracts-core-1.1.2/contracts/lifecycle/Pausable.sol@v1.1.2

pragma solidity >=0.7.6 <0.8.0;

/**
 * @dev Contract which allows children to implement pausability.
 */
abstract contract Pausable is ManagedIdentity {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool public paused;

    constructor(bool paused_) {
        paused = paused_;
    }

    function _requireNotPaused() internal view {
        require(!paused, "Pausable: paused");
    }

    function _requirePaused() internal view {
        require(paused, "Pausable: not paused");
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual {
        _requireNotPaused();
        paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual {
        _requirePaused();
        paused = false;
        emit Unpaused(_msgSender());
    }
}


// File @openzeppelin/contracts/math/SafeMath.sol@v3.4.0

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        uint256 c = a + b;
        if (c < a) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b > a) return (false, 0);
        return (true, a - b);
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, 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-contracts/pull/522
        if (a == 0) return (true, 0);
        uint256 c = a * b;
        if (c / a != b) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a / b);
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a % b);
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) return 0;
        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");
        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: division by zero");
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: modulo by zero");
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        return a - b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryDiv}.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a % b;
    }
}


// File @animoca/ethereum-contracts-sale-2.0.0/contracts/sale/interfaces/ISale.sol@v2.0.0

pragma solidity >=0.7.6 <0.8.0;

/**
 * @title ISale
 *
 * An interface for a contract which allows merchants to display products and customers to purchase them.
 *
 *  Products, designated as SKUs, are represented by bytes32 identifiers so that an identifier can carry an
 *  explicit name under the form of a fixed-length string. Each SKU can be priced via up to several payment
 *  tokens which can be ETH and/or ERC20(s). ETH token is represented by the magic value TOKEN_ETH, which means
 *  this value can be used as the 'token' argument of the purchase-related functions to indicate ETH payment.
 *
 *  The total available supply for a SKU is fixed at its creation. The magic value SUPPLY_UNLIMITED is used
 *  to represent a SKU with an infinite, never-decreasing supply. An optional purchase notifications receiver
 *  contract address can be set for a SKU at its creation: if the value is different from the zero address,
 *  the function `onPurchaseNotificationReceived` will be called on this address upon every purchase of the SKU.
 *
 *  This interface is designed to be consistent while managing a variety of implementation scenarios. It is
 *  also intended to be developer-friendly: all vital information is consistently deductible from the events
 *  (backend-oriented), as well as retrievable through calls to public functions (frontend-oriented).
 */
interface ISale {
    /**
     * Event emitted to notify about the magic values necessary for interfacing with this contract.
     * @param names An array of names for the magic values used by the contract.
     * @param values An array of values for the magic values used by the contract.
     */
    event MagicValues(bytes32[] names, bytes32[] values);

    /**
     * Event emitted to notify about the creation of a SKU.
     * @param sku The identifier of the created SKU.
     * @param totalSupply The initial total supply for sale.
     * @param maxQuantityPerPurchase The maximum allowed quantity for a single purchase.
     * @param notificationsReceiver If not the zero address, the address of a contract on which `onPurchaseNotificationReceived` will be called after
     *  each purchase. If this is the zero address, the call is not enabled.
     */
    event SkuCreation(bytes32 sku, uint256 totalSupply, uint256 maxQuantityPerPurchase, address notificationsReceiver);

    /**
     * Event emitted to notify about a change in the pricing of a SKU.
     * @dev `tokens` and `prices` arrays MUST have the same length.
     * @param sku The identifier of the updated SKU.
     * @param tokens An array of updated payment tokens. If empty, interpret as all payment tokens being disabled.
     * @param prices An array of updated prices for each of the payment tokens.
     *  Zero price values are used for payment tokens being disabled.
     */
    event SkuPricingUpdate(bytes32 indexed sku, address[] tokens, uint256[] prices);

    /**
     * Event emitted to notify about a purchase.
     * @param purchaser The initiater and buyer of the purchase.
     * @param recipient The recipient of the purchase.
     * @param token The token used as the currency for the payment.
     * @param sku The identifier of the purchased SKU.
     * @param quantity The purchased quantity.
     * @param userData Optional extra user input data.
     * @param totalPrice The amount of `token` paid.
     * @param extData Implementation-specific extra purchase data, such as
     *  details about discounts applied, conversion rates, purchase receipts, etc.
     */
    event Purchase(
        address indexed purchaser,
        address recipient,
        address indexed token,
        bytes32 indexed sku,
        uint256 quantity,
        bytes userData,
        uint256 totalPrice,
        bytes extData
    );

    /**
     * Returns the magic value used to represent the ETH payment token.
     * @dev MUST NOT be the zero address.
     * @return the magic value used to represent the ETH payment token.
     */
    // solhint-disable-next-line func-name-mixedcase
    function TOKEN_ETH() external pure returns (address);

    /**
     * Returns the magic value used to represent an infinite, never-decreasing SKU's supply.
     * @dev MUST NOT be zero.
     * @return the magic value used to represent an infinite, never-decreasing SKU's supply.
     */
    // solhint-disable-next-line func-name-mixedcase
    function SUPPLY_UNLIMITED() external pure returns (uint256);

    /**
     * Performs a purchase.
     * @dev Reverts if `recipient` is the zero address.
     * @dev Reverts if `token` is the address zero.
     * @dev Reverts if `quantity` is zero.
     * @dev Reverts if `quantity` is greater than the maximum purchase quantity.
     * @dev Reverts if `quantity` is greater than the remaining supply.
     * @dev Reverts if `sku` does not exist.
     * @dev Reverts if `sku` exists but does not have a price set for `token`.
     * @dev Emits the Purchase event.
     * @param recipient The recipient of the purchase.
     * @param token The token to use as the payment currency.
     * @param sku The identifier of the SKU to purchase.
     * @param quantity The quantity to purchase.
     * @param userData Optional extra user input data.
     */
    function purchaseFor(
        address payable recipient,
        address token,
        bytes32 sku,
        uint256 quantity,
        bytes calldata userData
    ) external payable;

    /**
     * Estimates the computed final total amount to pay for a purchase, including any potential discount.
     * @dev This function MUST compute the same price as `purchaseFor` would in identical conditions (same arguments, same point in time).
     * @dev If an implementer contract uses the `pricingData` field, it SHOULD document how to interpret the values.
     * @dev Reverts if `recipient` is the zero address.
     * @dev Reverts if `token` is the zero address.
     * @dev Reverts if `quantity` is zero.
     * @dev Reverts if `quantity` is greater than the maximum purchase quantity.
     * @dev Reverts if `quantity` is greater than the remaining supply.
     * @dev Reverts if `sku` does not exist.
     * @dev Reverts if `sku` exists but does not have a price set for `token`.
     * @param recipient The recipient of the purchase used to calculate the total price amount.
     * @param token The payment token used to calculate the total price amount.
     * @param sku The identifier of the SKU used to calculate the total price amount.
     * @param quantity The quantity used to calculate the total price amount.
     * @param userData Optional extra user input data.
     * @return totalPrice The computed total price to pay.
     * @return pricingData Implementation-specific extra pricing data, such as details about discounts applied.
     *  If not empty, the implementer MUST document how to interepret the values.
     */
    function estimatePurchase(
        address payable recipient,
        address token,
        bytes32 sku,
        uint256 quantity,
        bytes calldata userData
    ) external view returns (uint256 totalPrice, bytes32[] memory pricingData);

    /**
     * Returns the information relative to a SKU.
     * @dev WARNING: it is the responsibility of the implementer to ensure that the
     *  number of payment tokens is bounded, so that this function does not run out of gas.
     * @dev Reverts if `sku` does not exist.
     * @param sku The SKU identifier.
     * @return totalSupply The initial total supply for sale.
     * @return remainingSupply The remaining supply for sale.
     * @return maxQuantityPerPurchase The maximum allowed quantity for a single purchase.
     * @return notificationsReceiver The address of a contract on which to call the `onPurchaseNotificationReceived` function.
     * @return tokens The list of supported payment tokens.
     * @return prices The list of associated prices for each of the `tokens`.
     */
    function getSkuInfo(bytes32 sku)
        external
        view
        returns (
            uint256 totalSupply,
            uint256 remainingSupply,
            uint256 maxQuantityPerPurchase,
            address notificationsReceiver,
            address[] memory tokens,
            uint256[] memory prices
        );

    /**
     * Returns the list of created SKU identifiers.
     * @dev WARNING: it is the responsibility of the implementer to ensure that the
     *  number of SKUs is bounded, so that this function does not run out of gas.
     * @return skus the list of created SKU identifiers.
     */
    function getSkus() external view returns (bytes32[] memory skus);
}


// File @animoca/ethereum-contracts-sale-2.0.0/contracts/sale/interfaces/IPurchaseNotificationsReceiver.sol@v2.0.0

pragma solidity >=0.7.6 <0.8.0;

/**
 * @title IPurchaseNotificationsReceiver
 * Interface for any contract that wants to support purchase notifications from a Sale contract.
 */
interface IPurchaseNotificationsReceiver {
    /**
     * Handles the receipt of a purchase notification.
     * @dev This function MUST return the function selector, otherwise the caller will revert the transaction.
     *  The selector to be returned can be obtained as `this.onPurchaseNotificationReceived.selector`
     * @dev This function MAY throw.
     * @param purchaser The purchaser of the purchase.
     * @param recipient The recipient of the purchase.
     * @param token The token to use as the payment currency.
     * @param sku The identifier of the SKU to purchase.
     * @param quantity The quantity to purchase.
     * @param userData Optional extra user input data.
     * @param totalPrice The total price paid.
     * @param pricingData Implementation-specific extra pricing data, such as details about discounts applied.
     * @param paymentData Implementation-specific extra payment data, such as conversion rates.
     * @param deliveryData Implementation-specific extra delivery data, such as purchase receipts.
     * @return `bytes4(keccak256(
     *  "onPurchaseNotificationReceived(address,address,address,bytes32,uint256,bytes,uint256,bytes32[],bytes32[],bytes32[])"))`
     */
    function onPurchaseNotificationReceived(
        address purchaser,
        address recipient,
        address token,
        bytes32 sku,
        uint256 quantity,
        bytes calldata userData,
        uint256 totalPrice,
        bytes32[] calldata pricingData,
        bytes32[] calldata paymentData,
        bytes32[] calldata deliveryData
    ) external returns (bytes4);
}


// File @animoca/ethereum-contracts-sale-2.0.0/contracts/sale/abstract/PurchaseLifeCycles.sol@v2.0.0

pragma solidity >=0.7.6 <0.8.0;

/**
 * @title PurchaseLifeCycles
 * An abstract contract which define the life cycles for a purchase implementer.
 */
abstract contract PurchaseLifeCycles {
    /**
     * Wrapper for the purchase data passed as argument to the life cycle functions and down to their step functions.
     */
    struct PurchaseData {
        address payable purchaser;
        address payable recipient;
        address token;
        bytes32 sku;
        uint256 quantity;
        bytes userData;
        uint256 totalPrice;
        bytes32[] pricingData;
        bytes32[] paymentData;
        bytes32[] deliveryData;
    }

    /*                               Internal Life Cycle Functions                               */

    /**
     * `estimatePurchase` lifecycle.
     * @param purchase The purchase conditions.
     */
    function _estimatePurchase(PurchaseData memory purchase) internal view virtual returns (uint256 totalPrice, bytes32[] memory pricingData) {
        _validation(purchase);
        _pricing(purchase);

        totalPrice = purchase.totalPrice;
        pricingData = purchase.pricingData;
    }

    /**
     * `purchaseFor` lifecycle.
     * @param purchase The purchase conditions.
     */
    function _purchaseFor(PurchaseData memory purchase) internal virtual {
        _validation(purchase);
        _pricing(purchase);
        _payment(purchase);
        _delivery(purchase);
        _notification(purchase);
    }

    /*                            Internal Life Cycle Step Functions                             */

    /**
     * Lifecycle step which validates the purchase pre-conditions.
     * @dev Responsibilities:
     *  - Ensure that the purchase pre-conditions are met and revert if not.
     * @param purchase The purchase conditions.
     */
    function _validation(PurchaseData memory purchase) internal view virtual;

    /**
     * Lifecycle step which computes the purchase price.
     * @dev Responsibilities:
     *  - Computes the pricing formula, including any discount logic and price conversion;
     *  - Set the value of `purchase.totalPrice`;
     *  - Add any relevant extra data related to pricing in `purchase.pricingData` and document how to interpret it.
     * @param purchase The purchase conditions.
     */
    function _pricing(PurchaseData memory purchase) internal view virtual;

    /**
     * Lifecycle step which manages the transfer of funds from the purchaser.
     * @dev Responsibilities:
     *  - Ensure the payment reaches destination in the expected output token;
     *  - Handle any token swap logic;
     *  - Add any relevant extra data related to payment in `purchase.paymentData` and document how to interpret it.
     * @param purchase The purchase conditions.
     */
    function _payment(PurchaseData memory purchase) internal virtual;

    /**
     * Lifecycle step which delivers the purchased SKUs to the recipient.
     * @dev Responsibilities:
     *  - Ensure the product is delivered to the recipient, if that is the contract's responsibility.
     *  - Handle any internal logic related to the delivery, including the remaining supply update;
     *  - Add any relevant extra data related to delivery in `purchase.deliveryData` and document how to interpret it.
     * @param purchase The purchase conditions.
     */
    function _delivery(PurchaseData memory purchase) internal virtual;

    /**
     * Lifecycle step which notifies of the purchase.
     * @dev Responsibilities:
     *  - Manage after-purchase event(s) emission.
     *  - Handle calls to the notifications receiver contract's `onPurchaseNotificationReceived` function, if applicable.
     * @param purchase The purchase conditions.
     */
    function _notification(PurchaseData memory purchase) internal virtual;
}


// File @animoca/ethereum-contracts-sale-2.0.0/contracts/sale/abstract/Sale.sol@v2.0.0

pragma solidity >=0.7.6 <0.8.0;










/**
 * @title Sale
 * An abstract base sale contract with a minimal implementation of ISale and administration functions.
 *  A minimal implementation of the `_validation`, `_delivery` and `notification` life cycle step functions
 *  are provided, but the inheriting contract must implement `_pricing` and `_payment`.
 */
abstract contract Sale is PurchaseLifeCycles, ISale, PayoutWallet, Startable, Pausable {
    using AddressIsContract for address;
    using SafeMath for uint256;
    using EnumSet for EnumSet.Set;
    using EnumMap for EnumMap.Map;

    struct SkuInfo {
        uint256 totalSupply;
        uint256 remainingSupply;
        uint256 maxQuantityPerPurchase;
        address notificationsReceiver;
        EnumMap.Map prices;
    }

    address public constant override TOKEN_ETH = address(0x00eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee);
    uint256 public constant override SUPPLY_UNLIMITED = type(uint256).max;

    EnumSet.Set internal _skus;
    mapping(bytes32 => SkuInfo) internal _skuInfos;

    uint256 internal immutable _skusCapacity;
    uint256 internal immutable _tokensPerSkuCapacity;

    /**
     * Constructor.
     * @dev Emits the `MagicValues` event.
     * @dev Emits the `Paused` event.
     * @param payoutWallet_ the payout wallet.
     * @param skusCapacity the cap for the number of managed SKUs.
     * @param tokensPerSkuCapacity the cap for the number of tokens managed per SKU.
     */
    constructor(
        address payable payoutWallet_,
        uint256 skusCapacity,
        uint256 tokensPerSkuCapacity
    ) PayoutWallet(msg.sender, payoutWallet_) Pausable(true) {
        _skusCapacity = skusCapacity;
        _tokensPerSkuCapacity = tokensPerSkuCapacity;
        bytes32[] memory names = new bytes32[](2);
        bytes32[] memory values = new bytes32[](2);
        (names[0], values[0]) = ("TOKEN_ETH", bytes32(uint256(TOKEN_ETH)));
        (names[1], values[1]) = ("SUPPLY_UNLIMITED", bytes32(uint256(SUPPLY_UNLIMITED)));
        emit MagicValues(names, values);
    }

    /*                                   Public Admin Functions                                  */

    /**
     * Actvates, or 'starts', the contract.
     * @dev Emits the `Started` event.
     * @dev Emits the `Unpaused` event.
     * @dev Reverts if called by any other than the contract owner.
     * @dev Reverts if the contract has already been started.
     * @dev Reverts if the contract is not paused.
     */
    function start() public virtual {
        _requireOwnership(_msgSender());
        _start();
        _unpause();
    }

    /**
     * Pauses the contract.
     * @dev Emits the `Paused` event.
     * @dev Reverts if called by any other than the contract owner.
     * @dev Reverts if the contract has not been started yet.
     * @dev Reverts if the contract is already paused.
     */
    function pause() public virtual whenStarted {
        _requireOwnership(_msgSender());
        _pause();
    }

    /**
     * Resumes the contract.
     * @dev Emits the `Unpaused` event.
     * @dev Reverts if called by any other than the contract owner.
     * @dev Reverts if the contract has not been started yet.
     * @dev Reverts if the contract is not paused.
     */
    function unpause() public virtual whenStarted {
        _requireOwnership(_msgSender());
        _unpause();
    }

    /**
     * Sets the token prices for the specified product SKU.
     * @dev Reverts if called by any other than the contract owner.
     * @dev Reverts if `tokens` and `prices` have different lengths.
     * @dev Reverts if `sku` does not exist.
     * @dev Reverts if one of the `tokens` is the zero address.
     * @dev Reverts if the update results in too many tokens for the SKU.
     * @dev Emits the `SkuPricingUpdate` event.
     * @param sku The identifier of the SKU.
     * @param tokens The list of payment tokens to update.
     *  If empty, disable all the existing payment tokens.
     * @param prices The list of prices to apply for each payment token.
     *  Zero price values are used to disable a payment token.
     */
    function updateSkuPricing(
        bytes32 sku,
        address[] memory tokens,
        uint256[] memory prices
    ) public virtual {
        _requireOwnership(_msgSender());
        uint256 length = tokens.length;
        require(length == prices.length, "Sale: inconsistent arrays");
        SkuInfo storage skuInfo = _skuInfos[sku];
        require(skuInfo.totalSupply != 0, "Sale: non-existent sku");

        EnumMap.Map storage tokenPrices = skuInfo.prices;
        if (length == 0) {
            uint256 currentLength = tokenPrices.length();
            for (uint256 i = 0; i < currentLength; ++i) {
                // TODO add a clear function in EnumMap and EnumSet and use it
                (bytes32 token, ) = tokenPrices.at(0);
                tokenPrices.remove(token);
            }
        } else {
            _setTokenPrices(tokenPrices, tokens, prices);
        }

        emit SkuPricingUpdate(sku, tokens, prices);
    }

    /*                                   ISale Public Functions                                  */

    /**
     * Performs a purchase.
     * @dev Reverts if the sale has not started.
     * @dev Reverts if the sale is paused.
     * @dev Reverts if `recipient` is the zero address.
     * @dev Reverts if `token` is the zero address.
     * @dev Reverts if `quantity` is zero.
     * @dev Reverts if `quantity` is greater than the maximum purchase quantity.
     * @dev Reverts if `quantity` is greater than the remaining supply.
     * @dev Reverts if `sku` does not exist.
     * @dev Reverts if `sku` exists but does not have a price set for `token`.
     * @dev Emits the Purchase event.
     * @param recipient The recipient of the purchase.
     * @param token The token to use as the payment currency.
     * @param sku The identifier of the SKU to purchase.
     * @param quantity The quantity to purchase.
     * @param userData Optional extra user input data.
     */
    function purchaseFor(
        address payable recipient,
        address token,
        bytes32 sku,
        uint256 quantity,
        bytes calldata userData
    ) external payable virtual override whenStarted {
        _requireNotPaused();
        PurchaseData memory purchase;
        purchase.purchaser = _msgSender();
        purchase.recipient = recipient;
        purchase.token = token;
        purchase.sku = sku;
        purchase.quantity = quantity;
        purchase.userData = userData;

        _purchaseFor(purchase);
    }

    /**
     * Estimates the computed final total amount to pay for a purchase, including any potential discount.
     * @dev This function MUST compute the same price as `purchaseFor` would in identical conditions (same arguments, same point in time).
     * @dev If an implementer contract uses the `pricingData` field, it SHOULD document how to interpret the values.
     * @dev Reverts if the sale has not started.
     * @dev Reverts if the sale is paused.
     * @dev Reverts if `recipient` is the zero address.
     * @dev Reverts if `token` is the zero address.
     * @dev Reverts if `quantity` is zero.
     * @dev Reverts if `quantity` is greater than the maximum purchase quantity.
     * @dev Reverts if `quantity` is greater than the remaining supply.
     * @dev Reverts if `sku` does not exist.
     * @dev Reverts if `sku` exists but does not have a price set for `token`.
     * @param recipient The recipient of the purchase used to calculate the total price amount.
     * @param token The payment token used to calculate the total price amount.
     * @param sku The identifier of the SKU used to calculate the total price amount.
     * @param quantity The quantity used to calculate the total price amount.
     * @param userData Optional extra user input data.
     * @return totalPrice The computed total price.
     * @return pricingData Implementation-specific extra pricing data, such as details about discounts applied.
     *  If not empty, the implementer MUST document how to interepret the values.
     */
    function estimatePurchase(
        address payable recipient,
        address token,
        bytes32 sku,
        uint256 quantity,
        bytes calldata userData
    ) external view virtual override whenStarted returns (uint256 totalPrice, bytes32[] memory pricingData) {
        _requireNotPaused();
        PurchaseData memory purchase;
        purchase.purchaser = _msgSender();
        purchase.recipient = recipient;
        purchase.token = token;
        purchase.sku = sku;
        purchase.quantity = quantity;
        purchase.userData = userData;

        return _estimatePurchase(purchase);
    }

    /**
     * Returns the information relative to a SKU.
     * @dev WARNING: it is the responsibility of the implementer to ensure that the
     * number of payment tokens is bounded, so that this function does not run out of gas.
     * @dev Reverts if `sku` does not exist.
     * @param sku The SKU identifier.
     * @return totalSupply The initial total supply for sale.
     * @return remainingSupply The remaining supply for sale.
     * @return maxQuantityPerPurchase The maximum allowed quantity for a single purchase.
     * @return notificationsReceiver The address of a contract on which to call the `onPurchaseNotificationReceived` function.
     * @return tokens The list of supported payment tokens.
     * @return prices The list of associated prices for each of the `tokens`.
     */
    function getSkuInfo(bytes32 sku)
        external
        view
        override
        returns (
            uint256 totalSupply,
            uint256 remainingSupply,
            uint256 maxQuantityPerPurchase,
            address notificationsReceiver,
            address[] memory tokens,
            uint256[] memory prices
        )
    {
        SkuInfo storage skuInfo = _skuInfos[sku];
        uint256 length = skuInfo.prices.length();

        totalSupply = skuInfo.totalSupply;
        require(totalSupply != 0, "Sale: non-existent sku");
        remainingSupply = skuInfo.remainingSupply;
        maxQuantityPerPurchase = skuInfo.maxQuantityPerPurchase;
        notificationsReceiver = skuInfo.notificationsReceiver;

        tokens = new address[](length);
        prices = new uint256[](length);
        for (uint256 i = 0; i < length; ++i) {
            (bytes32 token, bytes32 price) = skuInfo.prices.at(i);
            tokens[i] = address(uint256(token));
            prices[i] = uint256(price);
        }
    }

    /**
     * Returns the list of created SKU identifiers.
     * @return skus the list of created SKU identifiers.
     */
    function getSkus() external view override returns (bytes32[] memory skus) {
        skus = _skus.values;
    }

    /*                               Internal Utility Functions                                  */

    /**
     * Creates an SKU.
     * @dev Reverts if `totalSupply` is zero.
     * @dev Reverts if `sku` already exists.
     * @dev Reverts if `notificationsReceiver` is not the zero address and is not a contract address.
     * @dev Reverts if the update results in too many SKUs.
     * @dev Emits the `SkuCreation` event.
     * @param sku the SKU identifier.
     * @param totalSupply the initial total supply.
     * @param maxQuantityPerPurchase The maximum allowed quantity for a single purchase.
     * @param notificationsReceiver The purchase notifications receiver contract address.
     *  If set to the zero address, the notification is not enabled.
     */
    function _createSku(
        bytes32 sku,
        uint256 totalSupply,
        uint256 maxQuantityPerPurchase,
        address notificationsReceiver
    ) internal virtual {
        require(totalSupply != 0, "Sale: zero supply");
        require(_skus.length() < _skusCapacity, "Sale: too many skus");
        require(_skus.add(sku), "Sale: sku already created");
        if (notificationsReceiver != address(0)) {
            require(notificationsReceiver.isContract(), "Sale: non-contract receiver");
        }
        SkuInfo storage skuInfo = _skuInfos[sku];
        skuInfo.totalSupply = totalSupply;
        skuInfo.remainingSupply = totalSupply;
        skuInfo.maxQuantityPerPurchase = maxQuantityPerPurchase;
        skuInfo.notificationsReceiver = notificationsReceiver;
        emit SkuCreation(sku, totalSupply, maxQuantityPerPurchase, notificationsReceiver);
    }

    /**
     * Updates SKU token prices.
     * @dev Reverts if one of the `tokens` is the zero address.
     * @dev Reverts if the update results in too many tokens for the SKU.
     * @param tokenPrices Storage pointer to a mapping of SKU token prices to update.
     * @param tokens The list of payment tokens to update.
     * @param prices The list of prices to apply for each payment token.
     *  Zero price values are used to disable a payment token.
     */
    function _setTokenPrices(
        EnumMap.Map storage tokenPrices,
        address[] memory tokens,
        uint256[] memory prices
    ) internal virtual {
        for (uint256 i = 0; i < tokens.length; ++i) {
            address token = tokens[i];
            require(token != address(0), "Sale: zero address token");
            uint256 price = prices[i];
            if (price == 0) {
                tokenPrices.remove(bytes32(uint256(token)));
            } else {
                tokenPrices.set(bytes32(uint256(token)), bytes32(price));
            }
        }
        require(tokenPrices.length() <= _tokensPerSkuCapacity, "Sale: too many tokens");
    }

    /*                            Internal Life Cycle Step Functions                             */

    /**
     * Lifecycle step which validates the purchase pre-conditions.
     * @dev Responsibilities:
     *  - Ensure that the purchase pre-conditions are met and revert if not.
     * @dev Reverts if `purchase.recipient` is the zero address.
     * @dev Reverts if `purchase.token` is the zero address.
     * @dev Reverts if `purchase.quantity` is zero.
     * @dev Reverts if `purchase.quantity` is greater than the SKU's `maxQuantityPerPurchase`.
     * @dev Reverts if `purchase.quantity` is greater than the available supply.
     * @dev Reverts if `purchase.sku` does not exist.
     * @dev Reverts if `purchase.sku` exists but does not have a price set for `purchase.token`.
     * @dev If this function is overriden, the implementer SHOULD super call this before.
     * @param purchase The purchase conditions.
     */
    function _validation(PurchaseData memory purchase) internal view virtual override {
        require(purchase.recipient != address(0), "Sale: zero address recipient");
        require(purchase.token != address(0), "Sale: zero address token");
        require(purchase.quantity != 0, "Sale: zero quantity purchase");
        SkuInfo storage skuInfo = _skuInfos[purchase.sku];
        require(skuInfo.totalSupply != 0, "Sale: non-existent sku");
        require(skuInfo.maxQuantityPerPurchase >= purchase.quantity, "Sale: above max quantity");
        if (skuInfo.totalSupply != SUPPLY_UNLIMITED) {
            require(skuInfo.remainingSupply >= purchase.quantity, "Sale: insufficient supply");
        }
        bytes32 priceKey = bytes32(uint256(purchase.token));
        require(skuInfo.prices.contains(priceKey), "Sale: non-existent sku token");
    }

    /**
     * Lifecycle step which delivers the purchased SKUs to the recipient.
     * @dev Responsibilities:
     *  - Ensure the product is delivered to the recipient, if that is the contract's responsibility.
     *  - Handle any internal logic related to the delivery, including the remaining supply update;
     *  - Add any relevant extra data related to delivery in `purchase.deliveryData` and document how to interpret it.
     * @dev Reverts if there is not enough available supply.
     * @dev If this function is overriden, the implementer SHOULD super call it.
     * @param purchase The purchase conditions.
     */
    function _delivery(PurchaseData memory purchase) internal virtual override {
        SkuInfo storage skuInfo = _skuInfos[purchase.sku];
        if (skuInfo.totalSupply != SUPPLY_UNLIMITED) {
            _skuInfos[purchase.sku].remainingSupply = skuInfo.remainingSupply.sub(purchase.quantity);
        }
    }

    /**
     * Lifecycle step which notifies of the purchase.
     * @dev Responsibilities:
     *  - Manage after-purchase event(s) emission.
     *  - Handle calls to the notifications receiver contract's `onPurchaseNotificationReceived` function, if applicable.
     * @dev Reverts if `onPurchaseNotificationReceived` throws or returns an incorrect value.
     * @dev Emits the `Purchase` event. The values of `purchaseData` are the concatenated values of `priceData`, `paymentData`
     * and `deliveryData`. If not empty, the implementer MUST document how to interpret these values.
     * @dev If this function is overriden, the implementer SHOULD super call it.
     * @param purchase The purchase conditions.
     */
    function _notification(PurchaseData memory purchase) internal virtual override {
        emit Purchase(
            purchase.purchaser,
            purchase.recipient,
            purchase.token,
            purchase.sku,
            purchase.quantity,
            purchase.userData,
            purchase.totalPrice,
            abi.encodePacked(purchase.pricingData, purchase.paymentData, purchase.deliveryData)
        );

        address notificationsReceiver = _skuInfos[purchase.sku].notificationsReceiver;
        if (notificationsReceiver != address(0)) {
            require(
                IPurchaseNotificationsReceiver(notificationsReceiver).onPurchaseNotificationReceived(
                    purchase.purchaser,
                    purchase.recipient,
                    purchase.token,
                    purchase.sku,
                    purchase.quantity,
                    purchase.userData,
                    purchase.totalPrice,
                    purchase.pricingData,
                    purchase.paymentData,
                    purchase.deliveryData
                ) == IPurchaseNotificationsReceiver(address(0)).onPurchaseNotificationReceived.selector, // TODO precompute return value
                "Sale: notification refused"
            );
        }
    }
}


// File @animoca/ethereum-contracts-sale-2.0.0/contracts/sale/FixedPricesSale.sol@v2.0.0

pragma solidity >=0.7.6 <0.8.0;


/**
 * @title FixedPricesSale
 * An Sale which implements a fixed prices strategy.
 *  The final implementer is responsible for implementing any additional pricing and/or delivery logic.
 */
abstract contract FixedPricesSale is Sale {
    using ERC20Wrapper for IWrappedERC20;
    using SafeMath for uint256;
    using EnumMap for EnumMap.Map;

    /**
     * Constructor.
     * @dev Emits the `MagicValues` event.
     * @dev Emits the `Paused` event.
     * @param payoutWallet_ the payout wallet.
     * @param skusCapacity the cap for the number of managed SKUs.
     * @param tokensPerSkuCapacity the cap for the number of tokens managed per SKU.
     */
    constructor(
        address payable payoutWallet_,
        uint256 skusCapacity,
        uint256 tokensPerSkuCapacity
    ) Sale(payoutWallet_, skusCapacity, tokensPerSkuCapacity) {}

    /*                               Internal Life Cycle Functions                               */

    /**
     * Lifecycle step which computes the purchase price.
     * @dev Responsibilities:
     *  - Computes the pricing formula, including any discount logic and price conversion;
     *  - Set the value of `purchase.totalPrice`;
     *  - Add any relevant extra data related to pricing in `purchase.pricingData` and document how to interpret it.
     * @dev Reverts if `purchase.sku` does not exist.
     * @dev Reverts if `purchase.token` is not supported by the SKU.
     * @dev Reverts in case of price overflow.
     * @param purchase The purchase conditions.
     */
    function _pricing(PurchaseData memory purchase) internal view virtual override {
        SkuInfo storage skuInfo = _skuInfos[purchase.sku];
        require(skuInfo.totalSupply != 0, "Sale: unsupported SKU");
        EnumMap.Map storage prices = skuInfo.prices;
        uint256 unitPrice = _unitPrice(purchase, prices);
        purchase.totalPrice = unitPrice.mul(purchase.quantity);
    }

    /**
     * Lifecycle step which manages the transfer of funds from the purchaser.
     * @dev Responsibilities:
     *  - Ensure the payment reaches destination in the expected output token;
     *  - Handle any token swap logic;
     *  - Add any relevant extra data related to payment in `purchase.paymentData` and document how to interpret it.
     * @dev Reverts in case of payment failure.
     * @param purchase The purchase conditions.
     */
    function _payment(PurchaseData memory purchase) internal virtual override {
        if (purchase.token == TOKEN_ETH) {
            require(msg.value >= purchase.totalPrice, "Sale: insufficient ETH");

            payoutWallet.transfer(purchase.totalPrice);

            uint256 change = msg.value.sub(purchase.totalPrice);

            if (change != 0) {
                purchase.purchaser.transfer(change);
            }
        } else {
            IWrappedERC20(purchase.token).wrappedTransferFrom(_msgSender(), payoutWallet, purchase.totalPrice);
        }
    }

    /*                               Internal Utility Functions                                  */

    /**
     * Retrieves the unit price of a SKU for the specified payment token.
     * @dev Reverts if the specified payment token is unsupported.
     * @param purchase The purchase conditions specifying the payment token with which the unit price will be retrieved.
     * @param prices Storage pointer to a mapping of SKU token prices to retrieve the unit price from.
     * @return unitPrice The unit price of a SKU for the specified payment token.
     */
    function _unitPrice(PurchaseData memory purchase, EnumMap.Map storage prices) internal view virtual returns (uint256 unitPrice) {
        unitPrice = uint256(prices.get(bytes32(uint256(purchase.token))));
        require(unitPrice != 0, "Sale: unsupported payment token");
    }
}


// File @animoca/ethereum-contracts-core-1.1.2/contracts/utils/Recoverable.sol@v1.1.2

pragma solidity >=0.7.6 <0.8.0;



abstract contract Recoverable is ManagedIdentity, Ownable {
    using ERC20Wrapper for IWrappedERC20;

    /**
     * Extract ERC20 tokens which were accidentally sent to the contract to a list of accounts.
     * Warning: this function should be overriden for contracts which are supposed to hold ERC20 tokens
     * so that the extraction is limited to only amounts sent accidentally.
     * @dev Reverts if the sender is not the contract owner.
     * @dev Reverts if `accounts`, `tokens` and `amounts` do not have the same length.
     * @dev Reverts if one of `tokens` is does not implement the ERC20 transfer function.
     * @dev Reverts if one of the ERC20 transfers fail for any reason.
     * @param accounts the list of accounts to transfer the tokens to.
     * @param tokens the list of ERC20 token addresses.
     * @param amounts the list of token amounts to transfer.
     */
    function recoverERC20s(
        address[] calldata accounts,
        address[] calldata tokens,
        uint256[] calldata amounts
    ) external virtual {
        _requireOwnership(_msgSender());
        uint256 length = accounts.length;
        require(length == tokens.length && length == amounts.length, "Recov: inconsistent arrays");
        for (uint256 i = 0; i != length; ++i) {
            IWrappedERC20(tokens[i]).wrappedTransfer(accounts[i], amounts[i]);
        }
    }

    /**
     * Extract ERC721 tokens which were accidentally sent to the contract to a list of accounts.
     * Warning: this function should be overriden for contracts which are supposed to hold ERC721 tokens
     * so that the extraction is limited to only tokens sent accidentally.
     * @dev Reverts if the sender is not the contract owner.
     * @dev Reverts if `accounts`, `contracts` and `amounts` do not have the same length.
     * @dev Reverts if one of `contracts` is does not implement the ERC721 transferFrom function.
     * @dev Reverts if one of the ERC721 transfers fail for any reason.
     * @param accounts the list of accounts to transfer the tokens to.
     * @param contracts the list of ERC721 contract addresses.
     * @param tokenIds the list of token ids to transfer.
     */
    function recoverERC721s(
        address[] calldata accounts,
        address[] calldata contracts,
        uint256[] calldata tokenIds
    ) external virtual {
        _requireOwnership(_msgSender());
        uint256 length = accounts.length;
        require(length == contracts.length && length == tokenIds.length, "Recov: inconsistent arrays");
        for (uint256 i = 0; i != length; ++i) {
            IRecoverableERC721(contracts[i]).transferFrom(address(this), accounts[i], tokenIds[i]);
        }
    }
}

interface IRecoverableERC721 {
    /// See {IERC721-transferFrom(address,address,uint256)}
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;
}


// File contracts/sale/TokenLaunchpadVouchersSale.sol

pragma solidity >=0.7.6 <0.8.0;


/**
 * @title TokenLaunchpad Vouchers Sale
 * A FixedPricesSale contract that handles the purchase and delivery of TokenLaunchpad vouchers.
 */
contract TokenLaunchpadVouchersSale is FixedPricesSale, Recoverable {
    IVouchersContract public immutable vouchersContract;

    mapping(bytes32 => uint256) public skuTokenIds;

    /**
     * Constructor.
     * @dev Emits the `MagicValues` event.
     * @dev Emits the `Paused` event.
     * @param vouchersContract_ The inventory contract from which the sale supply is attributed from.
     * @param payoutWallet the payout wallet.
     * @param skusCapacity the cap for the number of managed SKUs.
     * @param tokensPerSkuCapacity the cap for the number of tokens managed per SKU.
     */
    constructor(
        IVouchersContract vouchersContract_,
        address payable payoutWallet,
        uint256 skusCapacity,
        uint256 tokensPerSkuCapacity
    ) FixedPricesSale(payoutWallet, skusCapacity, tokensPerSkuCapacity) {
        vouchersContract = vouchersContract_;
    }

    /**
     * Creates an SKU.
     * @dev Reverts if `totalSupply` is zero.
     * @dev Reverts if `sku` already exists.
     * @dev Reverts if `notificationsReceiver` is not the zero address and is not a contract address.
     * @dev Reverts if the update results in too many SKUs.
     * @dev Reverts if `tokenId` is zero.
     * @dev Emits the `SkuCreation` event.
     * @param sku The SKU identifier.
     * @param totalSupply The initial total supply.
     * @param maxQuantityPerPurchase The maximum allowed quantity for a single purchase.
     * param notificationsReceiver The purchase notifications receiver contract address.
     *  If set to the zero address, the notification is not enabled.
     * @param tokenId The inventory contract token ID to associate with the SKU, used for purchase
     *  delivery.
     */
    function createSku(
        bytes32 sku,
        uint256 totalSupply,
        uint256 maxQuantityPerPurchase,
        uint256 tokenId
    ) external {
        _requireOwnership(_msgSender());
        require(vouchersContract.isFungible(tokenId), "Sale: not a fungible token");
        skuTokenIds[sku] = tokenId;
        _createSku(sku, totalSupply, maxQuantityPerPurchase, address(0));
    }

    /// @inheritdoc Sale
    function _delivery(PurchaseData memory purchase) internal override {
        super._delivery(purchase);
        vouchersContract.safeMint(purchase.recipient, skuTokenIds[purchase.sku], purchase.quantity, "");
    }
}

interface IVouchersContract {
    function isFungible(uint256 id) external pure returns (bool);

    function safeMint(
        address to,
        uint256 id,
        uint256 value,
        bytes calldata data
    ) external;
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"contract IVouchersContract","name":"vouchersContract_","type":"address"},{"internalType":"address payable","name":"payoutWallet","type":"address"},{"internalType":"uint256","name":"skusCapacity","type":"uint256"},{"internalType":"uint256","name":"tokensPerSkuCapacity","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32[]","name":"names","type":"bytes32[]"},{"indexed":false,"internalType":"bytes32[]","name":"values","type":"bytes32[]"}],"name":"MagicValues","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"payoutWallet_","type":"address"}],"name":"PayoutWalletSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"purchaser","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"bytes32","name":"sku","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"quantity","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"userData","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"totalPrice","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"extData","type":"bytes"}],"name":"Purchase","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"sku","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"totalSupply","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maxQuantityPerPurchase","type":"uint256"},{"indexed":false,"internalType":"address","name":"notificationsReceiver","type":"address"}],"name":"SkuCreation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"sku","type":"bytes32"},{"indexed":false,"internalType":"address[]","name":"tokens","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"prices","type":"uint256[]"}],"name":"SkuPricingUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Started","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"SUPPLY_UNLIMITED","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOKEN_ETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"sku","type":"bytes32"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"uint256","name":"maxQuantityPerPurchase","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"createSku","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"recipient","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"bytes32","name":"sku","type":"bytes32"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"bytes","name":"userData","type":"bytes"}],"name":"estimatePurchase","outputs":[{"internalType":"uint256","name":"totalPrice","type":"uint256"},{"internalType":"bytes32[]","name":"pricingData","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"sku","type":"bytes32"}],"name":"getSkuInfo","outputs":[{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"uint256","name":"remainingSupply","type":"uint256"},{"internalType":"uint256","name":"maxQuantityPerPurchase","type":"uint256"},{"internalType":"address","name":"notificationsReceiver","type":"address"},{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"prices","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSkus","outputs":[{"internalType":"bytes32[]","name":"skus","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"payoutWallet","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address payable","name":"recipient","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"bytes32","name":"sku","type":"bytes32"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"bytes","name":"userData","type":"bytes"}],"name":"purchaseFor","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"recoverERC20s","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"address[]","name":"contracts","type":"address[]"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"recoverERC721s","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"payoutWallet_","type":"address"}],"name":"setPayoutWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"skuTokenIds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"start","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startedAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"sku","type":"bytes32"},{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"prices","type":"uint256[]"}],"name":"updateSkuPricing","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vouchersContract","outputs":[{"internalType":"contract IVouchersContract","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

60e06040523480156200001157600080fd5b50604051620031e5380380620031e5833981810160405260808110156200003757600080fd5b5080516020820151604080840151606090940151600080546001600160a01b031916339081178255925194959394919285928592859285928592859260019290918691839182917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3506001600160a01b03811662000100576040805162461bcd60e51b815260206004820152601460248201527f5061796f75743a207a65726f2061646472657373000000000000000000000000604482015290519081900360640190fd5b600180546001600160a01b0383166001600160a01b0319909116811790915560408051918252517fdd880d24a789958a6398c99c2e54ce31bc10a638cbc42f7dd34285479ae0f8559181900360200190a150506003805460ff1916911515919091179055608082905260a081905260408051600280825260608201835260009260208301908036833750506040805160028082526060820183529394506000939092509060208301908036833750508351919250680a89e968a9cbe8aa8960bb1b9173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee91508490600090620001e557fe5b6020026020010183600081518110620001fa57fe5b602002602001018281525082815250505060001960001b6f14d55414131657d5539312535255115160821b90836001815181106200023457fe5b60200260200101836001815181106200024957fe5b60200260200101828152508281525050507fabb92614f53337043b55dc996a83ebb09adce78ec336ca188ea02180b61d1c148282604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b83811015620002c3578181015183820152602001620002a9565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101562000304578181015183820152602001620002ea565b5050505090500194505050505060405180910390a15050506001600160601b031960609990991b9890981660c052505050505050505060805160a05160c05160601c612e716200037460003980610cc9528061101e52806125c7525080611948525080611a1c5250612e716000f3fe60806040526004361061016a5760003560e01c80636ed51c48116100cb5780639e0495451161007f578063c3666c3611610059578063c3666c3614610844578063f21f537d14610965578063f2fde38b1461097a5761016a565b80639e04954514610785578063a963b2571461079a578063be9a65551461082f5761016a565b80638456cb59116100b05780638456cb59146107465780638488bb4e1461075b5780638da5cb5b146107705761016a565b80636ed51c48146105e957806373c8a958146106255761016a565b80635c4fafc7116101225780635e6e9f70116101075780635e6e9f701461041657806361bd3851146105515780636b8f9c43146105b65761016a565b80635c4fafc7146103d85780635c975abb146103ed5761016a565b80632a8a45bc116101535780632a8a45bc146102a85780633f4ba83a14610390578063474f2891146103a75761016a565b80631323b0661461016f5780631793494c1461026c575b600080fd5b34801561017b57600080fd5b50610211600480360360a081101561019257600080fd5b6001600160a01b03823581169260208101359091169160408201359160608101359181019060a0810160808201356401000000008111156101d257600080fd5b8201836020820111156101e457600080fd5b8035906020019184600183028401116401000000008311171561020657600080fd5b5090925090506109ad565b6040518083815260200180602001828103825283818151815260200191508051906020019060200280838360005b8381101561025757818101518382015260200161023f565b50505050905001935050505060405180910390f35b34801561027857600080fd5b506102966004803603602081101561028f57600080fd5b5035610aa2565b60408051918252519081900360200190f35b3480156102b457600080fd5b506102d2600480360360208110156102cb57600080fd5b5035610ab4565b60405180878152602001868152602001858152602001846001600160a01b031681526020018060200180602001838103835285818151815260200191508051906020019060200280838360005b8381101561033757818101518382015260200161031f565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561037657818101518382015260200161035e565b505050509050019850505050505050505060405180910390f35b34801561039c57600080fd5b506103a5610c59565b005b3480156103b357600080fd5b506103bc610cc7565b604080516001600160a01b039092168252519081900360200190f35b3480156103e457600080fd5b506103bc610ceb565b3480156103f957600080fd5b50610402610d03565b604080519115158252519081900360200190f35b34801561042257600080fd5b506103a56004803603606081101561043957600080fd5b8135919081019060408101602082013564010000000081111561045b57600080fd5b82018360208201111561046d57600080fd5b8035906020019184602083028401116401000000008311171561048f57600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092959493602081019350359150506401000000008111156104df57600080fd5b8201836020820111156104f157600080fd5b8035906020019184602083028401116401000000008311171561051357600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550610d0c945050505050565b34801561055d57600080fd5b50610566610ee9565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156105a257818101518382015260200161058a565b505050509050019250505060405180910390f35b3480156105c257600080fd5b506103a5600480360360208110156105d957600080fd5b50356001600160a01b0316610f44565b3480156105f557600080fd5b506103a56004803603608081101561060c57600080fd5b5080359060208101359060408101359060600135611011565b34801561063157600080fd5b506103a56004803603606081101561064857600080fd5b81019060208101813564010000000081111561066357600080fd5b82018360208201111561067557600080fd5b8035906020019184602083028401116401000000008311171561069757600080fd5b9193909290916020810190356401000000008111156106b557600080fd5b8201836020820111156106c757600080fd5b803590602001918460208302840111640100000000831117156106e957600080fd5b91939092909160208101903564010000000081111561070757600080fd5b82018360208201111561071957600080fd5b8035906020019184602083028401116401000000008311171561073b57600080fd5b509092509050611123565b34801561075257600080fd5b506103a5611210565b34801561076757600080fd5b506103bc611277565b34801561077c57600080fd5b506103bc611286565b34801561079157600080fd5b50610296611295565b6103a5600480360360a08110156107b057600080fd5b6001600160a01b03823581169260208101359091169160408201359160608101359181019060a0810160808201356401000000008111156107f057600080fd5b82018360208201111561080257600080fd5b8035906020019184600183028401116401000000008311171561082457600080fd5b50909250905061129b565b34801561083b57600080fd5b506103a5611381565b34801561085057600080fd5b506103a56004803603606081101561086757600080fd5b81019060208101813564010000000081111561088257600080fd5b82018360208201111561089457600080fd5b803590602001918460208302840111640100000000831117156108b657600080fd5b9193909290916020810190356401000000008111156108d457600080fd5b8201836020820111156108e657600080fd5b8035906020019184602083028401116401000000008311171561090857600080fd5b91939092909160208101903564010000000081111561092657600080fd5b82018360208201111561093857600080fd5b8035906020019184602083028401116401000000008311171561095a57600080fd5b509092509050611394565b34801561097157600080fd5b506102966114dc565b34801561098657600080fd5b506103a56004803603602081101561099d57600080fd5b50356001600160a01b03166114e2565b6000606060025460001415610a09576040805162461bcd60e51b815260206004820152601660248201527f537461727461626c653a206e6f74207374617274656400000000000000000000604482015290519081900360640190fd5b610a11611548565b610a19612da9565b610a216115a0565b6001600160a01b03908116825289811660208084019190915290891660408084019190915260608301899052608083018890528051601f870183900483028101830190915285815290869086908190840183828082843760009201919091525050505060a0820152610a92816115a4565b9250925050965096945050505050565b60076020526000908152604090205481565b6000818152600660205260408120819081908190606090819083610ada600483016115cb565b82549850905087610b32576040805162461bcd60e51b815260206004820152601660248201527f53616c653a206e6f6e2d6578697374656e7420736b7500000000000000000000604482015290519081900360640190fd5b60018201546002830154600384015491985096506001600160a01b031694508067ffffffffffffffff81118015610b6857600080fd5b50604051908082528060200260200182016040528015610b92578160200160208202803683370190505b5093508067ffffffffffffffff81118015610bac57600080fd5b50604051908082528060200260200182016040528015610bd6578160200160208202803683370190505b50925060005b81811015610c4d57600080610bf460048601846115cf565b915091508160001c878481518110610c0857fe5b60200260200101906001600160a01b031690816001600160a01b0316815250508060001c868481518110610c3857fe5b60209081029190910101525050600101610bdc565b50505091939550919395565b600254610cad576040805162461bcd60e51b815260206004820152601660248201527f537461727461626c653a206e6f74207374617274656400000000000000000000604482015290519081900360640190fd5b610cbd610cb86115a0565b611660565b610cc5611727565b565b7f000000000000000000000000000000000000000000000000000000000000000081565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b60035460ff1681565b610d17610cb86115a0565b815181518114610d6e576040805162461bcd60e51b815260206004820152601960248201527f53616c653a20696e636f6e73697374656e742061727261797300000000000000604482015290519081900360640190fd5b60008481526006602052604090208054610dcf576040805162461bcd60e51b815260206004820152601660248201527f53616c653a206e6f6e2d6578697374656e7420736b7500000000000000000000604482015290519081900360640190fd5b6004810182610e1a576000610de3826115cb565b905060005b81811015610e13576000610dfc84826115cf565b509050610e09848261177f565b5050600101610de8565b5050610e25565b610e2581868661185f565b857fcb3fe5489e0cd43d0f4a33d1e09a4a0463a03d0d38f56165530854e5540db1438686604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b83811015610e8d578181015183820152602001610e75565b50505050905001838103825284818151815260200191508051906020019060200280838360005b83811015610ecc578181015183820152602001610eb4565b5050505090500194505050505060405180910390a2505050505050565b60606004600001805480602002602001604051908101604052809291908181526020018280548015610f3a57602002820191906000526020600020905b815481526020019060010190808311610f26575b5050505050905090565b610f4f610cb86115a0565b6001600160a01b038116610faa576040805162461bcd60e51b815260206004820152601460248201527f5061796f75743a207a65726f2061646472657373000000000000000000000000604482015290519081900360640190fd5b6001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03838116919091179182905560408051929091168252517fdd880d24a789958a6398c99c2e54ce31bc10a638cbc42f7dd34285479ae0f855916020908290030190a150565b61101c610cb86115a0565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663adebf6f2826040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561108057600080fd5b505afa158015611094573d6000803e3d6000fd5b505050506040513d60208110156110aa57600080fd5b50516110fd576040805162461bcd60e51b815260206004820152601a60248201527f53616c653a206e6f7420612066756e6769626c6520746f6b656e000000000000604482015290519081900360640190fd5b600084815260076020526040812082905561111d908590859085906119c8565b50505050565b61112e610cb86115a0565b84838114801561113d57508082145b61118e576040805162461bcd60e51b815260206004820152601a60248201527f5265636f763a20696e636f6e73697374656e7420617272617973000000000000604482015290519081900360640190fd5b60005b818114611206576111fe8888838181106111a757fe5b905060200201356001600160a01b03168585848181106111c357fe5b905060200201358888858181106111d657fe5b905060200201356001600160a01b03166001600160a01b0316611bff9092919063ffffffff16565b600101611191565b5050505050505050565b600254611264576040805162461bcd60e51b815260206004820152601660248201527f537461727461626c653a206e6f74207374617274656400000000000000000000604482015290519081900360640190fd5b61126f610cb86115a0565b610cc5611c7f565b6001546001600160a01b031681565b6000546001600160a01b031690565b60001981565b6002546112ef576040805162461bcd60e51b815260206004820152601660248201527f537461727461626c653a206e6f74207374617274656400000000000000000000604482015290519081900360640190fd5b6112f7611548565b6112ff612da9565b6113076115a0565b6001600160a01b03908116825287811660208084019190915290871660408084019190915260608301879052608083018690528051601f850183900483028101830190915283815290849084908190840183828082843760009201919091525050505060a082015261137881611cbd565b50505050505050565b61138c610cb86115a0565b610cbd611cea565b61139f610cb86115a0565b8483811480156113ae57508082145b6113ff576040805162461bcd60e51b815260206004820152601a60248201527f5265636f763a20696e636f6e73697374656e7420617272617973000000000000604482015290519081900360640190fd5b60005b8181146112065785858281811061141557fe5b905060200201356001600160a01b03166001600160a01b03166323b872dd308a8a8581811061144057fe5b905060200201356001600160a01b031687878681811061145c57fe5b905060200201356040518463ffffffff1660e01b815260040180846001600160a01b03168152602001836001600160a01b031681526020018281526020019350505050600060405180830381600087803b1580156114b957600080fd5b505af11580156114cd573d6000803e3d6000fd5b50505050806001019050611402565b60025490565b6114ed610cb86115a0565b6000805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383811691821780845560405192939116917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a350565b60035460ff1615610cc5576040805162461bcd60e51b815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015290519081900360640190fd5b3390565b600060606115b183611d6c565b6115ba83612016565b505060c081015160e0909101519091565b5490565b815460009081908310611629576040805162461bcd60e51b815260206004820152601c60248201527f456e756d4d61703a20696e646578206f7574206f6620626f756e647300000000604482015290519081900360640190fd5b600084600001848154811061163a57fe5b906000526020600020906002020190508060000154816001015492509250509250929050565b306001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561169957600080fd5b505afa1580156116ad573d6000803e3d6000fd5b505050506040513d60208110156116c357600080fd5b50516001600160a01b03828116911614611724576040805162461bcd60e51b815260206004820152601660248201527f4f776e61626c653a206e6f7420746865206f776e657200000000000000000000604482015290519081900360640190fd5b50565b61172f6120b3565b6003805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6117626115a0565b604080516001600160a01b039092168252519081900360200190a1565b6000818152600183016020526040812054801561185357835460001980830191908101906000908790839081106117b257fe5b90600052602060002090600202019050808760000184815481106117d257fe5b60009182526020808320845460029093020191825560019384015491840191909155835482528983019052604090209084019055865487908061181157fe5b60008281526020808220600260001990940193840201828155600190810183905592909355888152898201909252604082209190915594506118599350505050565b60009150505b92915050565b60005b825181101561194557600083828151811061187957fe5b6020026020010151905060006001600160a01b0316816001600160a01b031614156118eb576040805162461bcd60e51b815260206004820152601860248201527f53616c653a207a65726f206164647265737320746f6b656e0000000000000000604482015290519081900360640190fd5b60008383815181106118f957fe5b6020026020010151905080600014156119255761191f866001600160a01b03841661177f565b5061193b565b611939866001600160a01b0384168361210a565b505b5050600101611862565b507f0000000000000000000000000000000000000000000000000000000000000000611970846115cb565b11156119c3576040805162461bcd60e51b815260206004820152601560248201527f53616c653a20746f6f206d616e7920746f6b656e730000000000000000000000604482015290519081900360640190fd5b505050565b82611a1a576040805162461bcd60e51b815260206004820152601160248201527f53616c653a207a65726f20737570706c79000000000000000000000000000000604482015290519081900360640190fd5b7f0000000000000000000000000000000000000000000000000000000000000000611a4560046115cb565b10611a97576040805162461bcd60e51b815260206004820152601360248201527f53616c653a20746f6f206d616e7920736b757300000000000000000000000000604482015290519081900360640190fd5b611aa26004856121a4565b611af3576040805162461bcd60e51b815260206004820152601960248201527f53616c653a20736b7520616c7265616479206372656174656400000000000000604482015290519081900360640190fd5b6001600160a01b03811615611b6557611b14816001600160a01b03166121ee565b611b65576040805162461bcd60e51b815260206004820152601b60248201527f53616c653a206e6f6e2d636f6e74726163742072656365697665720000000000604482015290519081900360640190fd5b60008481526006602090815260409182902085815560018101869055600281018590556003810180546001600160a01b03861673ffffffffffffffffffffffffffffffffffffffff1990911681179091558351888152928301879052828401869052606083015291517f38bd4aabce684540cd61351b91f2f5facf9d6963934347e25aab93d87ae7ac149181900360800190a15050505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526119c39084906121f4565b611c87611548565b6003805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586117626115a0565b611cc681611d6c565b611ccf81612016565b611cd8816123fc565b611ce18161254b565b6117248161261f565b60025415611d3f576040805162461bcd60e51b815260206004820152601260248201527f537461727461626c653a20737461727465640000000000000000000000000000604482015290519081900360640190fd5b426002557f27029695aa5f602a4ee81f4c32dfa86e562f200a17966496f3a7c3f2ec0f94176117626115a0565b60208101516001600160a01b0316611dcb576040805162461bcd60e51b815260206004820152601c60248201527f53616c653a207a65726f206164647265737320726563697069656e7400000000604482015290519081900360640190fd5b60408101516001600160a01b0316611e2a576040805162461bcd60e51b815260206004820152601860248201527f53616c653a207a65726f206164647265737320746f6b656e0000000000000000604482015290519081900360640190fd5b6080810151611e80576040805162461bcd60e51b815260206004820152601c60248201527f53616c653a207a65726f207175616e7469747920707572636861736500000000604482015290519081900360640190fd5b606081015160009081526006602052604090208054611ee6576040805162461bcd60e51b815260206004820152601660248201527f53616c653a206e6f6e2d6578697374656e7420736b7500000000000000000000604482015290519081900360640190fd5b816080015181600201541015611f43576040805162461bcd60e51b815260206004820152601860248201527f53616c653a2061626f7665206d6178207175616e746974790000000000000000604482015290519081900360640190fd5b805460001914611faa57816080015181600101541015611faa576040805162461bcd60e51b815260206004820152601960248201527f53616c653a20696e73756666696369656e7420737570706c7900000000000000604482015290519081900360640190fd5b60408201516001600160a01b0316611fc56004830182612b08565b6119c3576040805162461bcd60e51b815260206004820152601c60248201527f53616c653a206e6f6e2d6578697374656e7420736b7520746f6b656e00000000604482015290519081900360640190fd5b60608101516000908152600660205260409020805461207c576040805162461bcd60e51b815260206004820152601560248201527f53616c653a20756e737570706f7274656420534b550000000000000000000000604482015290519081900360640190fd5b60048101600061208c8483612b20565b90506120a5846080015182612b9090919063ffffffff16565b60c090940193909352505050565b60035460ff16610cc5576040805162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015290519081900360640190fd5b60008281526001840160205260408120548061216f57505060408051808201825283815260208082018481528654600181810189556000898152848120955160029093029095019182559151908201558654868452818801909252929091205561219d565b8285600001600183038154811061218257fe5b90600052602060002090600202016001018190555060009150505b9392505050565b60006121b08383612b08565b6121e657508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611859565b506000611859565b3b151590565b816122076001600160a01b0382166121ee565b612258576040805162461bcd60e51b815260206004820152601a60248201527f4552433230577261707065723a206e6f6e2d636f6e7472616374000000000000604482015290519081900360640190fd5b600080826001600160a01b0316846040518082805190602001908083835b602083106122b357805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101612276565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612315576040519150601f19603f3d011682016040523d82523d6000602084013e61231a565b606091505b50915091508115612399578051156123945780806020019051602081101561234157600080fd5b5051612394576040805162461bcd60e51b815260206004820152601e60248201527f4552433230577261707065723a206f7065726174696f6e206661696c65640000604482015290519081900360640190fd5b6123f5565b80516123ec576040805162461bcd60e51b815260206004820152601e60248201527f4552433230577261707065723a206f7065726174696f6e206661696c65640000604482015290519081900360640190fd5b80518082602001fd5b5050505050565b60408101516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee141561251f578060c0015134101561247e576040805162461bcd60e51b815260206004820152601660248201527f53616c653a20696e73756666696369656e742045544800000000000000000000604482015290519081900360640190fd5b60015460c08201516040516001600160a01b039092169181156108fc0291906000818181858888f193505050501580156124bc573d6000803e3d6000fd5b5060006124d68260c0015134612be990919063ffffffff16565b905080156125195781516040516001600160a01b039091169082156108fc029083906000818181858888f19350505050158015612517573d6000803e3d6000fd5b505b50611724565b61172461252a6115a0565b60015460c084015160408501516001600160a01b0390811693921690612c46565b61255481612cce565b60208181015160608301516000908152600790925260408083205460808086015183517f5cfa92970000000000000000000000000000000000000000000000000000000081526001600160a01b0395861660048201526024810193909352604483015260648201526084810184905290517f000000000000000000000000000000000000000000000000000000000000000090921692635cfa92979260a48084019382900301818387803b15801561260b57600080fd5b505af11580156123f5573d6000803e3d6000fd5b806060015181604001516001600160a01b031682600001516001600160a01b03167f29f844483ca6b10b5c0611d039afc15ce8f6380e905307b381c3a8ee4e90e11e846020015185608001518660a001518760c001518860e001518961010001518a610120015160405160200180848051906020019060200280838360005b838110156126b657818101518382015260200161269e565b50505050905001838051906020019060200280838360005b838110156126e65781810151838201526020016126ce565b50505050905001828051906020019060200280838360005b838110156127165781810151838201526020016126fe565b50505050905001935050505060405160208183030381529060405260405180866001600160a01b031681526020018581526020018060200184815260200180602001838103835286818151815260200191508051906020019080838360005b8381101561278d578181015183820152602001612775565b50505050905090810190601f1680156127ba5780820380516001836020036101000a031916815260200191505b50838103825284518152845160209182019186019080838360005b838110156127ed5781810151838201526020016127d5565b50505050905090810190601f16801561281a5780820380516001836020036101000a031916815260200191505b5097505050505050505060405180910390a460608101516000908152600660205260409020600301546001600160a01b03168015612b04576361eceae860e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916816001600160a01b03166361eceae8846000015185602001518660400151876060015188608001518960a001518a60c001518b60e001518c61010001518d61012001516040518b63ffffffff1660e01b8152600401808b6001600160a01b031681526020018a6001600160a01b03168152602001896001600160a01b031681526020018881526020018781526020018060200186815260200180602001806020018060200185810385528a818151815260200191508051906020019080838360005b8381101561295357818101518382015260200161293b565b50505050905090810190601f1680156129805780820380516001836020036101000a031916815260200191505b508581038452885181528851602091820191808b01910280838360005b838110156129b557818101518382015260200161299d565b50505050905001858103835287818151815260200191508051906020019060200280838360005b838110156129f45781810151838201526020016129dc565b50505050905001858103825286818151815260200191508051906020019060200280838360005b83811015612a33578181015183820152602001612a1b565b505050509050019e505050505050505050505050505050602060405180830381600087803b158015612a6457600080fd5b505af1158015612a78573d6000803e3d6000fd5b505050506040513d6020811015612a8e57600080fd5b50517fffffffff000000000000000000000000000000000000000000000000000000001614612b04576040805162461bcd60e51b815260206004820152601a60248201527f53616c653a206e6f74696669636174696f6e2072656675736564000000000000604482015290519081900360640190fd5b5050565b60009081526001919091016020526040902054151590565b6040820151600090612b3c9083906001600160a01b0316612d19565b905080611859576040805162461bcd60e51b815260206004820152601f60248201527f53616c653a20756e737570706f72746564207061796d656e7420746f6b656e00604482015290519081900360640190fd5b600082612b9f57506000611859565b82820282848281612bac57fe5b041461219d5760405162461bcd60e51b8152600401808060200182810382526021815260200180612e1b6021913960400191505060405180910390fd5b600082821115612c40576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905261111d9085906121f4565b60608101516000908152600660205260409020805460001914612b045760808201516001820154612cfe91612be9565b60608301516000908152600660205260409020600101555050565b600081815260018301602052604081205480612d7c576040805162461bcd60e51b815260206004820152601860248201527f456e756d4d61703a206e6f6e6578697374656e74206b65790000000000000000604482015290519081900360640190fd5b836000016001820381548110612d8e57fe5b90600052602060002090600202016001015491505092915050565b60405180610140016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008019168152602001600081526020016060815260200160008152602001606081526020016060815260200160608152509056fe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a26469706673582212204d8cb75b26991c2fd95de34bbfcb733e5c728a2668a653399596a37a352a4c8564736f6c6343000706003300000000000000000000000087a3747c9942d8351cc85aac2f94807b27a37c0d00000000000000000000000039fa29ede121b06dce3674e97970caa539afc9570000000000000000000000000000000000000000000000000000000000000019000000000000000000000000000000000000000000000000000000000000000a

Deployed Bytecode

0x60806040526004361061016a5760003560e01c80636ed51c48116100cb5780639e0495451161007f578063c3666c3611610059578063c3666c3614610844578063f21f537d14610965578063f2fde38b1461097a5761016a565b80639e04954514610785578063a963b2571461079a578063be9a65551461082f5761016a565b80638456cb59116100b05780638456cb59146107465780638488bb4e1461075b5780638da5cb5b146107705761016a565b80636ed51c48146105e957806373c8a958146106255761016a565b80635c4fafc7116101225780635e6e9f70116101075780635e6e9f701461041657806361bd3851146105515780636b8f9c43146105b65761016a565b80635c4fafc7146103d85780635c975abb146103ed5761016a565b80632a8a45bc116101535780632a8a45bc146102a85780633f4ba83a14610390578063474f2891146103a75761016a565b80631323b0661461016f5780631793494c1461026c575b600080fd5b34801561017b57600080fd5b50610211600480360360a081101561019257600080fd5b6001600160a01b03823581169260208101359091169160408201359160608101359181019060a0810160808201356401000000008111156101d257600080fd5b8201836020820111156101e457600080fd5b8035906020019184600183028401116401000000008311171561020657600080fd5b5090925090506109ad565b6040518083815260200180602001828103825283818151815260200191508051906020019060200280838360005b8381101561025757818101518382015260200161023f565b50505050905001935050505060405180910390f35b34801561027857600080fd5b506102966004803603602081101561028f57600080fd5b5035610aa2565b60408051918252519081900360200190f35b3480156102b457600080fd5b506102d2600480360360208110156102cb57600080fd5b5035610ab4565b60405180878152602001868152602001858152602001846001600160a01b031681526020018060200180602001838103835285818151815260200191508051906020019060200280838360005b8381101561033757818101518382015260200161031f565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561037657818101518382015260200161035e565b505050509050019850505050505050505060405180910390f35b34801561039c57600080fd5b506103a5610c59565b005b3480156103b357600080fd5b506103bc610cc7565b604080516001600160a01b039092168252519081900360200190f35b3480156103e457600080fd5b506103bc610ceb565b3480156103f957600080fd5b50610402610d03565b604080519115158252519081900360200190f35b34801561042257600080fd5b506103a56004803603606081101561043957600080fd5b8135919081019060408101602082013564010000000081111561045b57600080fd5b82018360208201111561046d57600080fd5b8035906020019184602083028401116401000000008311171561048f57600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092959493602081019350359150506401000000008111156104df57600080fd5b8201836020820111156104f157600080fd5b8035906020019184602083028401116401000000008311171561051357600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550610d0c945050505050565b34801561055d57600080fd5b50610566610ee9565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156105a257818101518382015260200161058a565b505050509050019250505060405180910390f35b3480156105c257600080fd5b506103a5600480360360208110156105d957600080fd5b50356001600160a01b0316610f44565b3480156105f557600080fd5b506103a56004803603608081101561060c57600080fd5b5080359060208101359060408101359060600135611011565b34801561063157600080fd5b506103a56004803603606081101561064857600080fd5b81019060208101813564010000000081111561066357600080fd5b82018360208201111561067557600080fd5b8035906020019184602083028401116401000000008311171561069757600080fd5b9193909290916020810190356401000000008111156106b557600080fd5b8201836020820111156106c757600080fd5b803590602001918460208302840111640100000000831117156106e957600080fd5b91939092909160208101903564010000000081111561070757600080fd5b82018360208201111561071957600080fd5b8035906020019184602083028401116401000000008311171561073b57600080fd5b509092509050611123565b34801561075257600080fd5b506103a5611210565b34801561076757600080fd5b506103bc611277565b34801561077c57600080fd5b506103bc611286565b34801561079157600080fd5b50610296611295565b6103a5600480360360a08110156107b057600080fd5b6001600160a01b03823581169260208101359091169160408201359160608101359181019060a0810160808201356401000000008111156107f057600080fd5b82018360208201111561080257600080fd5b8035906020019184600183028401116401000000008311171561082457600080fd5b50909250905061129b565b34801561083b57600080fd5b506103a5611381565b34801561085057600080fd5b506103a56004803603606081101561086757600080fd5b81019060208101813564010000000081111561088257600080fd5b82018360208201111561089457600080fd5b803590602001918460208302840111640100000000831117156108b657600080fd5b9193909290916020810190356401000000008111156108d457600080fd5b8201836020820111156108e657600080fd5b8035906020019184602083028401116401000000008311171561090857600080fd5b91939092909160208101903564010000000081111561092657600080fd5b82018360208201111561093857600080fd5b8035906020019184602083028401116401000000008311171561095a57600080fd5b509092509050611394565b34801561097157600080fd5b506102966114dc565b34801561098657600080fd5b506103a56004803603602081101561099d57600080fd5b50356001600160a01b03166114e2565b6000606060025460001415610a09576040805162461bcd60e51b815260206004820152601660248201527f537461727461626c653a206e6f74207374617274656400000000000000000000604482015290519081900360640190fd5b610a11611548565b610a19612da9565b610a216115a0565b6001600160a01b03908116825289811660208084019190915290891660408084019190915260608301899052608083018890528051601f870183900483028101830190915285815290869086908190840183828082843760009201919091525050505060a0820152610a92816115a4565b9250925050965096945050505050565b60076020526000908152604090205481565b6000818152600660205260408120819081908190606090819083610ada600483016115cb565b82549850905087610b32576040805162461bcd60e51b815260206004820152601660248201527f53616c653a206e6f6e2d6578697374656e7420736b7500000000000000000000604482015290519081900360640190fd5b60018201546002830154600384015491985096506001600160a01b031694508067ffffffffffffffff81118015610b6857600080fd5b50604051908082528060200260200182016040528015610b92578160200160208202803683370190505b5093508067ffffffffffffffff81118015610bac57600080fd5b50604051908082528060200260200182016040528015610bd6578160200160208202803683370190505b50925060005b81811015610c4d57600080610bf460048601846115cf565b915091508160001c878481518110610c0857fe5b60200260200101906001600160a01b031690816001600160a01b0316815250508060001c868481518110610c3857fe5b60209081029190910101525050600101610bdc565b50505091939550919395565b600254610cad576040805162461bcd60e51b815260206004820152601660248201527f537461727461626c653a206e6f74207374617274656400000000000000000000604482015290519081900360640190fd5b610cbd610cb86115a0565b611660565b610cc5611727565b565b7f00000000000000000000000087a3747c9942d8351cc85aac2f94807b27a37c0d81565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b60035460ff1681565b610d17610cb86115a0565b815181518114610d6e576040805162461bcd60e51b815260206004820152601960248201527f53616c653a20696e636f6e73697374656e742061727261797300000000000000604482015290519081900360640190fd5b60008481526006602052604090208054610dcf576040805162461bcd60e51b815260206004820152601660248201527f53616c653a206e6f6e2d6578697374656e7420736b7500000000000000000000604482015290519081900360640190fd5b6004810182610e1a576000610de3826115cb565b905060005b81811015610e13576000610dfc84826115cf565b509050610e09848261177f565b5050600101610de8565b5050610e25565b610e2581868661185f565b857fcb3fe5489e0cd43d0f4a33d1e09a4a0463a03d0d38f56165530854e5540db1438686604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b83811015610e8d578181015183820152602001610e75565b50505050905001838103825284818151815260200191508051906020019060200280838360005b83811015610ecc578181015183820152602001610eb4565b5050505090500194505050505060405180910390a2505050505050565b60606004600001805480602002602001604051908101604052809291908181526020018280548015610f3a57602002820191906000526020600020905b815481526020019060010190808311610f26575b5050505050905090565b610f4f610cb86115a0565b6001600160a01b038116610faa576040805162461bcd60e51b815260206004820152601460248201527f5061796f75743a207a65726f2061646472657373000000000000000000000000604482015290519081900360640190fd5b6001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03838116919091179182905560408051929091168252517fdd880d24a789958a6398c99c2e54ce31bc10a638cbc42f7dd34285479ae0f855916020908290030190a150565b61101c610cb86115a0565b7f00000000000000000000000087a3747c9942d8351cc85aac2f94807b27a37c0d6001600160a01b031663adebf6f2826040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561108057600080fd5b505afa158015611094573d6000803e3d6000fd5b505050506040513d60208110156110aa57600080fd5b50516110fd576040805162461bcd60e51b815260206004820152601a60248201527f53616c653a206e6f7420612066756e6769626c6520746f6b656e000000000000604482015290519081900360640190fd5b600084815260076020526040812082905561111d908590859085906119c8565b50505050565b61112e610cb86115a0565b84838114801561113d57508082145b61118e576040805162461bcd60e51b815260206004820152601a60248201527f5265636f763a20696e636f6e73697374656e7420617272617973000000000000604482015290519081900360640190fd5b60005b818114611206576111fe8888838181106111a757fe5b905060200201356001600160a01b03168585848181106111c357fe5b905060200201358888858181106111d657fe5b905060200201356001600160a01b03166001600160a01b0316611bff9092919063ffffffff16565b600101611191565b5050505050505050565b600254611264576040805162461bcd60e51b815260206004820152601660248201527f537461727461626c653a206e6f74207374617274656400000000000000000000604482015290519081900360640190fd5b61126f610cb86115a0565b610cc5611c7f565b6001546001600160a01b031681565b6000546001600160a01b031690565b60001981565b6002546112ef576040805162461bcd60e51b815260206004820152601660248201527f537461727461626c653a206e6f74207374617274656400000000000000000000604482015290519081900360640190fd5b6112f7611548565b6112ff612da9565b6113076115a0565b6001600160a01b03908116825287811660208084019190915290871660408084019190915260608301879052608083018690528051601f850183900483028101830190915283815290849084908190840183828082843760009201919091525050505060a082015261137881611cbd565b50505050505050565b61138c610cb86115a0565b610cbd611cea565b61139f610cb86115a0565b8483811480156113ae57508082145b6113ff576040805162461bcd60e51b815260206004820152601a60248201527f5265636f763a20696e636f6e73697374656e7420617272617973000000000000604482015290519081900360640190fd5b60005b8181146112065785858281811061141557fe5b905060200201356001600160a01b03166001600160a01b03166323b872dd308a8a8581811061144057fe5b905060200201356001600160a01b031687878681811061145c57fe5b905060200201356040518463ffffffff1660e01b815260040180846001600160a01b03168152602001836001600160a01b031681526020018281526020019350505050600060405180830381600087803b1580156114b957600080fd5b505af11580156114cd573d6000803e3d6000fd5b50505050806001019050611402565b60025490565b6114ed610cb86115a0565b6000805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383811691821780845560405192939116917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a350565b60035460ff1615610cc5576040805162461bcd60e51b815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015290519081900360640190fd5b3390565b600060606115b183611d6c565b6115ba83612016565b505060c081015160e0909101519091565b5490565b815460009081908310611629576040805162461bcd60e51b815260206004820152601c60248201527f456e756d4d61703a20696e646578206f7574206f6620626f756e647300000000604482015290519081900360640190fd5b600084600001848154811061163a57fe5b906000526020600020906002020190508060000154816001015492509250509250929050565b306001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561169957600080fd5b505afa1580156116ad573d6000803e3d6000fd5b505050506040513d60208110156116c357600080fd5b50516001600160a01b03828116911614611724576040805162461bcd60e51b815260206004820152601660248201527f4f776e61626c653a206e6f7420746865206f776e657200000000000000000000604482015290519081900360640190fd5b50565b61172f6120b3565b6003805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6117626115a0565b604080516001600160a01b039092168252519081900360200190a1565b6000818152600183016020526040812054801561185357835460001980830191908101906000908790839081106117b257fe5b90600052602060002090600202019050808760000184815481106117d257fe5b60009182526020808320845460029093020191825560019384015491840191909155835482528983019052604090209084019055865487908061181157fe5b60008281526020808220600260001990940193840201828155600190810183905592909355888152898201909252604082209190915594506118599350505050565b60009150505b92915050565b60005b825181101561194557600083828151811061187957fe5b6020026020010151905060006001600160a01b0316816001600160a01b031614156118eb576040805162461bcd60e51b815260206004820152601860248201527f53616c653a207a65726f206164647265737320746f6b656e0000000000000000604482015290519081900360640190fd5b60008383815181106118f957fe5b6020026020010151905080600014156119255761191f866001600160a01b03841661177f565b5061193b565b611939866001600160a01b0384168361210a565b505b5050600101611862565b507f000000000000000000000000000000000000000000000000000000000000000a611970846115cb565b11156119c3576040805162461bcd60e51b815260206004820152601560248201527f53616c653a20746f6f206d616e7920746f6b656e730000000000000000000000604482015290519081900360640190fd5b505050565b82611a1a576040805162461bcd60e51b815260206004820152601160248201527f53616c653a207a65726f20737570706c79000000000000000000000000000000604482015290519081900360640190fd5b7f0000000000000000000000000000000000000000000000000000000000000019611a4560046115cb565b10611a97576040805162461bcd60e51b815260206004820152601360248201527f53616c653a20746f6f206d616e7920736b757300000000000000000000000000604482015290519081900360640190fd5b611aa26004856121a4565b611af3576040805162461bcd60e51b815260206004820152601960248201527f53616c653a20736b7520616c7265616479206372656174656400000000000000604482015290519081900360640190fd5b6001600160a01b03811615611b6557611b14816001600160a01b03166121ee565b611b65576040805162461bcd60e51b815260206004820152601b60248201527f53616c653a206e6f6e2d636f6e74726163742072656365697665720000000000604482015290519081900360640190fd5b60008481526006602090815260409182902085815560018101869055600281018590556003810180546001600160a01b03861673ffffffffffffffffffffffffffffffffffffffff1990911681179091558351888152928301879052828401869052606083015291517f38bd4aabce684540cd61351b91f2f5facf9d6963934347e25aab93d87ae7ac149181900360800190a15050505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526119c39084906121f4565b611c87611548565b6003805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586117626115a0565b611cc681611d6c565b611ccf81612016565b611cd8816123fc565b611ce18161254b565b6117248161261f565b60025415611d3f576040805162461bcd60e51b815260206004820152601260248201527f537461727461626c653a20737461727465640000000000000000000000000000604482015290519081900360640190fd5b426002557f27029695aa5f602a4ee81f4c32dfa86e562f200a17966496f3a7c3f2ec0f94176117626115a0565b60208101516001600160a01b0316611dcb576040805162461bcd60e51b815260206004820152601c60248201527f53616c653a207a65726f206164647265737320726563697069656e7400000000604482015290519081900360640190fd5b60408101516001600160a01b0316611e2a576040805162461bcd60e51b815260206004820152601860248201527f53616c653a207a65726f206164647265737320746f6b656e0000000000000000604482015290519081900360640190fd5b6080810151611e80576040805162461bcd60e51b815260206004820152601c60248201527f53616c653a207a65726f207175616e7469747920707572636861736500000000604482015290519081900360640190fd5b606081015160009081526006602052604090208054611ee6576040805162461bcd60e51b815260206004820152601660248201527f53616c653a206e6f6e2d6578697374656e7420736b7500000000000000000000604482015290519081900360640190fd5b816080015181600201541015611f43576040805162461bcd60e51b815260206004820152601860248201527f53616c653a2061626f7665206d6178207175616e746974790000000000000000604482015290519081900360640190fd5b805460001914611faa57816080015181600101541015611faa576040805162461bcd60e51b815260206004820152601960248201527f53616c653a20696e73756666696369656e7420737570706c7900000000000000604482015290519081900360640190fd5b60408201516001600160a01b0316611fc56004830182612b08565b6119c3576040805162461bcd60e51b815260206004820152601c60248201527f53616c653a206e6f6e2d6578697374656e7420736b7520746f6b656e00000000604482015290519081900360640190fd5b60608101516000908152600660205260409020805461207c576040805162461bcd60e51b815260206004820152601560248201527f53616c653a20756e737570706f7274656420534b550000000000000000000000604482015290519081900360640190fd5b60048101600061208c8483612b20565b90506120a5846080015182612b9090919063ffffffff16565b60c090940193909352505050565b60035460ff16610cc5576040805162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015290519081900360640190fd5b60008281526001840160205260408120548061216f57505060408051808201825283815260208082018481528654600181810189556000898152848120955160029093029095019182559151908201558654868452818801909252929091205561219d565b8285600001600183038154811061218257fe5b90600052602060002090600202016001018190555060009150505b9392505050565b60006121b08383612b08565b6121e657508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611859565b506000611859565b3b151590565b816122076001600160a01b0382166121ee565b612258576040805162461bcd60e51b815260206004820152601a60248201527f4552433230577261707065723a206e6f6e2d636f6e7472616374000000000000604482015290519081900360640190fd5b600080826001600160a01b0316846040518082805190602001908083835b602083106122b357805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101612276565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612315576040519150601f19603f3d011682016040523d82523d6000602084013e61231a565b606091505b50915091508115612399578051156123945780806020019051602081101561234157600080fd5b5051612394576040805162461bcd60e51b815260206004820152601e60248201527f4552433230577261707065723a206f7065726174696f6e206661696c65640000604482015290519081900360640190fd5b6123f5565b80516123ec576040805162461bcd60e51b815260206004820152601e60248201527f4552433230577261707065723a206f7065726174696f6e206661696c65640000604482015290519081900360640190fd5b80518082602001fd5b5050505050565b60408101516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee141561251f578060c0015134101561247e576040805162461bcd60e51b815260206004820152601660248201527f53616c653a20696e73756666696369656e742045544800000000000000000000604482015290519081900360640190fd5b60015460c08201516040516001600160a01b039092169181156108fc0291906000818181858888f193505050501580156124bc573d6000803e3d6000fd5b5060006124d68260c0015134612be990919063ffffffff16565b905080156125195781516040516001600160a01b039091169082156108fc029083906000818181858888f19350505050158015612517573d6000803e3d6000fd5b505b50611724565b61172461252a6115a0565b60015460c084015160408501516001600160a01b0390811693921690612c46565b61255481612cce565b60208181015160608301516000908152600790925260408083205460808086015183517f5cfa92970000000000000000000000000000000000000000000000000000000081526001600160a01b0395861660048201526024810193909352604483015260648201526084810184905290517f00000000000000000000000087a3747c9942d8351cc85aac2f94807b27a37c0d90921692635cfa92979260a48084019382900301818387803b15801561260b57600080fd5b505af11580156123f5573d6000803e3d6000fd5b806060015181604001516001600160a01b031682600001516001600160a01b03167f29f844483ca6b10b5c0611d039afc15ce8f6380e905307b381c3a8ee4e90e11e846020015185608001518660a001518760c001518860e001518961010001518a610120015160405160200180848051906020019060200280838360005b838110156126b657818101518382015260200161269e565b50505050905001838051906020019060200280838360005b838110156126e65781810151838201526020016126ce565b50505050905001828051906020019060200280838360005b838110156127165781810151838201526020016126fe565b50505050905001935050505060405160208183030381529060405260405180866001600160a01b031681526020018581526020018060200184815260200180602001838103835286818151815260200191508051906020019080838360005b8381101561278d578181015183820152602001612775565b50505050905090810190601f1680156127ba5780820380516001836020036101000a031916815260200191505b50838103825284518152845160209182019186019080838360005b838110156127ed5781810151838201526020016127d5565b50505050905090810190601f16801561281a5780820380516001836020036101000a031916815260200191505b5097505050505050505060405180910390a460608101516000908152600660205260409020600301546001600160a01b03168015612b04576361eceae860e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916816001600160a01b03166361eceae8846000015185602001518660400151876060015188608001518960a001518a60c001518b60e001518c61010001518d61012001516040518b63ffffffff1660e01b8152600401808b6001600160a01b031681526020018a6001600160a01b03168152602001896001600160a01b031681526020018881526020018781526020018060200186815260200180602001806020018060200185810385528a818151815260200191508051906020019080838360005b8381101561295357818101518382015260200161293b565b50505050905090810190601f1680156129805780820380516001836020036101000a031916815260200191505b508581038452885181528851602091820191808b01910280838360005b838110156129b557818101518382015260200161299d565b50505050905001858103835287818151815260200191508051906020019060200280838360005b838110156129f45781810151838201526020016129dc565b50505050905001858103825286818151815260200191508051906020019060200280838360005b83811015612a33578181015183820152602001612a1b565b505050509050019e505050505050505050505050505050602060405180830381600087803b158015612a6457600080fd5b505af1158015612a78573d6000803e3d6000fd5b505050506040513d6020811015612a8e57600080fd5b50517fffffffff000000000000000000000000000000000000000000000000000000001614612b04576040805162461bcd60e51b815260206004820152601a60248201527f53616c653a206e6f74696669636174696f6e2072656675736564000000000000604482015290519081900360640190fd5b5050565b60009081526001919091016020526040902054151590565b6040820151600090612b3c9083906001600160a01b0316612d19565b905080611859576040805162461bcd60e51b815260206004820152601f60248201527f53616c653a20756e737570706f72746564207061796d656e7420746f6b656e00604482015290519081900360640190fd5b600082612b9f57506000611859565b82820282848281612bac57fe5b041461219d5760405162461bcd60e51b8152600401808060200182810382526021815260200180612e1b6021913960400191505060405180910390fd5b600082821115612c40576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905261111d9085906121f4565b60608101516000908152600660205260409020805460001914612b045760808201516001820154612cfe91612be9565b60608301516000908152600660205260409020600101555050565b600081815260018301602052604081205480612d7c576040805162461bcd60e51b815260206004820152601860248201527f456e756d4d61703a206e6f6e6578697374656e74206b65790000000000000000604482015290519081900360640190fd5b836000016001820381548110612d8e57fe5b90600052602060002090600202016001015491505092915050565b60405180610140016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008019168152602001600081526020016060815260200160008152602001606081526020016060815260200160608152509056fe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a26469706673582212204d8cb75b26991c2fd95de34bbfcb733e5c728a2668a653399596a37a352a4c8564736f6c63430007060033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000087a3747c9942d8351cc85aac2f94807b27a37c0d00000000000000000000000039fa29ede121b06dce3674e97970caa539afc9570000000000000000000000000000000000000000000000000000000000000019000000000000000000000000000000000000000000000000000000000000000a

-----Decoded View---------------
Arg [0] : vouchersContract_ (address): 0x87a3747C9942d8351Cc85AaC2f94807B27A37c0D
Arg [1] : payoutWallet (address): 0x39FA29EdE121b06dCe3674E97970caa539AFc957
Arg [2] : skusCapacity (uint256): 25
Arg [3] : tokensPerSkuCapacity (uint256): 10

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 00000000000000000000000087a3747c9942d8351cc85aac2f94807b27a37c0d
Arg [1] : 00000000000000000000000039fa29ede121b06dce3674e97970caa539afc957
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000019
Arg [3] : 000000000000000000000000000000000000000000000000000000000000000a


Deployed Bytecode Sourcemap

70469:2422:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;52638:627;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;52638:627:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;52638:627:0;;-1:-1:-1;52638:627:0;-1:-1:-1;52638:627:0;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;70604:46;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;70604:46:0;;:::i;:::-;;;;;;;;;;;;;;;;54089:1056;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;54089:1056:0;;:::i;:::-;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;54089:1056:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;47657:117;;;;;;;;;;;;;:::i;:::-;;70544:51;;;;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;70544:51:0;;;;;;;;;;;;;;45120:98;;;;;;;;;;;;;:::i;21026:18::-;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;48539:967;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;48539:967:0;;;;;;;;-1:-1:-1;48539:967:0;;-1:-1:-1;;48539:967:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;48539:967:0;;-1:-1:-1;48539:967:0;;-1:-1:-1;;;;;48539:967:0:i;55282:112::-;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18576:268;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;18576:268:0;-1:-1:-1;;;;;18576:268:0;;:::i;72235:402::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;72235:402:0;;;;;;;;;;;;;;;;;:::i;68166:492::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;68166:492:0;;-1:-1:-1;68166:492:0;-1:-1:-1;68166:492:0;:::i;47263:113::-;;;;;;;;;;;;;:::i;18287:35::-;;;;;;;;;;;;;:::i;17126:96::-;;;;;;;;;;;;;:::i;45225:69::-;;;;;;;;;;;;;:::i;50515:554::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;50515:554:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;50515:554:0;;-1:-1:-1;50515:554:0;-1:-1:-1;50515:554:0;:::i;46859:122::-;;;;;;;;;;;;;:::i;69484:522::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;69484:522:0;;-1:-1:-1;69484:522:0;-1:-1:-1;69484:522:0;:::i;20164:87::-;;;;;;;;;;;;;:::i;17469:201::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;17469:201:0;-1:-1:-1;;;;;17469:201:0;;:::i;52638:627::-;52866:18;52886:28;19863:10;;19877:1;19863:15;;19855:50;;;;;-1:-1:-1;;;19855:50:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;52927:19:::1;:17;:19::i;:::-;52957:28;;:::i;:::-;53017:12;:10;:12::i;:::-;-1:-1:-1::0;;;;;52996:33:0;;::::1;::::0;;53040:30;;::::1;:18;::::0;;::::1;:30:::0;;;;53081:22;;::::1;:14;::::0;;::::1;:22:::0;;;;53114:12:::1;::::0;::::1;:18:::0;;;53143:17:::1;::::0;::::1;:28:::0;;;53182;;::::1;::::0;::::1;::::0;;::::1;::::0;::::1;::::0;;;;;;;;;;;53202:8;;;;;;53182:28;::::1;53202:8:::0;;;;53182:28;::::1;;::::0;::::1;::::0;;;;-1:-1:-1;;;;53182:17:0::1;::::0;::::1;:28:::0;53230:27:::1;53182:8:::0;53230:17:::1;:27::i;:::-;53223:34;;;;;52638:627:::0;;;;;;;;;:::o;70604:46::-;;;;;;;;;;;;;:::o;54089:1056::-;54204:19;54480:14;;;:9;:14;;;;;54204:19;;;;;;54365:23;;;;54204:19;54522:23;:14;;;:21;:23::i;:::-;54572:19;;;-1:-1:-1;54505:40:0;-1:-1:-1;54610:16:0;54602:51;;;;;-1:-1:-1;;;54602:51:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;54682:23;;;;54741:30;;;;54806:29;;;;54682:23;;-1:-1:-1;54741:30:0;-1:-1:-1;;;;;;54806:29:0;;-1:-1:-1;54871:6:0;54857:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;54857:21:0;;54848:30;;54912:6;54898:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;54898:21:0;;54889:30;;54935:9;54930:208;54954:6;54950:1;:10;54930:208;;;54983:13;;55015:20;:14;;;55033:1;55015:17;:20::i;:::-;54982:53;;;;55078:5;55070:14;;55050:6;55057:1;55050:9;;;;;;;;;;;;;:35;-1:-1:-1;;;;;55050:35:0;;;-1:-1:-1;;;;;55050:35:0;;;;;55120:5;55112:14;;55100:6;55107:1;55100:9;;;;;;;;;;;;;;;;;:26;-1:-1:-1;;54962:3:0;;54930:208;;;;54089:1056;;;;;;;;;:::o;47657:117::-;19863:10;;19855:50;;;;;-1:-1:-1;;;19855:50:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;47714:31:::1;47732:12;:10;:12::i;:::-;47714:17;:31::i;:::-;47756:10;:8;:10::i;:::-;47657:117::o:0;70544:51::-;;;:::o;45120:98::-;45173:44;45120:98;:::o;21026:18::-;;;;;;:::o;48539:967::-;48688:31;48706:12;:10;:12::i;48688:31::-;48747:13;;48789;;48779:23;;48771:61;;;;;-1:-1:-1;;;48771:61:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;48843:23;48869:14;;;:9;:14;;;;;48902:19;;48894:59;;;;;-1:-1:-1;;;48894:59:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;49000:14;;;49029:11;49025:419;;49057:21;49081:20;:11;:18;:20::i;:::-;49057:44;;49121:9;49116:240;49140:13;49136:1;:17;49116:240;;;49260:13;49279:17;:11;49260:13;49279:14;:17::i;:::-;-1:-1:-1;49259:37:0;-1:-1:-1;49315:25:0;:11;49259:37;49315:18;:25::i;:::-;-1:-1:-1;;49155:3:0;;49116:240;;;;49025:419;;;;49388:44;49404:11;49417:6;49425;49388:15;:44::i;:::-;49478:3;49461:37;49483:6;49491;49461:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;48539:967;;;;;;:::o;55282:112::-;55333:21;55374:5;:12;;55367:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;55282:112;:::o;18576:268::-;18650:31;18668:12;:10;:12::i;18650:31::-;-1:-1:-1;;;;;18700:27:0;;18692:60;;;;;-1:-1:-1;;;18692:60:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;18763:12;:28;;-1:-1:-1;;18763:28:0;-1:-1:-1;;;;;18763:28:0;;;;;;;;;;;18807:29;;;18823:12;;;;18807:29;;;;;;;;;;;;;18576:268;:::o;72235:402::-;72400:31;72418:12;:10;:12::i;72400:31::-;72450:16;-1:-1:-1;;;;;72450:27:0;;72478:7;72450:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;72450:36:0;72442:75;;;;;-1:-1:-1;;;72442:75:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;72528:16;;;;:11;:16;;;;;:26;;;72565:64;;72540:3;;72581:11;;72594:22;;72565:10;:64::i;:::-;72235:402;;;;:::o;68166:492::-;68335:31;68353:12;:10;:12::i;68335:31::-;68394:8;68428:23;;;:51;;;;-1:-1:-1;68455:24:0;;;68428:51;68420:90;;;;;-1:-1:-1;;;68420:90:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;68526:9;68521:130;68546:6;68541:1;:11;68521:130;;68574:65;68615:8;;68624:1;68615:11;;;;;;;;;;;;;-1:-1:-1;;;;;68615:11:0;68628:7;;68636:1;68628:10;;;;;;;;;;;;;68588:6;;68595:1;68588:9;;;;;;;;;;;;;-1:-1:-1;;;;;68588:9:0;-1:-1:-1;;;;;68574:40:0;;;:65;;;;;:::i;:::-;68554:3;;68521:130;;;;68166:492;;;;;;;:::o;47263:113::-;19863:10;;19855:50;;;;;-1:-1:-1;;;19855:50:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;47318:31:::1;47336:12;:10;:12::i;47318:31::-;47360:8;:6;:8::i;18287:35::-:0;;;-1:-1:-1;;;;;18287:35:0;;:::o;17126:96::-;17181:7;17208:6;-1:-1:-1;;;;;17208:6:0;17126:96;:::o;45225:69::-;-1:-1:-1;;45225:69:0;:::o;50515:554::-;19863:10;;19855:50;;;;;-1:-1:-1;;;19855:50:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;50743:19:::1;:17;:19::i;:::-;50773:28;;:::i;:::-;50833:12;:10;:12::i;:::-;-1:-1:-1::0;;;;;50812:33:0;;::::1;::::0;;50856:30;;::::1;:18;::::0;;::::1;:30:::0;;;;50897:22;;::::1;:14;::::0;;::::1;:22:::0;;;;50930:12:::1;::::0;::::1;:18:::0;;;50959:17:::1;::::0;::::1;:28:::0;;;50998;;::::1;::::0;::::1;::::0;;::::1;::::0;::::1;::::0;;;;;;;;;;;51018:8;;;;;;50998:28;::::1;51018:8:::0;;;;50998:28;::::1;;::::0;::::1;::::0;;;;-1:-1:-1;;;;50998:17:0::1;::::0;::::1;:28:::0;51039:22:::1;50998:8:::0;51039:12:::1;:22::i;:::-;19916:1;50515:554:::0;;;;;;:::o;46859:122::-;46902:31;46920:12;:10;:12::i;46902:31::-;46944:8;:6;:8::i;69484:522::-;69658:31;69676:12;:10;:12::i;69658:31::-;69717:8;69751:26;;;:55;;;;-1:-1:-1;69781:25:0;;;69751:55;69743:94;;;;;-1:-1:-1;;;69743:94:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;69853:9;69848:151;69873:6;69868:1;:11;69848:151;;69920:9;;69930:1;69920:12;;;;;;;;;;;;;-1:-1:-1;;;;;69920:12:0;-1:-1:-1;;;;;69901:45:0;;69955:4;69962:8;;69971:1;69962:11;;;;;;;;;;;;;-1:-1:-1;;;;;69962:11:0;69975:8;;69984:1;69975:11;;;;;;;;;;;;;69901:86;;;;;;;;;;;;;-1:-1:-1;;;;;69901:86:0;;;;;;-1:-1:-1;;;;;69901:86:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;69881:3;;;;;69848:151;;20164:87;20233:10;;20164:87;:::o;17469:201::-;17549:31;17567:12;:10;:12::i;17549:31::-;17591:6;:17;;-1:-1:-1;;17591:17:0;-1:-1:-1;;;;;17591:17:0;;;;;;;;;17624:38;;17591:17;;17645:6;;;17624:38;;17591:6;17624:38;17469:201;:::o;21122:98::-;21185:6;;;;21184:7;21176:36;;;;;-1:-1:-1;;;21176:36:0;;;;;;;;;;;;;;;;;;;;;;;;;;;14756:106;14844:10;14756:106;:::o;41168:297::-;41256:18;41276:28;41317:21;41329:8;41317:11;:21::i;:::-;41349:18;41358:8;41349;:18::i;:::-;-1:-1:-1;;41393:19:0;;;;41437:20;;;;;41393:19;;41168:297::o;8435:109::-;8518:18;;8435:109::o;8909:269::-;9013:18;;8976:7;;;;9013:26;-1:-1:-1;9005:67:0;;;;;-1:-1:-1;;;9005:67:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;9085:22;9110:3;:11;;9122:5;9110:18;;;;;;;;;;;;;;;;;;9085:43;;9147:5;:9;;;9158:5;:11;;;9139:31;;;;;8909:269;;;;;:::o;17801:138::-;17892:4;-1:-1:-1;;;;;17892:10:0;;:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;17892:12:0;-1:-1:-1;;;;;17881:23:0;;;;;;17873:58;;;;;-1:-1:-1;;;17873:58:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;17801:138;:::o;21744:135::-;21792:16;:14;:16::i;:::-;21819:6;:14;;-1:-1:-1;;21819:14:0;;;21849:22;21858:12;:10;:12::i;:::-;21849:22;;;-1:-1:-1;;;;;21849:22:0;;;;;;;;;;;;;;21744:135::o;6579:1553::-;6643:4;6778:16;;;:11;;;:16;;;;;;6811:13;;6807:1318;;7255:18;;-1:-1:-1;;7208:12:0;;;;7255:22;;;;7184:21;;7255:3;;:22;;7551;;;;;;;;;;;;;;;;7522:51;;7697:9;7668:3;:11;;7680:13;7668:26;;;;;;;;;;;;;;;;:38;;:26;;;;;:38;;;;;;;;;;;;;;;7786:13;;7774:26;;:11;;;:26;;;;;7803:17;;;7774:46;;7929:17;;7774:3;;7929:17;;;;;;;;;;;;;;-1:-1:-1;;7929:17:0;;;;;;;;;;;;;;;;;;;;;8024:16;;;:11;;;:16;;;;;;8017:23;;;;7929:17;-1:-1:-1;8057:11:0;;-1:-1:-1;;;;8057:11:0;6807:1318;8108:5;8101:12;;;6579:1553;;;;;:::o;57571:679::-;57746:9;57741:412;57765:6;:13;57761:1;:17;57741:412;;;57800:13;57816:6;57823:1;57816:9;;;;;;;;;;;;;;57800:25;;57865:1;-1:-1:-1;;;;;57848:19:0;:5;-1:-1:-1;;;;;57848:19:0;;;57840:56;;;;;-1:-1:-1;;;57840:56:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;57911:13;57927:6;57934:1;57927:9;;;;;;;;;;;;;;57911:25;;57955:5;57964:1;57955:10;57951:191;;;57986:43;:11;-1:-1:-1;;;;;58013:14:0;;57986:18;:43::i;:::-;;57951:191;;;58070:56;:11;-1:-1:-1;;;;;58094:14:0;;58119:5;58070:15;:56::i;:::-;;57951:191;-1:-1:-1;;57780:3:0;;57741:412;;;;58195:21;58171:20;:11;:18;:20::i;:::-;:45;;58163:79;;;;;-1:-1:-1;;;58163:79:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;57571:679;;;:::o;56191:895::-;56387:16;56379:46;;;;;-1:-1:-1;;;56379:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;56461:13;56444:14;:5;:12;:14::i;:::-;:30;56436:62;;;;;-1:-1:-1;;;56436:62:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;56517:14;:5;56527:3;56517:9;:14::i;:::-;56509:52;;;;;-1:-1:-1;;;56509:52:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;56576:35:0;;;56572:142;;56636:34;:21;-1:-1:-1;;;;;56636:32:0;;:34::i;:::-;56628:74;;;;;-1:-1:-1;;;56628:74:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;56724:23;56750:14;;;:9;:14;;;;;;;;;56775:33;;;56819:23;;;:37;;;56867:30;;;:55;;;56933:29;;;:53;;-1:-1:-1;;;;;56933:53:0;;-1:-1:-1;;56933:53:0;;;;;;;;57002:76;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;56191:895;;;;;:::o;1919:229::-;2081:58;;;-1:-1:-1;;;;;2081:58:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2104:23;2081:58;;;2046:94;;2074:5;;2046:27;:94::i;21470:133::-;21516:19;:17;:19::i;:::-;21546:6;:13;;-1:-1:-1;;21546:13:0;21555:4;21546:13;;;21575:20;21582:12;:10;:12::i;41573:231::-;41653:21;41665:8;41653:11;:21::i;:::-;41685:18;41694:8;41685;:18::i;:::-;41714;41723:8;41714;:18::i;:::-;41743:19;41753:8;41743:9;:19::i;:::-;41773:23;41787:8;41773:13;:23::i;20392:134::-;19656:10;;:15;19648:46;;;;;-1:-1:-1;;;19648:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;20466:15:::1;20453:10;:28:::0;20497:21:::1;20505:12;:10;:12::i;59208:864::-:0;59309:18;;;;-1:-1:-1;;;;;59309:32:0;59301:73;;;;;-1:-1:-1;;;59301:73:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;59393:14;;;;-1:-1:-1;;;;;59393:28:0;59385:65;;;;;-1:-1:-1;;;59385:65:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;59469:17;;;;59461:63;;;;;-1:-1:-1;;;59461:63:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;59571:12;;;;59535:23;59561;;;:9;:23;;;;;59603:19;;59595:59;;;;;-1:-1:-1;;;59595:59:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;59707:8;:17;;;59673:7;:30;;;:51;;59665:88;;;;;-1:-1:-1;;;59665:88:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;59768:19;;-1:-1:-1;;59768:39:0;59764:154;;59859:8;:17;;;59832:7;:23;;;:44;;59824:82;;;;;-1:-1:-1;;;59824:82:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;59963:14;;;;-1:-1:-1;;;;;59955:23:0;59998:33;:14;;;59955:23;59998;:33::i;:::-;59990:74;;;;;-1:-1:-1;;;59990:74:0;;;;;;;;;;;;;;;;;;;;;;;;;;;64810:394;64936:12;;;;64900:23;64926;;;:9;:23;;;;;64968:19;;64960:58;;;;;-1:-1:-1;;;64960:58:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;65058:14;;;65029:26;65103:28;65114:8;65058:14;65103:10;:28::i;:::-;65083:48;;65164:32;65178:8;:17;;;65164:9;:13;;:32;;;;:::i;:::-;65142:19;;;;:54;;;;-1:-1:-1;;;64810:394:0:o;21228:98::-;21287:6;;;;21279:39;;;;;-1:-1:-1;;;21279:39:0;;;;;;;;;;;;;;;;;;;;;;;;;;;5675:729;5785:4;5920:16;;;:11;;;:16;;;;;;5953:13;5949:448;;-1:-1:-1;;6050:34:0;;;;;;;;;;;;;;;;;;6033:52;;;;;;;;:11;:52;;;;;;;;;;;;;;;;;;;;;;;;6242:18;;6223:16;;;:11;;;:16;;;;;;;:37;6275:11;;5949:448;6353:5;6319:3;:11;;6342:1;6331:8;:12;6319:25;;;;;;;;;;;;;;;;;;:31;;:39;;;;6380:5;6373:12;;;5675:729;;;;;;:::o;11229:410::-;11292:4;11314:20;11323:3;11328:5;11314:8;:20::i;:::-;11309:323;;-1:-1:-1;11351:22:0;;;;;;;;:10;:22;;;;;;;;;;;;;11532:17;;11511:18;;;:11;;;:18;;;;;;:38;;;;11564:11;;11309:323;-1:-1:-1;11615:5:0;11608:12;;1106:387;1429:20;1477:8;;;1106:387::o;2675:892::-;2801:5;2826:19;-1:-1:-1;;;;;2826:17:0;;;:19::i;:::-;2818:58;;;;;-1:-1:-1;;;2818:58:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;2950:12;2964:17;2985:6;-1:-1:-1;;;;;2985:11:0;2997:8;2985:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2949:57;;;;3021:7;3017:543;;;3049:11;;:16;3045:124;;3105:4;3094:24;;;;;;;;;;;;;;;-1:-1:-1;3094:24:0;3086:67;;;;;-1:-1:-1;;;3086:67:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;3017:543;;;3260:11;;3256:97;;3297:40;;;-1:-1:-1;;;3297:40:0;;;;;;;;;;;;;;;;;;;;;;;;;;;3256:97;3484:4;3478:11;3529:4;3522;3518:2;3514:13;3507:27;3447:102;2675:892;;;;;:::o;65676:580::-;65765:14;;;;-1:-1:-1;;;;;65765:27:0;45173:44;65765:27;65761:488;;;65830:8;:19;;;65817:9;:32;;65809:67;;;;;-1:-1:-1;;;65809:67:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;65893:12;;65915:19;;;;65893:42;;-1:-1:-1;;;;;65893:12:0;;;;:42;;;;;65915:19;65893:12;:42;:12;:42;65915:19;65893:12;:42;;;;;;;;;;;;;;;;;;;;;65952:14;65969:34;65983:8;:19;;;65969:9;:13;;:34;;;;:::i;:::-;65952:51;-1:-1:-1;66024:11:0;;66020:87;;66056:18;;:35;;-1:-1:-1;;;;;66056:27:0;;;;:35;;;;;66084:6;;66056:18;:35;:18;:35;66084:6;66056:27;:35;;;;;;;;;;;;;;;;;;;;;66020:87;65761:488;;;;66139:98;66189:12;:10;:12::i;:::-;66203;;66217:19;;;;66153:14;;;;-1:-1:-1;;;;;66139:49:0;;;;:98;66203:12;;66139:49;:98::i;72671:217::-;72749:25;72765:8;72749:15;:25::i;:::-;72811:18;;;;;72843:12;;;;72831:25;;;;:11;:25;;;;;;;;72858:17;;;;;72785:95;;;;;-1:-1:-1;;;;;72785:95:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:16;:25;;;;;;:95;;;;;;;;;;72831:25;72785;:95;;;;;;;;;;;;;;;;;;;;;;;;;;61778:1323;61991:8;:12;;;61962:8;:14;;;-1:-1:-1;;;;;61873:337:0;61896:8;:18;;;-1:-1:-1;;;;;61873:337:0;;61929:8;:18;;;62018:8;:17;;;62050:8;:17;;;62082:8;:19;;;62133:8;:20;;;62155:8;:20;;;62177:8;:21;;;62116:83;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;61873:337;;;;-1:-1:-1;;;;;61873:337:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;61873:337:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;62265:12;;;;62223:29;62255:23;;;:9;:23;;;;;:45;;;-1:-1:-1;;;;;62255:45:0;62315:35;;62311:783;;62906:82;;;62393:595;;;62424:21;-1:-1:-1;;;;;62393:84:0;;62500:8;:18;;;62541:8;:18;;;62582:8;:14;;;62619:8;:12;;;62654:8;:17;;;62694:8;:17;;;62734:8;:19;;;62776:8;:20;;;62819:8;:20;;;62862:8;:21;;;62393:509;;;;;;;;;;;;;-1:-1:-1;;;;;62393:509:0;;;;;;-1:-1:-1;;;;;62393:509:0;;;;;;-1:-1:-1;;;;;62393:509:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;62393:509:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;62393:509:0;:595;;;62367:715;;;;;-1:-1:-1;;;62367:715:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;61778:1323;;:::o;8216:124::-;8287:4;8311:16;;;:11;;;;;:16;;;;;;:21;;;8216:124::o;66837:281::-;67023:14;;;;66946:17;;66996:44;;:6;;-1:-1:-1;;;;;67015:23:0;66996:10;:44::i;:::-;66988:53;-1:-1:-1;67060:14:0;67052:58;;;;;-1:-1:-1;;;67052:58:0;;;;;;;;;;;;;;;;;;;;;;;;;;;25566:220;25624:7;25648:6;25644:20;;-1:-1:-1;25663:1:0;25656:8;;25644:20;25687:5;;;25691:1;25687;:5;:1;25711:5;;;;;:10;25703:56;;;;-1:-1:-1;;;25703:56:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;25149:158;25207:7;25240:1;25235;:6;;25227:49;;;;;-1:-1:-1;;;25227:49:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;25294:5:0;;;25149:158::o;2156:266::-;2345:68;;;-1:-1:-1;;;;;2345:68:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2368:27;2345:68;;;2310:104;;2338:5;;2310:27;:104::i;60721:313::-;60843:12;;;;60807:23;60833;;;:9;:23;;;;;60871:19;;-1:-1:-1;;60871:39:0;60867:160;;60997:17;;;;60969:23;;;;:46;;:27;:46::i;:::-;60937:12;;;;60927:23;;;;:9;:23;;;;;:39;;:88;60721:313;;:::o;9339:302::-;9405:7;9444:16;;;:11;;;:16;;;;;;9479:13;9471:50;;;;;-1:-1:-1;;;9471:50:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;9575:3;:11;;9598:1;9587:8;:12;9575:25;;;;;;;;;;;;;;;;;;:31;;;9568:38;;;9339:302;;;;:::o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o

Swarm Source

ipfs://4d8cb75b26991c2fd95de34bbfcb733e5c728a2668a653399596a37a352a4c85

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.