false
true
0

Contract Address Details

0xBf58BaA50781DBDd8A0BA4cF86D7c052845bd7f6

Contract Name
Coins
Creator
0x6715c0–30b1a3 at 0x9ece8b–20f32c
Balance
0 PLS ( )
Tokens
Fetching tokens...
Transactions
5,710 Transactions
Transfers
0 Transfers
Gas Used
1,740,924,764
Last Balance Update
26325150
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
Coins




Optimization enabled
true
Compiler version
v0.8.20+commit.a1b79de6




Optimization runs
200
EVM Version
default




Verified at
2024-11-01T02:54:40.889947Z

Contract source code

// File: contracts/common/commonPulseWars.sol


pragma solidity 0.8.20;

/**
 * @title NFTType
 * @dev Enum representing different types of NFT categories
 */
enum NFTType {
    PULSICANS,
    MAXIS,
    NATIVES,
    FRENEMIES_VCs,
    FOUNDERS_OF_THE_FUTURE,
    POWER_ITEMS,
    CITIZENS
}

/**
 * @title NFTInfo
 * @dev Struct to represent NFT information
*/
struct NFTInfo {
    NFTType nftType;
    address minter;
}

/**
 * @title CitizenInfo
 * @dev Struct to represent Citizen NFT information
 */
struct CitizenInfo {
    address nftAddress;
    uint256 nftID;
}

/**
 * @title Badge
 * @dev struct to represent badge information
 */
struct Badge {
        string name;
        uint maxClaimable;
        uint totalClaimed;
    }

enum TradeCoinType {
        PULSECHAIN_COINS,
        NON_PULSECHAIN_COINS,
        BOTH
    }

 struct CoinInfo {
        string symbol;
        uint256 decimals;
        uint256 priceInDai;
        uint256 priceInDaiAtStart;
        TradeCoinType coinType;
    }

// File: contracts/interface/ICoins.sol


pragma solidity 0.8.20;


interface ICoins {
    // Event emitted when a new coin is added
    event CoinAdded(uint256 indexed id, string symbol, uint256 decimals, uint256 priceInDai, TradeCoinType tradeCoinType);

    event CoinPriceUpdated(uint256 indexed tokenId, uint256 newPrice);
    
    event DefaultSelectionRangeUpdated(uint256 total, uint256 pwCoins, uint256 npwCoins, uint256 defaultRandomNumber);
    
    function addCoin(TradeCoinType _tradeCoinType,string calldata symbol, uint256 _decimals, uint256 _priceInDai) external returns (uint256);

    //Get initial coin list
    function getInitialCoinList(TradeCoinType _tradeCoinType, uint256 _rn) external view returns (uint[4] memory);

    //default coin list
    function getDefaultCoinList(TradeCoinType _tradeCoinType, uint _nftID) external view returns (uint[4] memory);

    // Function to get information about a coin
    function getCoin(uint256 id) external view returns (CoinInfo memory);

    // Function to get all coin addresses
    function getAllCoins(uint256 start, uint count) external view returns (CoinInfo[] memory);

    // Function to get the total number of coins
    function getTotalCoins() external view returns (uint256);

    //swaps
    /**
    * @notice Calculate the amount of DAI tokens that can be obtained for a given amount of input tokens
    * @param tokenId The ID of the input token
    * @param tokenAmount The amount of the input token
    * @return The amount of DAI tokens that can be obtained
    */
    function getDaiOutputForToken(uint256 tokenId, uint256 tokenAmount) external view returns (uint256);

    /**
    * @notice Calculate the amount of input tokens required to obtain a specific amount of DAI tokens
    * @param tokenId The ID of the input token
    * @param daiAmount The desired amount of DAI tokens
    * @return The amount of input tokens required
    */
    function getTokenAmountForDaiOutput(uint256 tokenId, uint256 daiAmount) external view returns (uint256);

    /**
    * @notice Calculate the amount of output tokens that can be obtained for a given amount of DAI tokens
    * @param tokenId The ID of the output token
    * @param daiAmount The amount of DAI tokens to be exchanged
    * @return The amount of output tokens that can be obtained
    */
    function getTokenOutputForDai(uint256 tokenId, uint256 daiAmount) external view returns (uint256);

     /**
    * @notice Calculate the amount of output tokens that can be obtained for a given amount of DAI tokens based on the price at the begining price of token
    * @param tokenId The ID of the output token
    * @param daiAmount The amount of DAI tokens to be exchanged
    * @return The amount of output tokens that can be obtained
    */
    function getTokenOutputForDaiAtStart(uint256 tokenId, uint256 daiAmount) external view returns (uint256);

    /**
    * @notice Calculate the amount of DAI tokens required to obtain a specific amount of output tokens
    * @param tokenId The ID of the output token
    * @param tokenAmount The desired amount of output tokens
    * @return The amount of DAI tokens required
    */
    function getDaiAmountForTokenOutput(uint256 tokenId, uint256 tokenAmount) external view returns (uint256);  
}

// File: @openzeppelin/contracts@4.9.0/utils/Context.sol


// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev 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, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

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

// File: @openzeppelin/contracts@4.9.0/access/Ownable.sol


// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)

pragma solidity ^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 Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

// File: @openzeppelin/contracts@4.9.0/access/Ownable2Step.sol


// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)

pragma solidity ^0.8.0;


/**
 * @dev Contract module which provides 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} and {acceptOwnership}.
 *
 * This module is used through inheritance. It will make available all functions
 * from parent (Ownable).
 */
abstract contract Ownable2Step is Ownable {
    address private _pendingOwner;

    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Returns the address of the pending owner.
     */
    function pendingOwner() public view virtual returns (address) {
        return _pendingOwner;
    }

    /**
     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual override onlyOwner {
        _pendingOwner = newOwner;
        emit OwnershipTransferStarted(owner(), newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual override {
        delete _pendingOwner;
        super._transferOwnership(newOwner);
    }

    /**
     * @dev The new owner accepts the ownership transfer.
     */
    function acceptOwnership() public virtual {
        address sender = _msgSender();
        require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
        _transferOwnership(sender);
    }
}

// File: contracts/utils/Authorizable.sol

//SPDX-License-Identifier: MIT

pragma solidity 0.8.20;


contract Authorizable is Ownable2Step {

    mapping(address => bool) private authorized;

    modifier onlyAuthorized() {
        require(authorized[msg.sender] ||  owner() == msg.sender, "Not authorized");
        _;
    }
    
    function isAuthorised(address _authAdd) public view returns(bool _isAuth){
        _isAuth = (authorized[_authAdd] ||  owner() == _authAdd) ;
    }

    function addAuthorized(address _toAdd) onlyOwner public {
        require(_toAdd != address(0));
        authorized[_toAdd] = true;
    }

    function removeAuthorized(address _toRemove) onlyOwner public {
        require(_toRemove != msg.sender);
        authorized[_toRemove] = false;
    }

}
// File: contracts/libraries/CoinUtils.sol


pragma solidity 0.8.20;

/// @title CoinUtils Library
/// @dev Provides utility functions for handling and selecting coins randomly.
library CoinUtils {

    /// @notice Randomly selects 4 unique coins from a given category of coins.
    /// @param _rn The random seed number to generate random indices.
    /// @param categoryLength The number of coins available in the category.
    /// @param coinCategory An array containing the coin IDs of the category.
    /// @return An array containing the 4 randomly selected coin IDs.
    /// @dev The function requires that the category length is at least 4.
    function randomSelectionfromList(
        uint _rn,
        uint categoryLength,
        uint[] memory coinCategory
    ) internal pure returns (uint[4] memory) {
        require(categoryLength >= 4, "Not enough coins in the category");

        uint[4] memory selectedCoins;
        uint256 randBase = _rn;

        for (uint256 i = 0; i < 4; i++) {
            uint256 randomIndex = uint256(keccak256(abi.encodePacked(randBase, i))) % categoryLength;
            selectedCoins[i] = coinCategory[randomIndex];

            // Swap this element with the last unchosen element
            coinCategory[randomIndex] = coinCategory[categoryLength - 1];
            categoryLength--;

            randBase += selectedCoins[i]; // Shuffle the randomness base
        }

        return selectedCoins;
    }

    /// @notice Randomly selects 4 unique coin IDs from a range of available coins.
    /// @param _rn The random seed number to generate random indices.
    /// @param len The total number of available coin IDs to select from.
    /// @return An array containing the 4 randomly selected coin IDs.
    /// @dev The function requires that the total number of available coins (`len`) is at least 4.
    function getRandomSelectionFromAll(uint _rn, uint len) internal pure returns (uint[4] memory) {
        uint[4] memory selectedCoins;
        require(len >= 4, "Not enough coins available");

        uint256 coinCount = 0;
        uint256 randBase = _rn;

        while (coinCount < 4) {
            uint256 randomId = (uint256(keccak256(abi.encodePacked(randBase))) % len) + 1;

            bool alreadySelected = false;
            for (uint256 i = 0; i < coinCount; i++) {
                if (selectedCoins[i] == randomId) {
                    alreadySelected = true;
                    break;
                }
            }

            if (alreadySelected) {
                randBase++;
                continue;
            }

            selectedCoins[coinCount] = randomId;
            coinCount++;
            randBase++;
        }

        return selectedCoins;
    }
}

// File: contracts/core/Coins.sol


pragma solidity 0.8.20;




/// @title Coins Contract
/// @dev Manages the in-game coins, their prices, and provides utilities for coin selection.
contract Coins is ICoins, Authorizable {
    // ---- Structs -----

    /// @dev Struct to define the range for default coin selection.
    /// @param total The total number of coins to consider for default selection.
    /// @param pwCoins The number of PulseChain coins to select for default selection.
    /// @param npwCoins The number of Non-PulseChain coins to select for default selection.
    struct DefaultSelectionRange {
        uint total;
        uint pwCoins;
        uint npwCoins;
    }

    // ---- Variables ----

    /// @dev Total number of coins added to the contract.
    uint256 private totalCoins;
    /// @dev Mapping of coin ID to CoinInfo struct.
    mapping(uint256 => CoinInfo) public coins;
    /// @dev Array of PulseChain coin IDs.
    uint256[] public pulseChainCoinIds;
    /// @dev Array of Non-PulseChain coin IDs.
    uint256[] public nonPulseChainCoinIds;
    /// @dev Random number used for default coin selection.
    uint256 public defaultRandomNumber;
    /// @dev Struct defining the range for default coin selection.
    DefaultSelectionRange public defaultSelectionRange;
    /// @dev CoinInfo for DAI stablecoin (always available).
    CoinInfo public DAI_INFO =
        CoinInfo({
            symbol: "DAI",
            decimals: 18,
            priceInDai: 1 ether,
            priceInDaiAtStart: 1 ether,
            coinType: TradeCoinType.BOTH
        });

    // ---- Functions ----

    /// @notice Adds a new coin to the contract.
    /// @param _tradeCoinType The type of coin (PULSECHAIN_COINS or NON_PULSECHAIN_COINS).
    /// @param symbol The symbol of the coin.
    /// @param _decimals The number of decimals for the coin.
    /// @param _priceInDai The initial price of the coin in DAI.
    /// @return The ID of the newly added coin.
    function addCoin(
        TradeCoinType _tradeCoinType,
        string calldata symbol,
        uint256 _decimals,
        uint256 _priceInDai
    ) external override onlyAuthorized returns (uint256) {
        require(_tradeCoinType != TradeCoinType.BOTH, "Invalid Type");

        totalCoins++;
        coins[totalCoins] = CoinInfo({
            symbol: symbol,
            decimals: _decimals,
            priceInDai: _priceInDai,
            priceInDaiAtStart: 0,
            coinType: _tradeCoinType
        });
        if (_tradeCoinType == TradeCoinType.PULSECHAIN_COINS) {
            pulseChainCoinIds.push(totalCoins);
        } else {
            if (_tradeCoinType == TradeCoinType.NON_PULSECHAIN_COINS) {
                nonPulseChainCoinIds.push(totalCoins);
            }
        }
        emit CoinAdded(totalCoins, symbol, _decimals, _priceInDai, _tradeCoinType);
        return totalCoins;
    }

    /// @notice Records the initial prices of specified coins in DAI.
    /// @param coinsIndex An array of coin IDs for which to record prices.
    /// @param coinsPrice An array of corresponding initial prices in DAI.
    function recordInitPrice(uint[] memory coinsIndex, uint[] memory coinsPrice) public onlyAuthorized {
        require(coinsIndex.length == coinsPrice.length, "Arrays must be of the same length");
        require(coinsIndex.length <= totalCoins, "Array length exceeds total coins");

        for (uint i = 0; i < coinsIndex.length; i++) {
            require(coinsIndex[i] > 0 && coinsIndex[i] <= totalCoins, "Invalid coin index");
            coins[coinsIndex[i]].priceInDaiAtStart = coinsPrice[i];
        }
    }

    /// @notice Updates the prices of specified coins in DAI.
    /// @param tokenIds An array of coin IDs for which to update prices.
    /// @param newPrices An array of corresponding new prices in DAI.
    function updatePrices(uint256[] memory tokenIds, uint256[] memory newPrices) external onlyAuthorized {
        require(tokenIds.length == newPrices.length, "Arrays must be of the same length");

        for (uint256 i = 0; i < tokenIds.length; i++) {
            uint256 tokenId = tokenIds[i];
            uint256 newPrice = newPrices[i];
            require(tokenId > 0 && tokenId <= totalCoins, "Invalid token ID");

            coins[tokenId].priceInDai = newPrice;
            emit CoinPriceUpdated(tokenId, newPrice);
        }
    }

    /// @notice Sets the range for default coin selection.
    /// @param _total The total number of coins to consider for default selection.
    /// @param _pwLength The number of PulseChain coins to select for default selection.
    /// @param _npwLength The number of Non-PulseChain coins to select for default selection.
    /// @param _defaultRN A random number used as a base for default coin selection.
    function setDefaultSelectionRange(
        uint _total,
        uint _pwLength,
        uint _npwLength,
        uint _defaultRN
    ) public onlyAuthorized {
        require(_total <= totalCoins, "Invalid Total");
        require(_pwLength <= pulseChainCoinIds.length, "Invalid PW length");
        require(_npwLength <= nonPulseChainCoinIds.length, "Invalid CZ Length");

        defaultSelectionRange = DefaultSelectionRange({ total: _total, pwCoins: _pwLength, npwCoins: _npwLength });
        defaultRandomNumber = _defaultRN;
        emit DefaultSelectionRangeUpdated(_total, _pwLength, _npwLength, _defaultRN);
    }

    /// @notice Gets a list of initial coins based on the specified coin type and random number.
    /// @dev Used for initial coin allocation in the game.
    /// @param _tradeCoinType The type of coins to select (PULSECHAIN_COINS, NON_PULSECHAIN_COINS, or BOTH).
    /// @param _rn A random number used for selection.
    /// @return An array of 4 coin IDs selected randomly.
    function getInitialCoinList(
        TradeCoinType _tradeCoinType,
        uint256 _rn
    ) external view override returns (uint[4] memory) {
        uint256[4] memory selectedCoins;
        uint256[] storage coinCategory;
        uint256 categoryLength;
        if (_tradeCoinType == TradeCoinType.PULSECHAIN_COINS) {
            coinCategory = pulseChainCoinIds;
            categoryLength = pulseChainCoinIds.length;
            selectedCoins = CoinUtils.randomSelectionfromList(_rn, categoryLength, coinCategory);
        } else if (_tradeCoinType == TradeCoinType.NON_PULSECHAIN_COINS) {
            coinCategory = nonPulseChainCoinIds;
            categoryLength = nonPulseChainCoinIds.length;
            selectedCoins = CoinUtils.randomSelectionfromList(_rn, categoryLength, coinCategory);
        } else {
            selectedCoins = CoinUtils.getRandomSelectionFromAll(_rn, totalCoins);
        }

        return selectedCoins;
    }

    /// @notice Gets a list of default coins based on the specified coin type and NFT ID.
    /// @dev Used for providing a default portfolio when a user doesn't choose their own coins.
    /// @param _tradeCoinType The type of coins to select (PULSECHAIN_COINS, NON_PULSECHAIN_COINS, or BOTH).
    /// @param _nftID The ID of the NFT for which to select default coins.
    /// @return An array of 4 coin IDs selected based on the default range and NFT ID.
    function getDefaultCoinList(
        TradeCoinType _tradeCoinType,
        uint _nftID
    ) external view override returns (uint[4] memory) {
        uint256[4] memory selectedCoins;
        uint256[] storage coinCategory;
        uint256 categoryLength;

        if (_tradeCoinType == TradeCoinType.PULSECHAIN_COINS) {
            coinCategory = pulseChainCoinIds;
            categoryLength = defaultSelectionRange.pwCoins;
            selectedCoins = CoinUtils.randomSelectionfromList(
                defaultRandomNumber + _nftID,
                categoryLength,
                coinCategory
            );
        } else if (_tradeCoinType == TradeCoinType.NON_PULSECHAIN_COINS) {
            coinCategory = nonPulseChainCoinIds;
            categoryLength = defaultSelectionRange.npwCoins;
            selectedCoins = CoinUtils.randomSelectionfromList(
                defaultRandomNumber + _nftID,
                categoryLength,
                coinCategory
            );
        } else {
            selectedCoins = CoinUtils.getRandomSelectionFromAll(
                defaultRandomNumber + _nftID,
                defaultSelectionRange.total
            );
        }

        return selectedCoins;
    }

    /// @notice Gets information about a specific coin.
    /// @param id The ID of the coin.
    /// @return The CoinInfo struct for the specified coin ID.
    function getCoin(uint256 id) external view override returns (CoinInfo memory) {
        require(id > 0 && id <= totalCoins, "Coin ID out of range");
        return coins[id];
    }

    /// @notice Gets information about a range of coins.
    /// @param start The starting index of the range (inclusive).
    /// @param count The number of coins to retrieve.
    /// @return An array of CoinInfo structs for the specified range of coins.
    function getAllCoins(uint256 start, uint count) external view override returns (CoinInfo[] memory) {
        require(start >= 1 && start + count - 1 <= totalCoins, "Invalid range");

        CoinInfo[] memory allCoins = new CoinInfo[](count);
        for (uint256 i = 0; i < count; i++) {
            allCoins[i] = coins[start + i];
        }

        return allCoins;
    }

    /// @notice Gets information about a range of PulseChain coins.
    /// @param start The starting index of the range (inclusive).
    /// @param count The number of coins to retrieve.
    /// @return An array of CoinInfo structs for the specified range of PulseChain coins.
    function getPulseChainCoins(uint256 start, uint256 count) external view returns (CoinInfo[] memory) {
        uint256 length = pulseChainCoinIds.length;
        require(start < length && start + count <= length, "Invalid range");

        CoinInfo[] memory pulseChainCoins = new CoinInfo[](count);
        for (uint256 i = 0; i < count; i++) {
            pulseChainCoins[i] = coins[pulseChainCoinIds[start + i]];
        }

        return pulseChainCoins;
    }

    /// @notice Gets information about a range of Non-PulseChain coins.
    /// @param start The starting index of the range (inclusive).
    /// @param count The number of coins to retrieve.
    /// @return An array of CoinInfo structs for the specified range of Non-PulseChain coins.
    function getNonPulseChainCoins(uint256 start, uint256 count) external view returns (CoinInfo[] memory) {
        uint256 length = nonPulseChainCoinIds.length;
        require(start < length && start + count <= length, "Invalid range");

        CoinInfo[] memory nonPulseChainCoins = new CoinInfo[](count);
        for (uint256 i = 0; i < count; i++) {
            nonPulseChainCoins[i] = coins[nonPulseChainCoinIds[start + i]];
        }

        return nonPulseChainCoins;
    }

    /// @notice Gets an array of PulseChain coin IDs within a specific range.
    /// @param start The starting index of the range (inclusive).
    /// @param count The number of coin IDs to retrieve.
    /// @return An array of PulseChain coin IDs.
    function getPulseChainCoinIds(uint256 start, uint256 count) external view returns (uint256[] memory) {
        uint256 length = pulseChainCoinIds.length;
        require(start < length && start + count <= length, "Invalid range");

        uint256[] memory selectedIds = new uint256[](count);
        for (uint256 i = 0; i < count; i++) {
            selectedIds[i] = pulseChainCoinIds[start + i];
        }

        return selectedIds;
    }

    /// @notice Gets an array of Non-PulseChain coin IDs within a specific range.
    /// @param start The starting index of the range (inclusive).
    /// @param count The number of coin IDs to retrieve.
    /// @return An array of Non-PulseChain coin IDs.
    function getNonPulseChainCoinIds(uint256 start, uint256 count) external view returns (uint256[] memory) {
        uint256 length = nonPulseChainCoinIds.length;
        require(start < length && start + count <= length, "Invalid range");

        uint256[] memory selectedIds = new uint256[](count);
        for (uint256 i = 0; i < count; i++) {
            selectedIds[i] = nonPulseChainCoinIds[start + i];
        }

        return selectedIds;
    }

    /// @notice Gets the total number of coins added to the contract.
    /// @return The total number of coins.
    function getTotalCoins() external view override returns (uint256) {
        return totalCoins;
    }

    /// @notice Gets the total number of PulseChain coins added to the contract.
    /// @return The total number of PulseChain coins.
    function getTotalPulseChainCoins() external view returns (uint256) {
        return pulseChainCoinIds.length;
    }

    /// @notice Gets the total number of Non-PulseChain coins added to the contract.
    /// @return The total number of Non-PulseChain coins.
    function getTotalNonPulseChainCoins() external view returns (uint256) {
        return nonPulseChainCoinIds.length;
    }
    function getDaiOutputForToken(uint256 tokenId, uint256 tokenAmount) external view override returns (uint256) {
        require(tokenId > 0 && tokenId <= totalCoins, "Invalid token ID");
        CoinInfo memory token = coins[tokenId];

        // Normalize token amount to DAI's decimals
        uint256 normalizedTokenAmount = tokenAmount * (10 ** (18 - token.decimals));
        uint256 daiAmount = (normalizedTokenAmount * token.priceInDai) / (10 ** 18);

        return daiAmount;
    }

    function getTokenAmountForDaiOutput(uint256 tokenId, uint256 daiAmount) external view override returns (uint256) {
        require(tokenId > 0 && tokenId <= totalCoins, "Invalid token ID");
        CoinInfo memory token = coins[tokenId];

        // Normalize DAI amount to the token's decimals
        uint256 normalizedDaiAmount = daiAmount * (10 ** token.decimals);
        uint256 tokenAmount = normalizedDaiAmount / token.priceInDai;
        return tokenAmount;
    }

    function getTokenOutputForDai(uint256 tokenId, uint256 daiAmount) external view override returns (uint256) {
        require(tokenId > 0 && tokenId <= totalCoins, "Invalid token ID");
        CoinInfo memory token = coins[tokenId];

        // Normalize DAI amount to the token's decimals
        uint256 normalizedDaiAmount = daiAmount * (10 ** token.decimals);
        uint256 tokenAmount = normalizedDaiAmount / token.priceInDai;

        return tokenAmount;
    }

    /// @notice Calculates the amount of a specific coin that could have been bought with a given amount of DAI at the initial price.
    /// @param tokenId The ID of the coin.
    /// @param daiAmount The amount of DAI to spend.
    /// @return The amount of the specified coin that could have been bought with the DAI at the initial price.
    function getTokenOutputForDaiAtStart(uint256 tokenId, uint256 daiAmount) external view override returns (uint256) {
        require(tokenId > 0 && tokenId <= totalCoins, "Invalid token ID");
        CoinInfo memory token = coins[tokenId];

        // Normalize DAI amount to the token's decimals
        uint256 normalizedDaiAmount = daiAmount * (10 ** token.decimals);
        uint256 tokenAmount = normalizedDaiAmount / token.priceInDaiAtStart;

        return tokenAmount;
    }

    function getDaiAmountForTokenOutput(uint256 tokenId, uint256 tokenAmount) external view override returns (uint256) {
        require(tokenId > 0 && tokenId <= totalCoins, "Invalid token ID");
        CoinInfo memory token = coins[tokenId];

        // Normalize token amount to DAI's decimals
        uint256 normalizedTokenAmount = tokenAmount * (10 ** (18 - token.decimals));
        uint256 daiAmount = (normalizedTokenAmount * token.priceInDai) / (10 ** 18);

        return daiAmount;
    }
}
        

Contract ABI

[{"type":"event","name":"CoinAdded","inputs":[{"type":"uint256","name":"id","internalType":"uint256","indexed":true},{"type":"string","name":"symbol","internalType":"string","indexed":false},{"type":"uint256","name":"decimals","internalType":"uint256","indexed":false},{"type":"uint256","name":"priceInDai","internalType":"uint256","indexed":false},{"type":"uint8","name":"tradeCoinType","internalType":"enum TradeCoinType","indexed":false}],"anonymous":false},{"type":"event","name":"CoinPriceUpdated","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256","indexed":true},{"type":"uint256","name":"newPrice","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"DefaultSelectionRangeUpdated","inputs":[{"type":"uint256","name":"total","internalType":"uint256","indexed":false},{"type":"uint256","name":"pwCoins","internalType":"uint256","indexed":false},{"type":"uint256","name":"npwCoins","internalType":"uint256","indexed":false},{"type":"uint256","name":"defaultRandomNumber","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferStarted","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"symbol","internalType":"string"},{"type":"uint256","name":"decimals","internalType":"uint256"},{"type":"uint256","name":"priceInDai","internalType":"uint256"},{"type":"uint256","name":"priceInDaiAtStart","internalType":"uint256"},{"type":"uint8","name":"coinType","internalType":"enum TradeCoinType"}],"name":"DAI_INFO","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"acceptOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addAuthorized","inputs":[{"type":"address","name":"_toAdd","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"addCoin","inputs":[{"type":"uint8","name":"_tradeCoinType","internalType":"enum TradeCoinType"},{"type":"string","name":"symbol","internalType":"string"},{"type":"uint256","name":"_decimals","internalType":"uint256"},{"type":"uint256","name":"_priceInDai","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"symbol","internalType":"string"},{"type":"uint256","name":"decimals","internalType":"uint256"},{"type":"uint256","name":"priceInDai","internalType":"uint256"},{"type":"uint256","name":"priceInDaiAtStart","internalType":"uint256"},{"type":"uint8","name":"coinType","internalType":"enum TradeCoinType"}],"name":"coins","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"defaultRandomNumber","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"total","internalType":"uint256"},{"type":"uint256","name":"pwCoins","internalType":"uint256"},{"type":"uint256","name":"npwCoins","internalType":"uint256"}],"name":"defaultSelectionRange","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple[]","name":"","internalType":"struct CoinInfo[]","components":[{"type":"string","name":"symbol","internalType":"string"},{"type":"uint256","name":"decimals","internalType":"uint256"},{"type":"uint256","name":"priceInDai","internalType":"uint256"},{"type":"uint256","name":"priceInDaiAtStart","internalType":"uint256"},{"type":"uint8","name":"coinType","internalType":"enum TradeCoinType"}]}],"name":"getAllCoins","inputs":[{"type":"uint256","name":"start","internalType":"uint256"},{"type":"uint256","name":"count","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct CoinInfo","components":[{"type":"string","name":"symbol","internalType":"string"},{"type":"uint256","name":"decimals","internalType":"uint256"},{"type":"uint256","name":"priceInDai","internalType":"uint256"},{"type":"uint256","name":"priceInDaiAtStart","internalType":"uint256"},{"type":"uint8","name":"coinType","internalType":"enum TradeCoinType"}]}],"name":"getCoin","inputs":[{"type":"uint256","name":"id","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getDaiAmountForTokenOutput","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"uint256","name":"tokenAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getDaiOutputForToken","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"uint256","name":"tokenAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[4]","name":"","internalType":"uint256[4]"}],"name":"getDefaultCoinList","inputs":[{"type":"uint8","name":"_tradeCoinType","internalType":"enum TradeCoinType"},{"type":"uint256","name":"_nftID","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[4]","name":"","internalType":"uint256[4]"}],"name":"getInitialCoinList","inputs":[{"type":"uint8","name":"_tradeCoinType","internalType":"enum TradeCoinType"},{"type":"uint256","name":"_rn","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"","internalType":"uint256[]"}],"name":"getNonPulseChainCoinIds","inputs":[{"type":"uint256","name":"start","internalType":"uint256"},{"type":"uint256","name":"count","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple[]","name":"","internalType":"struct CoinInfo[]","components":[{"type":"string","name":"symbol","internalType":"string"},{"type":"uint256","name":"decimals","internalType":"uint256"},{"type":"uint256","name":"priceInDai","internalType":"uint256"},{"type":"uint256","name":"priceInDaiAtStart","internalType":"uint256"},{"type":"uint8","name":"coinType","internalType":"enum TradeCoinType"}]}],"name":"getNonPulseChainCoins","inputs":[{"type":"uint256","name":"start","internalType":"uint256"},{"type":"uint256","name":"count","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"","internalType":"uint256[]"}],"name":"getPulseChainCoinIds","inputs":[{"type":"uint256","name":"start","internalType":"uint256"},{"type":"uint256","name":"count","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple[]","name":"","internalType":"struct CoinInfo[]","components":[{"type":"string","name":"symbol","internalType":"string"},{"type":"uint256","name":"decimals","internalType":"uint256"},{"type":"uint256","name":"priceInDai","internalType":"uint256"},{"type":"uint256","name":"priceInDaiAtStart","internalType":"uint256"},{"type":"uint8","name":"coinType","internalType":"enum TradeCoinType"}]}],"name":"getPulseChainCoins","inputs":[{"type":"uint256","name":"start","internalType":"uint256"},{"type":"uint256","name":"count","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getTokenAmountForDaiOutput","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"uint256","name":"daiAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getTokenOutputForDai","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"uint256","name":"daiAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getTokenOutputForDaiAtStart","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"uint256","name":"daiAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getTotalCoins","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getTotalNonPulseChainCoins","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getTotalPulseChainCoins","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"_isAuth","internalType":"bool"}],"name":"isAuthorised","inputs":[{"type":"address","name":"_authAdd","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"nonPulseChainCoinIds","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"pendingOwner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"pulseChainCoinIds","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"recordInitPrice","inputs":[{"type":"uint256[]","name":"coinsIndex","internalType":"uint256[]"},{"type":"uint256[]","name":"coinsPrice","internalType":"uint256[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"removeAuthorized","inputs":[{"type":"address","name":"_toRemove","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setDefaultSelectionRange","inputs":[{"type":"uint256","name":"_total","internalType":"uint256"},{"type":"uint256","name":"_pwLength","internalType":"uint256"},{"type":"uint256","name":"_npwLength","internalType":"uint256"},{"type":"uint256","name":"_defaultRN","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updatePrices","inputs":[{"type":"uint256[]","name":"tokenIds","internalType":"uint256[]"},{"type":"uint256[]","name":"newPrices","internalType":"uint256[]"}]}]
              

Contract Creation Code

Verify & Publish
0x61016060405260036101209081526244414960e81b610140526080818152601260a052670de0b6b3a764000060c081905260e05260026101005290600b9081906200004b9082620001dc565b506020820151816001015560408201518160020155606082015181600301556080820151816004015f6101000a81548160ff0219169083600281111562000096576200009662000128565b02179055505050348015620000a9575f80fd5b50620000b533620000bb565b620002a4565b600180546001600160a01b0319169055620000d681620000d9565b50565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b634e487b7160e01b5f52602160045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b600181811c908216806200016557607f821691505b6020821081036200018457634e487b7160e01b5f52602260045260245ffd5b50919050565b601f821115620001d7575f81815260208120601f850160051c81016020861015620001b25750805b601f850160051c820191505b81811015620001d357828155600101620001be565b5050505b505050565b81516001600160401b03811115620001f857620001f86200013c565b620002108162000209845462000150565b846200018a565b602080601f83116001811462000246575f84156200022e5750858301515b5f19600386901b1c1916600185901b178555620001d3565b5f85815260208120601f198616915b82811015620002765788860151825594840194600190910190840162000255565b50858210156200029457878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b6129ab80620002b25f395ff3fe608060405234801561000f575f80fd5b50600436106101fd575f3560e01c8063832aed2611610114578063cc3facc4116100a9578063da31158811610079578063da3115881461044d578063defd8e071461046d578063e30c397814610480578063f2fde38b14610491578063f499d99d146104a4575f80fd5b8063cc3facc41461041f578063cf1c316a14610432578063cf5e62d1146103c2578063d86b900514610445575f80fd5b8063ae8cac29116100e4578063ae8cac2914610265578063b7695d35146103d5578063bf1ede32146103e8578063c6610657146103fb575f80fd5b8063832aed26146103825780638da5cb5b14610395578063a773e0c9146103b9578063a9a01f85146103c2575f80fd5b806351b699cd1161019557806367f9fc3c1161016557806367f9fc3c1461031f578063689eb23214610332578063715018a61461035257806379ba50971461035a5780637db58e0f14610362575f80fd5b806351b699cd146102b4578063552180f2146102d7578063560f5441146103045780635c3684881461030c575f80fd5b80631f6e889a116101d05780631f6e889a14610265578063289fc9d2146102865780633887c27c1461028e578063485d7d94146102a1575f80fd5b80630331b529146102015780630795eca01461022a5780631be21ad91461023f5780631c138e2314610252575b5f80fd5b61021461020f366004612148565b6104ac565b6040516102219190612225565b60405180910390f35b61023d610238366004612285565b6106aa565b005b61023d61024d366004612360565b610841565b610214610260366004612148565b6109f8565b610278610273366004612148565b610bdb565b604051908152602001610221565b600354610278565b61023d61029c366004612360565b610d59565b61023d6102af3660046123c0565b610ea1565b6102c76102c23660046123c0565b610edd565b6040519015158152602001610221565b600854600954600a546102e992919083565b60408051938452602084019290925290820152606001610221565b600654610278565b61027861031a366004612148565b610f29565b61021461032d366004612148565b61107f565b610345610340366004612400565b611269565b6040516102219190612428565b61023d611382565b61023d611395565b610375610370366004612148565b61140f565b6040516102219190612458565b610375610390366004612148565b6114ed565b5f546001600160a01b03165b6040516001600160a01b039091168152602001610221565b61027860075481565b6102786103d0366004612148565b6115cb565b6102786103e336600461249b565b611721565b6102786103f63660046124b2565b611740565b61040e61040936600461249b565b6119c5565b60405161022195949392919061253c565b61034561042d366004612400565b611a7c565b61023d6104403660046123c0565b611b60565b61040e611b9d565b61046061045b36600461249b565b611bac565b604051610221919061256f565b61027861047b36600461249b565b611d05565b6001546001600160a01b03166103a1565b61023d61049f3660046123c0565b611d14565b600554610278565b60065460609080841080156104ca5750806104c78486612595565b11155b6104ef5760405162461bcd60e51b81526004016104e6906125a8565b60405180910390fd5b5f8367ffffffffffffffff811115610509576105096122b4565b60405190808252806020026020018201604052801561054257816020015b61052f6120ef565b8152602001906001900390816105275790505b5090505f5b8481101561069f5760045f600661055e848a612595565b8154811061056e5761056e6125cf565b905f5260205f20015481526020019081526020015f206040518060a00160405290815f8201805461059e906125e3565b80601f01602080910402602001604051908101604052809291908181526020018280546105ca906125e3565b80156106155780601f106105ec57610100808354040283529160200191610615565b820191905f5260205f20905b8154815290600101906020018083116105f857829003601f168201915b505050918352505060018201546020820152600280830154604083015260038301546060830152600483015460809092019160ff169081111561065a5761065a6121ab565b600281111561066b5761066b6121ab565b81525050828281518110610681576106816125cf565b602002602001018190525080806106979061261b565b915050610547565b509150505b92915050565b335f9081526002602052604090205460ff16806106df5750336106d45f546001600160a01b031690565b6001600160a01b0316145b6106fb5760405162461bcd60e51b81526004016104e690612633565b60035484111561073d5760405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a5908151bdd185b609a1b60448201526064016104e6565b6005548311156107835760405162461bcd60e51b8152602060048201526011602482015270092dcecc2d8d2c840a0ae40d8cadccee8d607b1b60448201526064016104e6565b6006548211156107c95760405162461bcd60e51b8152602060048201526011602482015270092dcecc2d8d2c84086b44098cadccee8d607b1b60448201526064016104e6565b6040805160608082018352868252602080830187905291830185905260088790556009869055600a85905560078490558251878152918201869052818301859052810183905290517ffcc94614435c643ae847e0a8e20e2e9e2fb8d9dea40a715cfc429b6a305d0a509181900360800190a150505050565b335f9081526002602052604090205460ff168061087657503361086b5f546001600160a01b031690565b6001600160a01b0316145b6108925760405162461bcd60e51b81526004016104e690612633565b80518251146108b35760405162461bcd60e51b81526004016104e69061265b565b600354825111156109065760405162461bcd60e51b815260206004820181905260248201527f4172726179206c656e677468206578636565647320746f74616c20636f696e7360448201526064016104e6565b5f5b82518110156109f3575f838281518110610924576109246125cf565b60200260200101511180156109545750600354838281518110610949576109496125cf565b602002602001015111155b6109955760405162461bcd60e51b8152602060048201526012602482015271092dcecc2d8d2c840c6ded2dc40d2dcc8caf60731b60448201526064016104e6565b8181815181106109a7576109a76125cf565b602002602001015160045f8584815181106109c4576109c46125cf565b602002602001015181526020019081526020015f206003018190555080806109eb9061261b565b915050610908565b505050565b606060018310158015610a2257506003546001610a158486612595565b610a1f919061269c565b11155b610a3e5760405162461bcd60e51b81526004016104e6906125a8565b5f8267ffffffffffffffff811115610a5857610a586122b4565b604051908082528060200260200182016040528015610a9157816020015b610a7e6120ef565b815260200190600190039081610a765790505b5090505f5b83811015610bd35760045f610aab8388612595565b81526020019081526020015f206040518060a00160405290815f82018054610ad2906125e3565b80601f0160208091040260200160405190810160405280929190818152602001828054610afe906125e3565b8015610b495780601f10610b2057610100808354040283529160200191610b49565b820191905f5260205f20905b815481529060010190602001808311610b2c57829003601f168201915b505050918352505060018201546020820152600280830154604083015260038301546060830152600483015460809092019160ff1690811115610b8e57610b8e6121ab565b6002811115610b9f57610b9f6121ab565b81525050828281518110610bb557610bb56125cf565b60200260200101819052508080610bcb9061261b565b915050610a96565b509392505050565b5f8083118015610bed57506003548311155b610c095760405162461bcd60e51b81526004016104e6906126af565b5f83815260046020526040808220815160a08101909252805482908290610c2f906125e3565b80601f0160208091040260200160405190810160405280929190818152602001828054610c5b906125e3565b8015610ca65780601f10610c7d57610100808354040283529160200191610ca6565b820191905f5260205f20905b815481529060010190602001808311610c8957829003601f168201915b505050918352505060018201546020820152600280830154604083015260038301546060830152600483015460809092019160ff1690811115610ceb57610ceb6121ab565b6002811115610cfc57610cfc6121ab565b8152505090505f81602001516012610d14919061269c565b610d1f90600a6127b9565b610d2990856127c4565b90505f670de0b6b3a7640000836040015183610d4591906127c4565b610d4f91906127ef565b9695505050505050565b335f9081526002602052604090205460ff1680610d8e575033610d835f546001600160a01b031690565b6001600160a01b0316145b610daa5760405162461bcd60e51b81526004016104e690612633565b8051825114610dcb5760405162461bcd60e51b81526004016104e69061265b565b5f5b82518110156109f3575f838281518110610de957610de96125cf565b602002602001015190505f838381518110610e0657610e066125cf565b602002602001015190505f82118015610e2157506003548211155b610e3d5760405162461bcd60e51b81526004016104e6906126af565b5f82815260046020526040908190206002018290555182907f69bedddd1c17558723d2c1fef779d4861749d024df6d986964feee81ecb8ebdd90610e849084815260200190565b60405180910390a250508080610e999061261b565b915050610dcd565b610ea9611d84565b336001600160a01b03821603610ebd575f80fd5b6001600160a01b03165f908152600260205260409020805460ff19169055565b6001600160a01b0381165f9081526002602052604081205460ff16806106a45750816001600160a01b0316610f195f546001600160a01b031690565b6001600160a01b03161492915050565b5f8083118015610f3b57506003548311155b610f575760405162461bcd60e51b81526004016104e6906126af565b5f83815260046020526040808220815160a08101909252805482908290610f7d906125e3565b80601f0160208091040260200160405190810160405280929190818152602001828054610fa9906125e3565b8015610ff45780601f10610fcb57610100808354040283529160200191610ff4565b820191905f5260205f20905b815481529060010190602001808311610fd757829003601f168201915b505050918352505060018201546020820152600280830154604083015260038301546060830152600483015460809092019160ff1690811115611039576110396121ab565b600281111561104a5761104a6121ab565b8152505090505f8160200151600a61106291906127b9565b61106c90856127c4565b90505f826060015182610d4f91906127ef565b600554606090808410801561109d57508061109a8486612595565b11155b6110b95760405162461bcd60e51b81526004016104e6906125a8565b5f8367ffffffffffffffff8111156110d3576110d36122b4565b60405190808252806020026020018201604052801561110c57816020015b6110f96120ef565b8152602001906001900390816110f15790505b5090505f5b8481101561069f5760045f6005611128848a612595565b81548110611138576111386125cf565b905f5260205f20015481526020019081526020015f206040518060a00160405290815f82018054611168906125e3565b80601f0160208091040260200160405190810160405280929190818152602001828054611194906125e3565b80156111df5780601f106111b6576101008083540402835291602001916111df565b820191905f5260205f20905b8154815290600101906020018083116111c257829003601f168201915b505050918352505060018201546020820152600280830154604083015260038301546060830152600483015460809092019160ff1690811115611224576112246121ab565b6002811115611235576112356121ab565b8152505082828151811061124b5761124b6125cf565b602002602001018190525080806112619061261b565b915050611111565b61127161212a565b61127961212a565b5f808086600281111561128e5761128e6121ab565b036112f657505060058054604080516020808402820181019092528281526112ef9187918491869083908301828280156112e557602002820191905f5260205f20905b8154815260200190600101908083116112d1575b5050505050611ddd565b9250611378565b600186600281111561130a5761130a6121ab565b0361136957505060068054604080516020808402820181019092528281526112ef9187918491869083908301828280156112e557602002820191905f5260205f20908154815260200190600101908083116112d1575050505050611ddd565b61137585600354611f4d565b92505b5090949350505050565b61138a611d84565b6113935f61208c565b565b60015433906001600160a01b031681146114035760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016104e6565b61140c8161208c565b50565b600654606090808410801561142d57508061142a8486612595565b11155b6114495760405162461bcd60e51b81526004016104e6906125a8565b5f8367ffffffffffffffff811115611463576114636122b4565b60405190808252806020026020018201604052801561148c578160200160208202803683370190505b5090505f5b8481101561069f5760066114a58288612595565b815481106114b5576114b56125cf565b905f5260205f2001548282815181106114d0576114d06125cf565b6020908102919091010152806114e58161261b565b915050611491565b600554606090808410801561150b5750806115088486612595565b11155b6115275760405162461bcd60e51b81526004016104e6906125a8565b5f8367ffffffffffffffff811115611541576115416122b4565b60405190808252806020026020018201604052801561156a578160200160208202803683370190505b5090505f5b8481101561069f5760056115838288612595565b81548110611593576115936125cf565b905f5260205f2001548282815181106115ae576115ae6125cf565b6020908102919091010152806115c38161261b565b91505061156f565b5f80831180156115dd57506003548311155b6115f95760405162461bcd60e51b81526004016104e6906126af565b5f83815260046020526040808220815160a0810190925280548290829061161f906125e3565b80601f016020809104026020016040519081016040528092919081815260200182805461164b906125e3565b80156116965780601f1061166d57610100808354040283529160200191611696565b820191905f5260205f20905b81548152906001019060200180831161167957829003601f168201915b505050918352505060018201546020820152600280830154604083015260038301546060830152600483015460809092019160ff16908111156116db576116db6121ab565b60028111156116ec576116ec6121ab565b8152505090505f8160200151600a61170491906127b9565b61170e90856127c4565b90505f826040015182610d4f91906127ef565b60058181548110611730575f80fd5b5f91825260209091200154905081565b335f9081526002602052604081205460ff168061177557503361176a5f546001600160a01b031690565b6001600160a01b0316145b6117915760405162461bcd60e51b81526004016104e690612633565b60028660028111156117a5576117a56121ab565b036117e15760405162461bcd60e51b815260206004820152600c60248201526b496e76616c6964205479706560a01b60448201526064016104e6565b60038054905f6117f08361261b565b91905055506040518060a0016040528086868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201829052509385525050506020820186905260408201859052606082015260800187600281111561185f5761185f6121ab565b90526003545f9081526004602052604090208151819061187f908261284f565b506020820151816001015560408201518160020155606082015181600301556080820151816004015f6101000a81548160ff021916908360028111156118c7576118c76121ab565b02179055505f91506118d69050565b8660028111156118e8576118e86121ab565b0361192757600354600580546001810182555f919091527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db00155611976565b600186600281111561193b5761193b6121ab565b0361197657600354600680546001810182555f919091527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f01555b6003547ff55a319d41f7f8bc2b2c2694b498de9f983c7b6906ef28f8277275cc1c024f06868686868b6040516119b095949392919061290b565b60405180910390a25060035495945050505050565b60046020525f90815260409020805481906119df906125e3565b80601f0160208091040260200160405190810160405280929190818152602001828054611a0b906125e3565b8015611a565780601f10611a2d57610100808354040283529160200191611a56565b820191905f5260205f20905b815481529060010190602001808311611a3957829003601f168201915b505050506001830154600284015460038501546004909501549394919390925060ff1685565b611a8461212a565b611a8c61212a565b5f8080866002811115611aa157611aa16121ab565b03611b13575050600954600754600591906112ef90611ac1908790612595565b82848054806020026020016040519081016040528092919081815260200182805480156112e557602002820191905f5260205f20908154815260200190600101908083116112d1575050505050611ddd565b6001866002811115611b2757611b276121ab565b03611b47575050600a54600754600691906112ef90611ac1908790612595565b61137585600754611b589190612595565b600854611f4d565b611b68611d84565b6001600160a01b038116611b7a575f80fd5b6001600160a01b03165f908152600260205260409020805460ff19166001179055565b600b805481906119df906125e3565b611bb46120ef565b5f82118015611bc557506003548211155b611c085760405162461bcd60e51b8152602060048201526014602482015273436f696e204944206f7574206f662072616e676560601b60448201526064016104e6565b5f8281526004602052604090819020815160a08101909252805482908290611c2f906125e3565b80601f0160208091040260200160405190810160405280929190818152602001828054611c5b906125e3565b8015611ca65780601f10611c7d57610100808354040283529160200191611ca6565b820191905f5260205f20905b815481529060010190602001808311611c8957829003601f168201915b505050918352505060018201546020820152600280830154604083015260038301546060830152600483015460809092019160ff1690811115611ceb57611ceb6121ab565b6002811115611cfc57611cfc6121ab565b90525092915050565b60068181548110611730575f80fd5b611d1c611d84565b600180546001600160a01b0383166001600160a01b03199091168117909155611d4c5f546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b5f546001600160a01b031633146113935760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104e6565b611de561212a565b6004831015611e365760405162461bcd60e51b815260206004820181905260248201527f4e6f7420656e6f75676820636f696e7320696e207468652063617465676f727960448201526064016104e6565b611e3e61212a565b845f5b6004811015611f42575f868383604051602001611e68929190918252602082015260400190565b604051602081830303815290604052805190602001205f1c611e8a919061294d565b9050858181518110611e9e57611e9e6125cf565b6020026020010151848360048110611eb857611eb86125cf565b602002015285611ec960018961269c565b81518110611ed957611ed96125cf565b6020026020010151868281518110611ef357611ef36125cf565b602090810291909101015286611f0881612960565b975050838260048110611f1d57611f1d6125cf565b6020020151611f2c9084612595565b9250508080611f3a9061261b565b915050611e41565b509095945050505050565b611f5561212a565b611f5d61212a565b6004831015611fae5760405162461bcd60e51b815260206004820152601a60248201527f4e6f7420656e6f75676820636f696e7320617661696c61626c6500000000000060448201526064016104e6565b5f845b6004821015611378575f8582604051602001611fcf91815260200190565b604051602081830303815290604052805190602001205f1c611ff1919061294d565b611ffc906001612595565b90505f805b84811015612041578286826004811061201c5761201c6125cf565b60200201510361202f5760019150612041565b806120398161261b565b915050612001565b50801561205c57826120528161261b565b9350505050611fb1565b8185856004811061206f5761206f6125cf565b60200201528361207e8161261b565b94505082806120529061261b565b600180546001600160a01b031916905561140c815f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6040518060a00160405280606081526020015f81526020015f81526020015f81526020015f6002811115612125576121256121ab565b905290565b60405180608001604052806004906020820280368337509192915050565b5f8060408385031215612159575f80fd5b50508035926020909101359150565b5f81518084525f5b8181101561218c57602081850181015186830182015201612170565b505f602082860101526020601f19601f83011685010191505092915050565b634e487b7160e01b5f52602160045260245ffd5b600381106121db57634e487b7160e01b5f52602160045260245ffd5b9052565b5f815160a084526121f360a0850182612168565b90506020830151602085015260408301516040850152606083015160608501526080830151610bd360808601826121bf565b5f602080830181845280855180835260408601915060408160051b87010192508387015f5b8281101561227857603f198886030184526122668583516121df565b9450928501929085019060010161224a565b5092979650505050505050565b5f805f8060808587031215612298575f80fd5b5050823594602084013594506040840135936060013592509050565b634e487b7160e01b5f52604160045260245ffd5b5f82601f8301126122d7575f80fd5b8135602067ffffffffffffffff808311156122f4576122f46122b4565b8260051b604051601f19603f83011681018181108482111715612319576123196122b4565b604052938452858101830193838101925087851115612336575f80fd5b83870191505b848210156123555781358352918301919083019061233c565b979650505050505050565b5f8060408385031215612371575f80fd5b823567ffffffffffffffff80821115612388575f80fd5b612394868387016122c8565b935060208501359150808211156123a9575f80fd5b506123b6858286016122c8565b9150509250929050565b5f602082840312156123d0575f80fd5b81356001600160a01b03811681146123e6575f80fd5b9392505050565b8035600381106123fb575f80fd5b919050565b5f8060408385031215612411575f80fd5b61241a836123ed565b946020939093013593505050565b6080810181835f5b600481101561244f578151835260209283019290910190600101612430565b50505092915050565b602080825282518282018190525f9190848201906040850190845b8181101561248f57835183529284019291840191600101612473565b50909695505050505050565b5f602082840312156124ab575f80fd5b5035919050565b5f805f805f608086880312156124c6575f80fd5b6124cf866123ed565b9450602086013567ffffffffffffffff808211156124eb575f80fd5b818801915088601f8301126124fe575f80fd5b81358181111561250c575f80fd5b89602082850101111561251d575f80fd5b9699602092909201985095966040810135965060600135945092505050565b60a081525f61254e60a0830188612168565b9050856020830152846040830152836060830152610d4f60808301846121bf565b602081525f6123e660208301846121df565b634e487b7160e01b5f52601160045260245ffd5b808201808211156106a4576106a4612581565b6020808252600d908201526c496e76616c69642072616e676560981b604082015260600190565b634e487b7160e01b5f52603260045260245ffd5b600181811c908216806125f757607f821691505b60208210810361261557634e487b7160e01b5f52602260045260245ffd5b50919050565b5f6001820161262c5761262c612581565b5060010190565b6020808252600e908201526d139bdd08185d5d1a1bdc9a5e995960921b604082015260600190565b60208082526021908201527f417272617973206d757374206265206f66207468652073616d65206c656e67746040820152600d60fb1b606082015260800190565b818103818111156106a4576106a4612581565b60208082526010908201526f125b9d985b1a59081d1bdad95b88125160821b604082015260600190565b600181815b8085111561271357815f19048211156126f9576126f9612581565b8085161561270657918102915b93841c93908002906126de565b509250929050565b5f82612729575060016106a4565b8161273557505f6106a4565b816001811461274b576002811461275557612771565b60019150506106a4565b60ff84111561276657612766612581565b50506001821b6106a4565b5060208310610133831016604e8410600b8410161715612794575081810a6106a4565b61279e83836126d9565b805f19048211156127b1576127b1612581565b029392505050565b5f6123e6838361271b565b80820281158282048414176106a4576106a4612581565b634e487b7160e01b5f52601260045260245ffd5b5f826127fd576127fd6127db565b500490565b601f8211156109f3575f81815260208120601f850160051c810160208610156128285750805b601f850160051c820191505b8181101561284757828155600101612834565b505050505050565b815167ffffffffffffffff811115612869576128696122b4565b61287d8161287784546125e3565b84612802565b602080601f8311600181146128b0575f84156128995750858301515b5f19600386901b1c1916600185901b178555612847565b5f85815260208120601f198616915b828110156128de578886015182559484019460019091019084016128bf565b50858210156128fb57878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b60808152846080820152848660a08301375f60a086830101525f60a0601f19601f8801168301019050846020830152836040830152610d4f60608301846121bf565b5f8261295b5761295b6127db565b500690565b5f8161296e5761296e612581565b505f19019056fea26469706673582212209d83ff8fe9c33a41cd1d44c21af4e67f06c1afb7eedc9d0c51c4ac44e418494164736f6c63430008140033

Deployed ByteCode

0x608060405234801561000f575f80fd5b50600436106101fd575f3560e01c8063832aed2611610114578063cc3facc4116100a9578063da31158811610079578063da3115881461044d578063defd8e071461046d578063e30c397814610480578063f2fde38b14610491578063f499d99d146104a4575f80fd5b8063cc3facc41461041f578063cf1c316a14610432578063cf5e62d1146103c2578063d86b900514610445575f80fd5b8063ae8cac29116100e4578063ae8cac2914610265578063b7695d35146103d5578063bf1ede32146103e8578063c6610657146103fb575f80fd5b8063832aed26146103825780638da5cb5b14610395578063a773e0c9146103b9578063a9a01f85146103c2575f80fd5b806351b699cd1161019557806367f9fc3c1161016557806367f9fc3c1461031f578063689eb23214610332578063715018a61461035257806379ba50971461035a5780637db58e0f14610362575f80fd5b806351b699cd146102b4578063552180f2146102d7578063560f5441146103045780635c3684881461030c575f80fd5b80631f6e889a116101d05780631f6e889a14610265578063289fc9d2146102865780633887c27c1461028e578063485d7d94146102a1575f80fd5b80630331b529146102015780630795eca01461022a5780631be21ad91461023f5780631c138e2314610252575b5f80fd5b61021461020f366004612148565b6104ac565b6040516102219190612225565b60405180910390f35b61023d610238366004612285565b6106aa565b005b61023d61024d366004612360565b610841565b610214610260366004612148565b6109f8565b610278610273366004612148565b610bdb565b604051908152602001610221565b600354610278565b61023d61029c366004612360565b610d59565b61023d6102af3660046123c0565b610ea1565b6102c76102c23660046123c0565b610edd565b6040519015158152602001610221565b600854600954600a546102e992919083565b60408051938452602084019290925290820152606001610221565b600654610278565b61027861031a366004612148565b610f29565b61021461032d366004612148565b61107f565b610345610340366004612400565b611269565b6040516102219190612428565b61023d611382565b61023d611395565b610375610370366004612148565b61140f565b6040516102219190612458565b610375610390366004612148565b6114ed565b5f546001600160a01b03165b6040516001600160a01b039091168152602001610221565b61027860075481565b6102786103d0366004612148565b6115cb565b6102786103e336600461249b565b611721565b6102786103f63660046124b2565b611740565b61040e61040936600461249b565b6119c5565b60405161022195949392919061253c565b61034561042d366004612400565b611a7c565b61023d6104403660046123c0565b611b60565b61040e611b9d565b61046061045b36600461249b565b611bac565b604051610221919061256f565b61027861047b36600461249b565b611d05565b6001546001600160a01b03166103a1565b61023d61049f3660046123c0565b611d14565b600554610278565b60065460609080841080156104ca5750806104c78486612595565b11155b6104ef5760405162461bcd60e51b81526004016104e6906125a8565b60405180910390fd5b5f8367ffffffffffffffff811115610509576105096122b4565b60405190808252806020026020018201604052801561054257816020015b61052f6120ef565b8152602001906001900390816105275790505b5090505f5b8481101561069f5760045f600661055e848a612595565b8154811061056e5761056e6125cf565b905f5260205f20015481526020019081526020015f206040518060a00160405290815f8201805461059e906125e3565b80601f01602080910402602001604051908101604052809291908181526020018280546105ca906125e3565b80156106155780601f106105ec57610100808354040283529160200191610615565b820191905f5260205f20905b8154815290600101906020018083116105f857829003601f168201915b505050918352505060018201546020820152600280830154604083015260038301546060830152600483015460809092019160ff169081111561065a5761065a6121ab565b600281111561066b5761066b6121ab565b81525050828281518110610681576106816125cf565b602002602001018190525080806106979061261b565b915050610547565b509150505b92915050565b335f9081526002602052604090205460ff16806106df5750336106d45f546001600160a01b031690565b6001600160a01b0316145b6106fb5760405162461bcd60e51b81526004016104e690612633565b60035484111561073d5760405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a5908151bdd185b609a1b60448201526064016104e6565b6005548311156107835760405162461bcd60e51b8152602060048201526011602482015270092dcecc2d8d2c840a0ae40d8cadccee8d607b1b60448201526064016104e6565b6006548211156107c95760405162461bcd60e51b8152602060048201526011602482015270092dcecc2d8d2c84086b44098cadccee8d607b1b60448201526064016104e6565b6040805160608082018352868252602080830187905291830185905260088790556009869055600a85905560078490558251878152918201869052818301859052810183905290517ffcc94614435c643ae847e0a8e20e2e9e2fb8d9dea40a715cfc429b6a305d0a509181900360800190a150505050565b335f9081526002602052604090205460ff168061087657503361086b5f546001600160a01b031690565b6001600160a01b0316145b6108925760405162461bcd60e51b81526004016104e690612633565b80518251146108b35760405162461bcd60e51b81526004016104e69061265b565b600354825111156109065760405162461bcd60e51b815260206004820181905260248201527f4172726179206c656e677468206578636565647320746f74616c20636f696e7360448201526064016104e6565b5f5b82518110156109f3575f838281518110610924576109246125cf565b60200260200101511180156109545750600354838281518110610949576109496125cf565b602002602001015111155b6109955760405162461bcd60e51b8152602060048201526012602482015271092dcecc2d8d2c840c6ded2dc40d2dcc8caf60731b60448201526064016104e6565b8181815181106109a7576109a76125cf565b602002602001015160045f8584815181106109c4576109c46125cf565b602002602001015181526020019081526020015f206003018190555080806109eb9061261b565b915050610908565b505050565b606060018310158015610a2257506003546001610a158486612595565b610a1f919061269c565b11155b610a3e5760405162461bcd60e51b81526004016104e6906125a8565b5f8267ffffffffffffffff811115610a5857610a586122b4565b604051908082528060200260200182016040528015610a9157816020015b610a7e6120ef565b815260200190600190039081610a765790505b5090505f5b83811015610bd35760045f610aab8388612595565b81526020019081526020015f206040518060a00160405290815f82018054610ad2906125e3565b80601f0160208091040260200160405190810160405280929190818152602001828054610afe906125e3565b8015610b495780601f10610b2057610100808354040283529160200191610b49565b820191905f5260205f20905b815481529060010190602001808311610b2c57829003601f168201915b505050918352505060018201546020820152600280830154604083015260038301546060830152600483015460809092019160ff1690811115610b8e57610b8e6121ab565b6002811115610b9f57610b9f6121ab565b81525050828281518110610bb557610bb56125cf565b60200260200101819052508080610bcb9061261b565b915050610a96565b509392505050565b5f8083118015610bed57506003548311155b610c095760405162461bcd60e51b81526004016104e6906126af565b5f83815260046020526040808220815160a08101909252805482908290610c2f906125e3565b80601f0160208091040260200160405190810160405280929190818152602001828054610c5b906125e3565b8015610ca65780601f10610c7d57610100808354040283529160200191610ca6565b820191905f5260205f20905b815481529060010190602001808311610c8957829003601f168201915b505050918352505060018201546020820152600280830154604083015260038301546060830152600483015460809092019160ff1690811115610ceb57610ceb6121ab565b6002811115610cfc57610cfc6121ab565b8152505090505f81602001516012610d14919061269c565b610d1f90600a6127b9565b610d2990856127c4565b90505f670de0b6b3a7640000836040015183610d4591906127c4565b610d4f91906127ef565b9695505050505050565b335f9081526002602052604090205460ff1680610d8e575033610d835f546001600160a01b031690565b6001600160a01b0316145b610daa5760405162461bcd60e51b81526004016104e690612633565b8051825114610dcb5760405162461bcd60e51b81526004016104e69061265b565b5f5b82518110156109f3575f838281518110610de957610de96125cf565b602002602001015190505f838381518110610e0657610e066125cf565b602002602001015190505f82118015610e2157506003548211155b610e3d5760405162461bcd60e51b81526004016104e6906126af565b5f82815260046020526040908190206002018290555182907f69bedddd1c17558723d2c1fef779d4861749d024df6d986964feee81ecb8ebdd90610e849084815260200190565b60405180910390a250508080610e999061261b565b915050610dcd565b610ea9611d84565b336001600160a01b03821603610ebd575f80fd5b6001600160a01b03165f908152600260205260409020805460ff19169055565b6001600160a01b0381165f9081526002602052604081205460ff16806106a45750816001600160a01b0316610f195f546001600160a01b031690565b6001600160a01b03161492915050565b5f8083118015610f3b57506003548311155b610f575760405162461bcd60e51b81526004016104e6906126af565b5f83815260046020526040808220815160a08101909252805482908290610f7d906125e3565b80601f0160208091040260200160405190810160405280929190818152602001828054610fa9906125e3565b8015610ff45780601f10610fcb57610100808354040283529160200191610ff4565b820191905f5260205f20905b815481529060010190602001808311610fd757829003601f168201915b505050918352505060018201546020820152600280830154604083015260038301546060830152600483015460809092019160ff1690811115611039576110396121ab565b600281111561104a5761104a6121ab565b8152505090505f8160200151600a61106291906127b9565b61106c90856127c4565b90505f826060015182610d4f91906127ef565b600554606090808410801561109d57508061109a8486612595565b11155b6110b95760405162461bcd60e51b81526004016104e6906125a8565b5f8367ffffffffffffffff8111156110d3576110d36122b4565b60405190808252806020026020018201604052801561110c57816020015b6110f96120ef565b8152602001906001900390816110f15790505b5090505f5b8481101561069f5760045f6005611128848a612595565b81548110611138576111386125cf565b905f5260205f20015481526020019081526020015f206040518060a00160405290815f82018054611168906125e3565b80601f0160208091040260200160405190810160405280929190818152602001828054611194906125e3565b80156111df5780601f106111b6576101008083540402835291602001916111df565b820191905f5260205f20905b8154815290600101906020018083116111c257829003601f168201915b505050918352505060018201546020820152600280830154604083015260038301546060830152600483015460809092019160ff1690811115611224576112246121ab565b6002811115611235576112356121ab565b8152505082828151811061124b5761124b6125cf565b602002602001018190525080806112619061261b565b915050611111565b61127161212a565b61127961212a565b5f808086600281111561128e5761128e6121ab565b036112f657505060058054604080516020808402820181019092528281526112ef9187918491869083908301828280156112e557602002820191905f5260205f20905b8154815260200190600101908083116112d1575b5050505050611ddd565b9250611378565b600186600281111561130a5761130a6121ab565b0361136957505060068054604080516020808402820181019092528281526112ef9187918491869083908301828280156112e557602002820191905f5260205f20908154815260200190600101908083116112d1575050505050611ddd565b61137585600354611f4d565b92505b5090949350505050565b61138a611d84565b6113935f61208c565b565b60015433906001600160a01b031681146114035760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016104e6565b61140c8161208c565b50565b600654606090808410801561142d57508061142a8486612595565b11155b6114495760405162461bcd60e51b81526004016104e6906125a8565b5f8367ffffffffffffffff811115611463576114636122b4565b60405190808252806020026020018201604052801561148c578160200160208202803683370190505b5090505f5b8481101561069f5760066114a58288612595565b815481106114b5576114b56125cf565b905f5260205f2001548282815181106114d0576114d06125cf565b6020908102919091010152806114e58161261b565b915050611491565b600554606090808410801561150b5750806115088486612595565b11155b6115275760405162461bcd60e51b81526004016104e6906125a8565b5f8367ffffffffffffffff811115611541576115416122b4565b60405190808252806020026020018201604052801561156a578160200160208202803683370190505b5090505f5b8481101561069f5760056115838288612595565b81548110611593576115936125cf565b905f5260205f2001548282815181106115ae576115ae6125cf565b6020908102919091010152806115c38161261b565b91505061156f565b5f80831180156115dd57506003548311155b6115f95760405162461bcd60e51b81526004016104e6906126af565b5f83815260046020526040808220815160a0810190925280548290829061161f906125e3565b80601f016020809104026020016040519081016040528092919081815260200182805461164b906125e3565b80156116965780601f1061166d57610100808354040283529160200191611696565b820191905f5260205f20905b81548152906001019060200180831161167957829003601f168201915b505050918352505060018201546020820152600280830154604083015260038301546060830152600483015460809092019160ff16908111156116db576116db6121ab565b60028111156116ec576116ec6121ab565b8152505090505f8160200151600a61170491906127b9565b61170e90856127c4565b90505f826040015182610d4f91906127ef565b60058181548110611730575f80fd5b5f91825260209091200154905081565b335f9081526002602052604081205460ff168061177557503361176a5f546001600160a01b031690565b6001600160a01b0316145b6117915760405162461bcd60e51b81526004016104e690612633565b60028660028111156117a5576117a56121ab565b036117e15760405162461bcd60e51b815260206004820152600c60248201526b496e76616c6964205479706560a01b60448201526064016104e6565b60038054905f6117f08361261b565b91905055506040518060a0016040528086868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201829052509385525050506020820186905260408201859052606082015260800187600281111561185f5761185f6121ab565b90526003545f9081526004602052604090208151819061187f908261284f565b506020820151816001015560408201518160020155606082015181600301556080820151816004015f6101000a81548160ff021916908360028111156118c7576118c76121ab565b02179055505f91506118d69050565b8660028111156118e8576118e86121ab565b0361192757600354600580546001810182555f919091527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db00155611976565b600186600281111561193b5761193b6121ab565b0361197657600354600680546001810182555f919091527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f01555b6003547ff55a319d41f7f8bc2b2c2694b498de9f983c7b6906ef28f8277275cc1c024f06868686868b6040516119b095949392919061290b565b60405180910390a25060035495945050505050565b60046020525f90815260409020805481906119df906125e3565b80601f0160208091040260200160405190810160405280929190818152602001828054611a0b906125e3565b8015611a565780601f10611a2d57610100808354040283529160200191611a56565b820191905f5260205f20905b815481529060010190602001808311611a3957829003601f168201915b505050506001830154600284015460038501546004909501549394919390925060ff1685565b611a8461212a565b611a8c61212a565b5f8080866002811115611aa157611aa16121ab565b03611b13575050600954600754600591906112ef90611ac1908790612595565b82848054806020026020016040519081016040528092919081815260200182805480156112e557602002820191905f5260205f20908154815260200190600101908083116112d1575050505050611ddd565b6001866002811115611b2757611b276121ab565b03611b47575050600a54600754600691906112ef90611ac1908790612595565b61137585600754611b589190612595565b600854611f4d565b611b68611d84565b6001600160a01b038116611b7a575f80fd5b6001600160a01b03165f908152600260205260409020805460ff19166001179055565b600b805481906119df906125e3565b611bb46120ef565b5f82118015611bc557506003548211155b611c085760405162461bcd60e51b8152602060048201526014602482015273436f696e204944206f7574206f662072616e676560601b60448201526064016104e6565b5f8281526004602052604090819020815160a08101909252805482908290611c2f906125e3565b80601f0160208091040260200160405190810160405280929190818152602001828054611c5b906125e3565b8015611ca65780601f10611c7d57610100808354040283529160200191611ca6565b820191905f5260205f20905b815481529060010190602001808311611c8957829003601f168201915b505050918352505060018201546020820152600280830154604083015260038301546060830152600483015460809092019160ff1690811115611ceb57611ceb6121ab565b6002811115611cfc57611cfc6121ab565b90525092915050565b60068181548110611730575f80fd5b611d1c611d84565b600180546001600160a01b0383166001600160a01b03199091168117909155611d4c5f546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b5f546001600160a01b031633146113935760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104e6565b611de561212a565b6004831015611e365760405162461bcd60e51b815260206004820181905260248201527f4e6f7420656e6f75676820636f696e7320696e207468652063617465676f727960448201526064016104e6565b611e3e61212a565b845f5b6004811015611f42575f868383604051602001611e68929190918252602082015260400190565b604051602081830303815290604052805190602001205f1c611e8a919061294d565b9050858181518110611e9e57611e9e6125cf565b6020026020010151848360048110611eb857611eb86125cf565b602002015285611ec960018961269c565b81518110611ed957611ed96125cf565b6020026020010151868281518110611ef357611ef36125cf565b602090810291909101015286611f0881612960565b975050838260048110611f1d57611f1d6125cf565b6020020151611f2c9084612595565b9250508080611f3a9061261b565b915050611e41565b509095945050505050565b611f5561212a565b611f5d61212a565b6004831015611fae5760405162461bcd60e51b815260206004820152601a60248201527f4e6f7420656e6f75676820636f696e7320617661696c61626c6500000000000060448201526064016104e6565b5f845b6004821015611378575f8582604051602001611fcf91815260200190565b604051602081830303815290604052805190602001205f1c611ff1919061294d565b611ffc906001612595565b90505f805b84811015612041578286826004811061201c5761201c6125cf565b60200201510361202f5760019150612041565b806120398161261b565b915050612001565b50801561205c57826120528161261b565b9350505050611fb1565b8185856004811061206f5761206f6125cf565b60200201528361207e8161261b565b94505082806120529061261b565b600180546001600160a01b031916905561140c815f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6040518060a00160405280606081526020015f81526020015f81526020015f81526020015f6002811115612125576121256121ab565b905290565b60405180608001604052806004906020820280368337509192915050565b5f8060408385031215612159575f80fd5b50508035926020909101359150565b5f81518084525f5b8181101561218c57602081850181015186830182015201612170565b505f602082860101526020601f19601f83011685010191505092915050565b634e487b7160e01b5f52602160045260245ffd5b600381106121db57634e487b7160e01b5f52602160045260245ffd5b9052565b5f815160a084526121f360a0850182612168565b90506020830151602085015260408301516040850152606083015160608501526080830151610bd360808601826121bf565b5f602080830181845280855180835260408601915060408160051b87010192508387015f5b8281101561227857603f198886030184526122668583516121df565b9450928501929085019060010161224a565b5092979650505050505050565b5f805f8060808587031215612298575f80fd5b5050823594602084013594506040840135936060013592509050565b634e487b7160e01b5f52604160045260245ffd5b5f82601f8301126122d7575f80fd5b8135602067ffffffffffffffff808311156122f4576122f46122b4565b8260051b604051601f19603f83011681018181108482111715612319576123196122b4565b604052938452858101830193838101925087851115612336575f80fd5b83870191505b848210156123555781358352918301919083019061233c565b979650505050505050565b5f8060408385031215612371575f80fd5b823567ffffffffffffffff80821115612388575f80fd5b612394868387016122c8565b935060208501359150808211156123a9575f80fd5b506123b6858286016122c8565b9150509250929050565b5f602082840312156123d0575f80fd5b81356001600160a01b03811681146123e6575f80fd5b9392505050565b8035600381106123fb575f80fd5b919050565b5f8060408385031215612411575f80fd5b61241a836123ed565b946020939093013593505050565b6080810181835f5b600481101561244f578151835260209283019290910190600101612430565b50505092915050565b602080825282518282018190525f9190848201906040850190845b8181101561248f57835183529284019291840191600101612473565b50909695505050505050565b5f602082840312156124ab575f80fd5b5035919050565b5f805f805f608086880312156124c6575f80fd5b6124cf866123ed565b9450602086013567ffffffffffffffff808211156124eb575f80fd5b818801915088601f8301126124fe575f80fd5b81358181111561250c575f80fd5b89602082850101111561251d575f80fd5b9699602092909201985095966040810135965060600135945092505050565b60a081525f61254e60a0830188612168565b9050856020830152846040830152836060830152610d4f60808301846121bf565b602081525f6123e660208301846121df565b634e487b7160e01b5f52601160045260245ffd5b808201808211156106a4576106a4612581565b6020808252600d908201526c496e76616c69642072616e676560981b604082015260600190565b634e487b7160e01b5f52603260045260245ffd5b600181811c908216806125f757607f821691505b60208210810361261557634e487b7160e01b5f52602260045260245ffd5b50919050565b5f6001820161262c5761262c612581565b5060010190565b6020808252600e908201526d139bdd08185d5d1a1bdc9a5e995960921b604082015260600190565b60208082526021908201527f417272617973206d757374206265206f66207468652073616d65206c656e67746040820152600d60fb1b606082015260800190565b818103818111156106a4576106a4612581565b60208082526010908201526f125b9d985b1a59081d1bdad95b88125160821b604082015260600190565b600181815b8085111561271357815f19048211156126f9576126f9612581565b8085161561270657918102915b93841c93908002906126de565b509250929050565b5f82612729575060016106a4565b8161273557505f6106a4565b816001811461274b576002811461275557612771565b60019150506106a4565b60ff84111561276657612766612581565b50506001821b6106a4565b5060208310610133831016604e8410600b8410161715612794575081810a6106a4565b61279e83836126d9565b805f19048211156127b1576127b1612581565b029392505050565b5f6123e6838361271b565b80820281158282048414176106a4576106a4612581565b634e487b7160e01b5f52601260045260245ffd5b5f826127fd576127fd6127db565b500490565b601f8211156109f3575f81815260208120601f850160051c810160208610156128285750805b601f850160051c820191505b8181101561284757828155600101612834565b505050505050565b815167ffffffffffffffff811115612869576128696122b4565b61287d8161287784546125e3565b84612802565b602080601f8311600181146128b0575f84156128995750858301515b5f19600386901b1c1916600185901b178555612847565b5f85815260208120601f198616915b828110156128de578886015182559484019460019091019084016128bf565b50858210156128fb57878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b60808152846080820152848660a08301375f60a086830101525f60a0601f19601f8801168301019050846020830152836040830152610d4f60608301846121bf565b5f8261295b5761295b6127db565b500690565b5f8161296e5761296e612581565b505f19019056fea26469706673582212209d83ff8fe9c33a41cd1d44c21af4e67f06c1afb7eedc9d0c51c4ac44e418494164736f6c63430008140033