false
true
0

Contract Address Details

0x5EE3c7c8De8c1d74BBc92720D1cdcD20496C487F

Contract Name
SCADAMiner
Creator
0x915b41–22723c at 0x53db86–641ccb
Balance
0 PLS ( )
Tokens
Fetching tokens...
Transactions
1,740 Transactions
Transfers
0 Transfers
Gas Used
0
Last Balance Update
26286281
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
SCADAMiner




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




Optimization runs
200
EVM Version
paris




Verified at
2025-12-09T07:49:57.764901Z

Constructor Arguments

0x00000000000000000000000069e23263927ae53e5ff3a898d082a83b7d6fb4380000000000000000000000003b1489f3ea4643b7e7b29548e2e2cfef094bb05e000000000000000000000000915b4145e169ce7352936e88546ac8667d22723c

Arg [0] (address) : 0x69e23263927ae53e5ff3a898d082a83b7d6fb438
Arg [1] (address) : 0x3b1489f3ea4643b7e7b29548e2e2cfef094bb05e
Arg [2] (address) : 0x915b4145e169ce7352936e88546ac8667d22723c

              

SCADAMiner.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

interface ISCADAToken {
    function transfer(address to, uint256 amount) external returns (bool);
    function balanceOf(address account) external view returns (uint256);
}

contract SCADAMiner is Ownable, ReentrancyGuard {
    using SafeERC20 for IERC20;

    struct UserPoolInfo {
        uint256 tokenDeposited;
        uint256 shares;
    }

    struct UserInfo {
        uint256 totalShares;
        uint256 rewardDebt;
        uint256 totalClaimed;
        mapping(uint256 => UserPoolInfo) pools;
    }

    struct TokenPool {
        address token;
        uint256 sharesPerToken;
        bool isActive;
        uint256 totalDeposited;
        uint256 totalWithdrawn;
        uint256 totalShares;        
        uint256 totalFeesCollected;
    }

    // Core state
    ISCADAToken public immutable scadaToken;
    address public immutable scadaManager;
    address public immutable creator;

    // Reward accounting
    uint256 public accRewardPerShare;
    uint256 public totalShares;
    uint256 public totalRewardsDistributed;

    // Pools & users
    TokenPool[] public tokenPools; // index 0 = dummy
    mapping(address => uint256) public tokenToPoolId;
    mapping(address => UserInfo) private _userInfo;

    // Settings
    uint256 public minDeposit = 1000 * 1e18;
    uint256 public exitFeePercent = 200; // 2% = 200 basis points


    // Events
    event PoolAdded(uint256 indexed poolId, address indexed token, uint256 sharesPerToken);
    event PoolUpdated(uint256 indexed poolId, uint256 sharesPerToken, bool isActive);
    event Deposit(address indexed user, uint256 indexed poolId, uint256 tokenAmount, uint256 sharesReceived);
    event Withdraw(address indexed user, uint256 indexed poolId, uint256 tokenAmount, uint256 sharesRedeemed, uint256 fee);
    event RewardsDistributed(uint256 amount, uint256 newAccRewardPerShare);
    event RewardsClaimed(address indexed user, uint256 amount);

    constructor(
        address _scadaToken,
        address _scadaManager,
        address _creator
    ) Ownable(_scadaManager) {
        require(_scadaToken != address(0) && _scadaManager != address(0) && _creator != address(0), "Invalid addresses");
        scadaToken = ISCADAToken(_scadaToken);
        scadaManager = _scadaManager;
        creator = _creator;

        // Dummy pool at index 0
        tokenPools.push(TokenPool({
            token: address(0),
            sharesPerToken: 0,
            isActive: false,
            totalDeposited: 0,
            totalWithdrawn: 0,
            totalShares: 0,
            totalFeesCollected: 0
        }));
    }

    modifier onlyManager() {
        require(msg.sender == scadaManager, "Only manager");
        _;
    }

    modifier onlyCreator() {
        require(msg.sender == creator, "Only creator");
        _;
    }

    // ========== Pool Management ==========

    function addPool(address token, uint256 sharesPerToken) external onlyCreator {
        require(token != address(0), "Invalid token");
        require(token != address(scadaToken), "Cannot stake SCADA");
        require(sharesPerToken > 0, "Invalid sharesPerToken");
        require(tokenToPoolId[token] == 0, "Pool exists");

        tokenPools.push(TokenPool({
            token: token,
            sharesPerToken: sharesPerToken,
            isActive: true,
            totalDeposited: 0,
            totalWithdrawn: 0,
            totalShares: 0,
            totalFeesCollected: 0
        }));

        uint256 poolId = tokenPools.length - 1;
        tokenToPoolId[token] = poolId;

        emit PoolAdded(poolId, token, sharesPerToken);
    }

    // ========== Reward Distribution ==========

    function distributeRewards(uint256 rewardAmount) external nonReentrant onlyManager {
        require(rewardAmount > 0, "No rewards");
        require(totalShares > 0, "No shares");

        accRewardPerShare += (rewardAmount * 1e18) / totalShares;
        totalRewardsDistributed += rewardAmount;

        emit RewardsDistributed(rewardAmount, accRewardPerShare);
    }

    // ========== User Functions ==========

    function deposit(uint256 poolId, uint256 amount) external nonReentrant {

        require(poolId > 0 && poolId < tokenPools.length, "Invalid pool");
        require(amount >= minDeposit, "Below minimum");

        TokenPool storage pool = tokenPools[poolId];
        require(pool.isActive, "Pool inactive");

        UserInfo storage user = _userInfo[msg.sender];

        // Claim pending rewards first
        _claimPending(msg.sender);

        // Calculate shares for this deposit at current rate
        uint256 sharesToAdd = (amount * pool.sharesPerToken) / 1e18;
        require(sharesToAdd > 0, "No shares received");

        // Transfer tokens
        IERC20(pool.token).safeTransferFrom(msg.sender, address(this), amount);

        // Update user pool-specific accounting
        user.pools[poolId].tokenDeposited += amount;
        user.pools[poolId].shares += sharesToAdd;

        // Update user global accounting
        user.totalShares += sharesToAdd;
        user.rewardDebt = (user.totalShares * accRewardPerShare) / 1e18;

        // Update pool accounting
        pool.totalDeposited += amount;
        pool.totalShares += sharesToAdd;
        totalShares += sharesToAdd;

        emit Deposit(msg.sender, poolId, amount, sharesToAdd);
    }

    function withdraw(uint256 poolId, uint256 tokenAmount) external nonReentrant {
        
        require(poolId > 0 && poolId < tokenPools.length, "Invalid pool");
        require(tokenAmount > 0, "Invalid amount");

        TokenPool storage pool = tokenPools[poolId];
        UserInfo storage user = _userInfo[msg.sender];
        UserPoolInfo storage userPool = user.pools[poolId];

        require(userPool.tokenDeposited >= tokenAmount, "Amount too large");
        
        _claimPending(msg.sender);

        uint256 sharesToRedeem = (userPool.shares * tokenAmount) / userPool.tokenDeposited;
        require(sharesToRedeem > 0, "No shares to redeem");

        uint256 availableTokens = pool.totalDeposited - pool.totalWithdrawn;
        require(availableTokens >= tokenAmount, "Insufficient pool liquidity");

        uint256 contractBalance = IERC20(pool.token).balanceOf(address(this));
        require(contractBalance >= tokenAmount, "Insufficient contract balance");

        uint256 fee = (tokenAmount * exitFeePercent) / 10000;
        uint256 tokenAfterFee = tokenAmount - fee;

        IERC20(pool.token).safeTransfer(msg.sender, tokenAfterFee);

        userPool.tokenDeposited -= tokenAmount;
        userPool.shares -= sharesToRedeem;
        user.totalShares -= sharesToRedeem;
        user.rewardDebt = (user.totalShares * accRewardPerShare) / 1e18;

        pool.totalWithdrawn += tokenAmount;
        pool.totalFeesCollected += fee;
        pool.totalShares -= sharesToRedeem;
        totalShares -= sharesToRedeem;

        emit Withdraw(msg.sender, poolId, tokenAmount, sharesToRedeem, fee);
    }

    function claimRewards() external nonReentrant {
        _claimPending(msg.sender);
    }

    function _claimPending(address userAddr) internal {
        UserInfo storage user = _userInfo[userAddr];
        if (user.totalShares == 0) return;

        uint256 accumulated = (user.totalShares * accRewardPerShare) / 1e18;
        if (accumulated <= user.rewardDebt) return;

        uint256 reward = accumulated - user.rewardDebt;
        user.rewardDebt = accumulated;
        user.totalClaimed += reward;
        require(scadaToken.transfer(userAddr, reward), "Reward transfer failed");

        emit RewardsClaimed(userAddr, reward);
    }

    // ========== View Functions ==========

    function pendingRewards(address userAddr) external view returns (uint256) {
        UserInfo storage user = _userInfo[userAddr];
        if (user.totalShares == 0) return 0;
        
        uint256 accumulated = (user.totalShares * accRewardPerShare) / 1e18;
        return accumulated > user.rewardDebt ? accumulated - user.rewardDebt : 0;
    }

 function getUserInfo(address userAddr, uint256 poolId) external view returns (
    uint256 tokenDeposited,
    uint256 poolShares,
    uint256 userTotalShares,
    uint256 pendingReward,
    uint256 totalClaimed
) {
    UserInfo storage user = _userInfo[userAddr];
    
    return (
        poolId > 0 && poolId < tokenPools.length ? user.pools[poolId].tokenDeposited : 0,
        poolId > 0 && poolId < tokenPools.length ? user.pools[poolId].shares : 0,
        user.totalShares,
        this.pendingRewards(userAddr),
        user.totalClaimed
    );
}

function getPoolInfo(uint256 poolId) external view returns (
    address token,
    uint256 sharesPerToken,
    bool isActive,
    uint256 totalDeposited,
    uint256 totalWithdrawn,
    uint256 availableLiquidity,
    uint256 poolTotalShares,
    uint256 totalFeesCollected
) {
    require(poolId < tokenPools.length, "Invalid pool");
    TokenPool storage pool = tokenPools[poolId];
    
    return (
        pool.token,
        pool.sharesPerToken,
        pool.isActive,
        pool.totalDeposited,
        pool.totalWithdrawn,
        pool.totalDeposited - pool.totalWithdrawn,
        pool.totalShares,
        pool.totalFeesCollected
    );
}

    function getPoolCount() external view returns (uint256) {
        return tokenPools.length - 1;
    }

    function calculateShares(uint256 poolId, uint256 tokenAmount) external view returns (uint256) {
        require(poolId > 0 && poolId < tokenPools.length, "Invalid pool");
        return (tokenAmount * tokenPools[poolId].sharesPerToken) / 1e18;
    }

    // ========== Admin Functions ==========

    function updatePool(uint256 poolId, uint256 sharesPerToken, bool isActive) external onlyCreator {
        require(poolId > 0 && poolId < tokenPools.length, "Invalid pool");
        
        tokenPools[poolId].sharesPerToken = sharesPerToken;
        tokenPools[poolId].isActive = isActive;
        
        emit PoolUpdated(poolId, sharesPerToken, isActive);
    }

    function setMinDeposit(uint256 _minDeposit) external onlyCreator {
        minDeposit = _minDeposit;
    }

    function setExitFee(uint256 _exitFeePercent) external onlyCreator {
        require(_exitFeePercent <= 1000, "Max 10%");
        exitFeePercent = _exitFeePercent;
    }

    function collectFees(address token, uint256 amount) external onlyCreator {
        uint256 poolId = tokenToPoolId[token];
        require(poolId > 0, "Invalid token");
        
        TokenPool storage pool = tokenPools[poolId];
        require(amount <= pool.totalFeesCollected, "Exceeds available fees");

        pool.totalFeesCollected -= amount;
        IERC20(token).safeTransfer(creator, amount);
    }

}
        

@openzeppelin/contracts/access/Ownable.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @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.
 *
 * The initial owner is set to the address provided by the deployer. 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;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

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

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @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 {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @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 {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _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);
    }
}
          

@openzeppelin/contracts/interfaces/IERC1363.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363.sol)

pragma solidity >=0.6.2;

import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";

/**
 * @title IERC1363
 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
 *
 * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
 * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
 */
interface IERC1363 is IERC20, IERC165 {
    /*
     * Note: the ERC-165 identifier for this interface is 0xb0202a11.
     * 0xb0202a11 ===
     *   bytes4(keccak256('transferAndCall(address,uint256)')) ^
     *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
     */

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @param data Additional data with no specified format, sent in call to `spender`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}
          

@openzeppelin/contracts/interfaces/IERC165.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC165.sol)

pragma solidity >=0.4.16;

import {IERC165} from "../utils/introspection/IERC165.sol";
          

@openzeppelin/contracts/interfaces/IERC20.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20.sol)

pragma solidity >=0.4.16;

import {IERC20} from "../token/ERC20/IERC20.sol";
          

@openzeppelin/contracts/security/ReentrancyGuard.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be _NOT_ENTERED
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == _ENTERED;
    }
}
          

@openzeppelin/contracts/token/ERC20/IERC20.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)

pragma solidity >=0.4.16;

/**
 * @dev Interface of the ERC-20 standard as defined in the ERC.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}
          

@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC-20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    /**
     * @dev An operation with an ERC-20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     *
     * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
     * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
     * set here.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            safeTransfer(token, to, value);
        } else if (!token.transferAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
     * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferFromAndCallRelaxed(
        IERC1363 token,
        address from,
        address to,
        uint256 value,
        bytes memory data
    ) internal {
        if (to.code.length == 0) {
            safeTransferFrom(token, from, to, value);
        } else if (!token.transferFromAndCall(from, to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
     * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
     * once without retrying, and relies on the returned value to be true.
     *
     * Reverts if the returned value is other than `true`.
     */
    function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            forceApprove(token, to, value);
        } else if (!token.approveAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            // bubble errors
            if iszero(success) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0, returndatasize())
                revert(ptr, returndatasize())
            }
            returnSize := returndatasize()
            returnValue := mload(0)
        }

        if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        bool success;
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            returnSize := returndatasize()
            returnValue := mload(0)
        }
        return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
    }
}
          

@openzeppelin/contracts/utils/Context.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @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;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}
          

@openzeppelin/contracts/utils/introspection/IERC165.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)

pragma solidity >=0.4.16;

/**
 * @dev Interface of the ERC-165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[ERC].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
          

Compiler Settings

{"outputSelection":{},"optimizer":{"runs":200,"enabled":true},"metadata":{"bytecodeHash":"ipfs"},"libraries":{},"evmVersion":"paris"}
              

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_scadaToken","internalType":"address"},{"type":"address","name":"_scadaManager","internalType":"address"},{"type":"address","name":"_creator","internalType":"address"}]},{"type":"error","name":"OwnableInvalidOwner","inputs":[{"type":"address","name":"owner","internalType":"address"}]},{"type":"error","name":"OwnableUnauthorizedAccount","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"error","name":"SafeERC20FailedOperation","inputs":[{"type":"address","name":"token","internalType":"address"}]},{"type":"event","name":"Deposit","inputs":[{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"uint256","name":"poolId","internalType":"uint256","indexed":true},{"type":"uint256","name":"tokenAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"sharesReceived","internalType":"uint256","indexed":false}],"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":"event","name":"PoolAdded","inputs":[{"type":"uint256","name":"poolId","internalType":"uint256","indexed":true},{"type":"address","name":"token","internalType":"address","indexed":true},{"type":"uint256","name":"sharesPerToken","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"PoolUpdated","inputs":[{"type":"uint256","name":"poolId","internalType":"uint256","indexed":true},{"type":"uint256","name":"sharesPerToken","internalType":"uint256","indexed":false},{"type":"bool","name":"isActive","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"RewardsClaimed","inputs":[{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RewardsDistributed","inputs":[{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"uint256","name":"newAccRewardPerShare","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Withdraw","inputs":[{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"uint256","name":"poolId","internalType":"uint256","indexed":true},{"type":"uint256","name":"tokenAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"sharesRedeemed","internalType":"uint256","indexed":false},{"type":"uint256","name":"fee","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"accRewardPerShare","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addPool","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"sharesPerToken","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"calculateShares","inputs":[{"type":"uint256","name":"poolId","internalType":"uint256"},{"type":"uint256","name":"tokenAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claimRewards","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"collectFees","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"creator","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"deposit","inputs":[{"type":"uint256","name":"poolId","internalType":"uint256"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"distributeRewards","inputs":[{"type":"uint256","name":"rewardAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"exitFeePercent","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getPoolCount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"sharesPerToken","internalType":"uint256"},{"type":"bool","name":"isActive","internalType":"bool"},{"type":"uint256","name":"totalDeposited","internalType":"uint256"},{"type":"uint256","name":"totalWithdrawn","internalType":"uint256"},{"type":"uint256","name":"availableLiquidity","internalType":"uint256"},{"type":"uint256","name":"poolTotalShares","internalType":"uint256"},{"type":"uint256","name":"totalFeesCollected","internalType":"uint256"}],"name":"getPoolInfo","inputs":[{"type":"uint256","name":"poolId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"tokenDeposited","internalType":"uint256"},{"type":"uint256","name":"poolShares","internalType":"uint256"},{"type":"uint256","name":"userTotalShares","internalType":"uint256"},{"type":"uint256","name":"pendingReward","internalType":"uint256"},{"type":"uint256","name":"totalClaimed","internalType":"uint256"}],"name":"getUserInfo","inputs":[{"type":"address","name":"userAddr","internalType":"address"},{"type":"uint256","name":"poolId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"minDeposit","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"pendingRewards","inputs":[{"type":"address","name":"userAddr","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"scadaManager","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract ISCADAToken"}],"name":"scadaToken","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setExitFee","inputs":[{"type":"uint256","name":"_exitFeePercent","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMinDeposit","inputs":[{"type":"uint256","name":"_minDeposit","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"sharesPerToken","internalType":"uint256"},{"type":"bool","name":"isActive","internalType":"bool"},{"type":"uint256","name":"totalDeposited","internalType":"uint256"},{"type":"uint256","name":"totalWithdrawn","internalType":"uint256"},{"type":"uint256","name":"totalShares","internalType":"uint256"},{"type":"uint256","name":"totalFeesCollected","internalType":"uint256"}],"name":"tokenPools","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"tokenToPoolId","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalRewardsDistributed","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalShares","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updatePool","inputs":[{"type":"uint256","name":"poolId","internalType":"uint256"},{"type":"uint256","name":"sharesPerToken","internalType":"uint256"},{"type":"bool","name":"isActive","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdraw","inputs":[{"type":"uint256","name":"poolId","internalType":"uint256"},{"type":"uint256","name":"tokenAmount","internalType":"uint256"}]}]
              

Contract Creation Code

0x60e0604052683635c9adc5dea0000060085560c86009553480156200002357600080fd5b50604051620020bb380380620020bb833981016040819052620000469162000304565b816001600160a01b0381166200007757604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b620000828162000297565b50600180556001600160a01b03831615801590620000a857506001600160a01b03821615155b8015620000bd57506001600160a01b03811615155b620000ff5760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b60448201526064016200006e565b6001600160a01b03928316608090815291831660a090815290831660c09081526040805160e0810182526000808252602082018181529282018181526060830182815296830182815295830182815294830182815260058054600181018255935292517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0600790930292830180546001600160a01b031916919099161790975591517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db183015594517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db28201805460ff191691151591909117905592517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db384015590517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db4830155517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db582015590517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db6909101556200034e565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b0381168114620002ff57600080fd5b919050565b6000806000606084860312156200031a57600080fd5b6200032584620002e7565b92506200033560208501620002e7565b91506200034560408501620002e7565b90509250925092565b60805160a05160c051611cfe620003bd6000396000818161024d0152818161062401528181610f62015281816111af015281816111fc0152818161132a015261167f0152600081816103a70152610de90152600081816101b1015281816106a9015261184b0152611cfe6000f3fe608060405234801561001057600080fd5b50600436106101a75760003560e01c806372ca14e6116100f9578063a033fcd411610097578063e2bbb15811610071578063e2bbb15814610444578063e5a583a914610457578063ee1725461461046a578063f2fde38b1461047357600080fd5b8063a033fcd4146103fe578063b3c740e814610411578063d587d3631461042457600080fd5b80638da5cb5b116100d35780638da5cb5b146103c95780638eec5d70146103da5780638fcc9cfb146103e2578063939d6237146103f557600080fd5b806372ca14e61461035e57806376e8424f1461036757806385da9e5a146103a257600080fd5b8063372500ab11610166578063441a3e7011610140578063441a3e701461031d57806359974e381461033057806369ab3e3214610343578063715018a61461035657600080fd5b8063372500ab146103035780633a98ef391461030b57806341b3d1851461031457600080fd5b8062583a15146101ac578062c0f916146101f057806302d05d3f146102485780632f380b351461026f57806331d7a262146102cd57806332a9caba146102ee575b600080fd5b6101d37f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b6102036101fe366004611ad1565b610486565b604080516001600160a01b0390981688526020880196909652931515948601949094526060850191909152608084015260a083019190915260c082015260e0016101e7565b6101d37f000000000000000000000000000000000000000000000000000000000000000081565b61028261027d366004611ad1565b6104e3565b604080516001600160a01b0390991689526020890197909752941515958701959095526060860192909252608085015260a084015260c083019190915260e0820152610100016101e7565b6102e06102db366004611b06565b61059e565b6040519081526020016101e7565b6103016102fc366004611b21565b610619565b005b6103016109aa565b6102e060035481565b6102e060085481565b61030161032b366004611b4b565b6109c6565b61030161033e366004611ad1565b610dd6565b610301610351366004611b7b565b610f57565b61030161107b565b6102e060095481565b61037a610375366004611b21565b61108d565b604080519586526020860194909452928401919091526060830152608082015260a0016101e7565b6101d37f000000000000000000000000000000000000000000000000000000000000000081565b6000546001600160a01b03166101d3565b6102e061118d565b6103016103f0366004611ad1565b6111a4565b6102e060025481565b61030161040c366004611b21565b6111f1565b6102e061041f366004611b4b565b611355565b6102e0610432366004611b06565b60066020526000908152604090205481565b610301610452366004611b4b565b6113cf565b610301610465366004611ad1565b611674565b6102e060045481565b610301610481366004611b06565b6116fd565b6005818154811061049657600080fd5b600091825260209091206007909102018054600182015460028301546003840154600485015460058601546006909601546001600160a01b039095169650929460ff909216939092919087565b600080600080600080600080600580549050891061051c5760405162461bcd60e51b815260040161051390611bb4565b60405180910390fd5b600060058a8154811061053157610531611bda565b60009182526020909120600790910201805460018201546002830154600384015460048501549495506001600160a01b0390931693919260ff909116916105788183611c06565b866005015487600601549850985098509850985098509850985050919395975091939597565b6001600160a01b0381166000908152600760205260408120805482036105c75750600092915050565b6000670de0b6b3a764000060025483600001546105e49190611c19565b6105ee9190611c30565b905081600101548111610602576000610611565b60018201546106119082611c06565b949350505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146106615760405162461bcd60e51b815260040161051390611c52565b6001600160a01b0382166106a75760405162461bcd60e51b815260206004820152600d60248201526c24b73b30b634b2103a37b5b2b760991b6044820152606401610513565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03160361071d5760405162461bcd60e51b815260206004820152601260248201527143616e6e6f74207374616b6520534341444160701b6044820152606401610513565b600081116107665760405162461bcd60e51b815260206004820152601660248201527524b73b30b634b21039b430b932b9a832b92a37b5b2b760511b6044820152606401610513565b6001600160a01b038216600090815260066020526040902054156107ba5760405162461bcd60e51b815260206004820152600b60248201526a506f6f6c2065786973747360a81b6044820152606401610513565b6040805160e0810182526001600160a01b0384811682526020820184815260019383018481526000606085018181526080860182815260a0870183815260c0880184815260058054808c01825581875299517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db06007909b029a8b0180546001600160a01b03191691909a161790985595517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db189015593517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db28801805460ff191691151591909117905590517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db3870155517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db486015590517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db585015590517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db69093019290925554909161094a91611c06565b6001600160a01b03841660008181526006602052604090819020839055519192509082907f6c5d0ef1d0199b6de41ecbce95f59643be4d723ca363faf92d756e61e82fb13e9061099d9086815260200190565b60405180910390a3505050565b6109b2611738565b6109bb33611791565b6109c460018055565b565b6109ce611738565b6000821180156109df575060055482105b6109fb5760405162461bcd60e51b815260040161051390611bb4565b60008111610a3c5760405162461bcd60e51b815260206004820152600e60248201526d125b9d985b1a5908185b5bdd5b9d60921b6044820152606401610513565b600060058381548110610a5157610a51611bda565b60009182526020808320338452600780835260408086208987526003810190945290942080549490930201935091841115610ac15760405162461bcd60e51b815260206004820152601060248201526f416d6f756e7420746f6f206c6172676560801b6044820152606401610513565b610aca33611791565b60008160000154858360010154610ae19190611c19565b610aeb9190611c30565b905060008111610b335760405162461bcd60e51b81526020600482015260136024820152724e6f2073686172657320746f2072656465656d60681b6044820152606401610513565b600084600401548560030154610b499190611c06565b905085811015610b9b5760405162461bcd60e51b815260206004820152601b60248201527f496e73756666696369656e7420706f6f6c206c697175696469747900000000006044820152606401610513565b84546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015610be3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c079190611c78565b905086811015610c595760405162461bcd60e51b815260206004820152601d60248201527f496e73756666696369656e7420636f6e74726163742062616c616e63650000006044820152606401610513565b600061271060095489610c6c9190611c19565b610c769190611c30565b90506000610c84828a611c06565b8854909150610c9d906001600160a01b03163383611946565b88866000016000828254610cb19190611c06565b9250508190555084866001016000828254610ccc9190611c06565b9091555050865485908890600090610ce5908490611c06565b90915550506002548754670de0b6b3a764000091610d0291611c19565b610d0c9190611c30565b876001018190555088886004016000828254610d289190611c91565b9250508190555081886006016000828254610d439190611c91565b9250508190555084886005016000828254610d5e9190611c06565b925050819055508460036000828254610d779190611c06565b9091555050604080518a8152602081018790529081018390528a9033907fe08737ac48a1dab4b1a46c7dc9398bd5bfc6d7ad6fabb7cd8caa254de14def359060600160405180910390a35050505050505050610dd260018055565b5050565b610dde611738565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610e455760405162461bcd60e51b815260206004820152600c60248201526b27b7363c9036b0b730b3b2b960a11b6044820152606401610513565b60008111610e825760405162461bcd60e51b815260206004820152600a6024820152694e6f207265776172647360b01b6044820152606401610513565b600060035411610ec05760405162461bcd60e51b81526020600482015260096024820152684e6f2073686172657360b81b6044820152606401610513565b600354610ed582670de0b6b3a7640000611c19565b610edf9190611c30565b60026000828254610ef09190611c91565b925050819055508060046000828254610f099190611c91565b90915550506002546040805183815260208101929092527f29e98ba00d07f171959c4ddcd2f3020debc7c52cf537a034d7e664340d098c6c910160405180910390a1610f5460018055565b50565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610f9f5760405162461bcd60e51b815260040161051390611c52565b600083118015610fb0575060055483105b610fcc5760405162461bcd60e51b815260040161051390611bb4565b8160058481548110610fe057610fe0611bda565b906000526020600020906007020160010181905550806005848154811061100957611009611bda565b906000526020600020906007020160020160006101000a81548160ff021916908315150217905550827fec70f7b7f8beefa9ff0456053baafec83986e3915f156e2ed04b0acb57d7dd55838360405161106e9291909182521515602082015260400190565b60405180910390a2505050565b6110836119aa565b6109c460006119d7565b6001600160a01b0382166000908152600760205260408120819081908190819086158015906110bd575060055487105b6110c85760006110da565b60008781526003820160205260409020545b6000881180156110eb575060055488105b6110f657600061110b565b60008881526003830160205260409020600101545b82546040516318ebd13160e11b81526001600160a01b038c16600482015230906331d7a26290602401602060405180830381865afa158015611151573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111759190611c78565b600290940154929b919a509850919650945092505050565b60055460009061119f90600190611c06565b905090565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146111ec5760405162461bcd60e51b815260040161051390611c52565b600855565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146112395760405162461bcd60e51b815260040161051390611c52565b6001600160a01b0382166000908152600660205260409020548061128f5760405162461bcd60e51b815260206004820152600d60248201526c24b73b30b634b2103a37b5b2b760991b6044820152606401610513565b6000600582815481106112a4576112a4611bda565b9060005260206000209060070201905080600601548311156113015760405162461bcd60e51b81526020600482015260166024820152754578636565647320617661696c61626c65206665657360501b6044820152606401610513565b828160060160008282546113159190611c06565b9091555061134f90506001600160a01b0385167f000000000000000000000000000000000000000000000000000000000000000085611946565b50505050565b60008083118015611367575060055483105b6113835760405162461bcd60e51b815260040161051390611bb4565b670de0b6b3a76400006005848154811061139f5761139f611bda565b906000526020600020906007020160010154836113bc9190611c19565b6113c69190611c30565b90505b92915050565b6113d7611738565b6000821180156113e8575060055482105b6114045760405162461bcd60e51b815260040161051390611bb4565b6008548110156114465760405162461bcd60e51b815260206004820152600d60248201526c42656c6f77206d696e696d756d60981b6044820152606401610513565b60006005838154811061145b5761145b611bda565b60009182526020909120600790910201600281015490915060ff166114b25760405162461bcd60e51b815260206004820152600d60248201526c506f6f6c20696e61637469766560981b6044820152606401610513565b336000818152600760205260409020906114cb90611791565b6000670de0b6b3a76400008360010154856114e69190611c19565b6114f09190611c30565b9050600081116115375760405162461bcd60e51b8152602060048201526012602482015271139bc81cda185c995cc81c9958d95a5d995960721b6044820152606401610513565b825461154e906001600160a01b0316333087611a27565b60008581526003830160205260408120805486929061156e908490611c91565b9091555050600085815260038301602052604081206001018054839290611596908490611c91565b90915550508154819083906000906115af908490611c91565b90915550506002548254670de0b6b3a7640000916115cc91611c19565b6115d69190611c30565b8260010181905550838360030160008282546115f29190611c91565b925050819055508083600501600082825461160d9190611c91565b9250508190555080600360008282546116269190611c91565b90915550506040805185815260208101839052869133917f36af321ec8d3c75236829c5317affd40ddb308863a1236d2d277a4025cccee1e910160405180910390a3505050610dd260018055565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146116bc5760405162461bcd60e51b815260040161051390611c52565b6103e88111156116f85760405162461bcd60e51b81526020600482015260076024820152664d61782031302560c81b6044820152606401610513565b600955565b6117056119aa565b6001600160a01b03811661172f57604051631e4fbdf760e01b815260006004820152602401610513565b610f54816119d7565b60026001540361178a5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610513565b6002600155565b6001600160a01b038116600090815260076020526040812080549091036117b6575050565b6000670de0b6b3a764000060025483600001546117d39190611c19565b6117dd9190611c30565b9050816001015481116117ef57505050565b60008260010154826118019190611c06565b9050818360010181905550808360020160008282546118209190611c91565b909155505060405163a9059cbb60e01b81526001600160a01b038581166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af1158015611894573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118b89190611ca4565b6118fd5760405162461bcd60e51b815260206004820152601660248201527514995dd85c99081d1c985b9cd9995c8819985a5b195960521b6044820152606401610513565b836001600160a01b03167ffc30cddea38e2bf4d6ea7d3f9ed3b6ad7f176419f4963bd81318067a4aee73fe8260405161193891815260200190565b60405180910390a250505050565b6040516001600160a01b038381166024830152604482018390526119a591859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050611a60565b505050565b6000546001600160a01b031633146109c45760405163118cdaa760e01b8152336004820152602401610513565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6040516001600160a01b03848116602483015283811660448301526064820183905261134f9186918216906323b872dd90608401611973565b600080602060008451602086016000885af180611a83576040513d6000823e3d81fd5b50506000513d91508115611a9b578060011415611aa8565b6001600160a01b0384163b155b1561134f57604051635274afe760e01b81526001600160a01b0385166004820152602401610513565b600060208284031215611ae357600080fd5b5035919050565b80356001600160a01b0381168114611b0157600080fd5b919050565b600060208284031215611b1857600080fd5b6113c682611aea565b60008060408385031215611b3457600080fd5b611b3d83611aea565b946020939093013593505050565b60008060408385031215611b5e57600080fd5b50508035926020909101359150565b8015158114610f5457600080fd5b600080600060608486031215611b9057600080fd5b83359250602084013591506040840135611ba981611b6d565b809150509250925092565b6020808252600c908201526b125b9d985b1a59081c1bdbdb60a21b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b818103818111156113c9576113c9611bf0565b80820281158282048414176113c9576113c9611bf0565b600082611c4d57634e487b7160e01b600052601260045260246000fd5b500490565b6020808252600c908201526b27b7363c9031b932b0ba37b960a11b604082015260600190565b600060208284031215611c8a57600080fd5b5051919050565b808201808211156113c9576113c9611bf0565b600060208284031215611cb657600080fd5b8151611cc181611b6d565b939250505056fea2646970667358221220f12f266c7f9efbb87fcb97991cc66f81c9a90a1cc62cf834a9bd0af9035b36d064736f6c6343000814003300000000000000000000000069e23263927ae53e5ff3a898d082a83b7d6fb4380000000000000000000000003b1489f3ea4643b7e7b29548e2e2cfef094bb05e000000000000000000000000915b4145e169ce7352936e88546ac8667d22723c

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106101a75760003560e01c806372ca14e6116100f9578063a033fcd411610097578063e2bbb15811610071578063e2bbb15814610444578063e5a583a914610457578063ee1725461461046a578063f2fde38b1461047357600080fd5b8063a033fcd4146103fe578063b3c740e814610411578063d587d3631461042457600080fd5b80638da5cb5b116100d35780638da5cb5b146103c95780638eec5d70146103da5780638fcc9cfb146103e2578063939d6237146103f557600080fd5b806372ca14e61461035e57806376e8424f1461036757806385da9e5a146103a257600080fd5b8063372500ab11610166578063441a3e7011610140578063441a3e701461031d57806359974e381461033057806369ab3e3214610343578063715018a61461035657600080fd5b8063372500ab146103035780633a98ef391461030b57806341b3d1851461031457600080fd5b8062583a15146101ac578062c0f916146101f057806302d05d3f146102485780632f380b351461026f57806331d7a262146102cd57806332a9caba146102ee575b600080fd5b6101d37f00000000000000000000000069e23263927ae53e5ff3a898d082a83b7d6fb43881565b6040516001600160a01b0390911681526020015b60405180910390f35b6102036101fe366004611ad1565b610486565b604080516001600160a01b0390981688526020880196909652931515948601949094526060850191909152608084015260a083019190915260c082015260e0016101e7565b6101d37f000000000000000000000000915b4145e169ce7352936e88546ac8667d22723c81565b61028261027d366004611ad1565b6104e3565b604080516001600160a01b0390991689526020890197909752941515958701959095526060860192909252608085015260a084015260c083019190915260e0820152610100016101e7565b6102e06102db366004611b06565b61059e565b6040519081526020016101e7565b6103016102fc366004611b21565b610619565b005b6103016109aa565b6102e060035481565b6102e060085481565b61030161032b366004611b4b565b6109c6565b61030161033e366004611ad1565b610dd6565b610301610351366004611b7b565b610f57565b61030161107b565b6102e060095481565b61037a610375366004611b21565b61108d565b604080519586526020860194909452928401919091526060830152608082015260a0016101e7565b6101d37f0000000000000000000000003b1489f3ea4643b7e7b29548e2e2cfef094bb05e81565b6000546001600160a01b03166101d3565b6102e061118d565b6103016103f0366004611ad1565b6111a4565b6102e060025481565b61030161040c366004611b21565b6111f1565b6102e061041f366004611b4b565b611355565b6102e0610432366004611b06565b60066020526000908152604090205481565b610301610452366004611b4b565b6113cf565b610301610465366004611ad1565b611674565b6102e060045481565b610301610481366004611b06565b6116fd565b6005818154811061049657600080fd5b600091825260209091206007909102018054600182015460028301546003840154600485015460058601546006909601546001600160a01b039095169650929460ff909216939092919087565b600080600080600080600080600580549050891061051c5760405162461bcd60e51b815260040161051390611bb4565b60405180910390fd5b600060058a8154811061053157610531611bda565b60009182526020909120600790910201805460018201546002830154600384015460048501549495506001600160a01b0390931693919260ff909116916105788183611c06565b866005015487600601549850985098509850985098509850985050919395975091939597565b6001600160a01b0381166000908152600760205260408120805482036105c75750600092915050565b6000670de0b6b3a764000060025483600001546105e49190611c19565b6105ee9190611c30565b905081600101548111610602576000610611565b60018201546106119082611c06565b949350505050565b336001600160a01b037f000000000000000000000000915b4145e169ce7352936e88546ac8667d22723c16146106615760405162461bcd60e51b815260040161051390611c52565b6001600160a01b0382166106a75760405162461bcd60e51b815260206004820152600d60248201526c24b73b30b634b2103a37b5b2b760991b6044820152606401610513565b7f00000000000000000000000069e23263927ae53e5ff3a898d082a83b7d6fb4386001600160a01b0316826001600160a01b03160361071d5760405162461bcd60e51b815260206004820152601260248201527143616e6e6f74207374616b6520534341444160701b6044820152606401610513565b600081116107665760405162461bcd60e51b815260206004820152601660248201527524b73b30b634b21039b430b932b9a832b92a37b5b2b760511b6044820152606401610513565b6001600160a01b038216600090815260066020526040902054156107ba5760405162461bcd60e51b815260206004820152600b60248201526a506f6f6c2065786973747360a81b6044820152606401610513565b6040805160e0810182526001600160a01b0384811682526020820184815260019383018481526000606085018181526080860182815260a0870183815260c0880184815260058054808c01825581875299517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db06007909b029a8b0180546001600160a01b03191691909a161790985595517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db189015593517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db28801805460ff191691151591909117905590517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db3870155517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db486015590517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db585015590517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db69093019290925554909161094a91611c06565b6001600160a01b03841660008181526006602052604090819020839055519192509082907f6c5d0ef1d0199b6de41ecbce95f59643be4d723ca363faf92d756e61e82fb13e9061099d9086815260200190565b60405180910390a3505050565b6109b2611738565b6109bb33611791565b6109c460018055565b565b6109ce611738565b6000821180156109df575060055482105b6109fb5760405162461bcd60e51b815260040161051390611bb4565b60008111610a3c5760405162461bcd60e51b815260206004820152600e60248201526d125b9d985b1a5908185b5bdd5b9d60921b6044820152606401610513565b600060058381548110610a5157610a51611bda565b60009182526020808320338452600780835260408086208987526003810190945290942080549490930201935091841115610ac15760405162461bcd60e51b815260206004820152601060248201526f416d6f756e7420746f6f206c6172676560801b6044820152606401610513565b610aca33611791565b60008160000154858360010154610ae19190611c19565b610aeb9190611c30565b905060008111610b335760405162461bcd60e51b81526020600482015260136024820152724e6f2073686172657320746f2072656465656d60681b6044820152606401610513565b600084600401548560030154610b499190611c06565b905085811015610b9b5760405162461bcd60e51b815260206004820152601b60248201527f496e73756666696369656e7420706f6f6c206c697175696469747900000000006044820152606401610513565b84546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015610be3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c079190611c78565b905086811015610c595760405162461bcd60e51b815260206004820152601d60248201527f496e73756666696369656e7420636f6e74726163742062616c616e63650000006044820152606401610513565b600061271060095489610c6c9190611c19565b610c769190611c30565b90506000610c84828a611c06565b8854909150610c9d906001600160a01b03163383611946565b88866000016000828254610cb19190611c06565b9250508190555084866001016000828254610ccc9190611c06565b9091555050865485908890600090610ce5908490611c06565b90915550506002548754670de0b6b3a764000091610d0291611c19565b610d0c9190611c30565b876001018190555088886004016000828254610d289190611c91565b9250508190555081886006016000828254610d439190611c91565b9250508190555084886005016000828254610d5e9190611c06565b925050819055508460036000828254610d779190611c06565b9091555050604080518a8152602081018790529081018390528a9033907fe08737ac48a1dab4b1a46c7dc9398bd5bfc6d7ad6fabb7cd8caa254de14def359060600160405180910390a35050505050505050610dd260018055565b5050565b610dde611738565b336001600160a01b037f0000000000000000000000003b1489f3ea4643b7e7b29548e2e2cfef094bb05e1614610e455760405162461bcd60e51b815260206004820152600c60248201526b27b7363c9036b0b730b3b2b960a11b6044820152606401610513565b60008111610e825760405162461bcd60e51b815260206004820152600a6024820152694e6f207265776172647360b01b6044820152606401610513565b600060035411610ec05760405162461bcd60e51b81526020600482015260096024820152684e6f2073686172657360b81b6044820152606401610513565b600354610ed582670de0b6b3a7640000611c19565b610edf9190611c30565b60026000828254610ef09190611c91565b925050819055508060046000828254610f099190611c91565b90915550506002546040805183815260208101929092527f29e98ba00d07f171959c4ddcd2f3020debc7c52cf537a034d7e664340d098c6c910160405180910390a1610f5460018055565b50565b336001600160a01b037f000000000000000000000000915b4145e169ce7352936e88546ac8667d22723c1614610f9f5760405162461bcd60e51b815260040161051390611c52565b600083118015610fb0575060055483105b610fcc5760405162461bcd60e51b815260040161051390611bb4565b8160058481548110610fe057610fe0611bda565b906000526020600020906007020160010181905550806005848154811061100957611009611bda565b906000526020600020906007020160020160006101000a81548160ff021916908315150217905550827fec70f7b7f8beefa9ff0456053baafec83986e3915f156e2ed04b0acb57d7dd55838360405161106e9291909182521515602082015260400190565b60405180910390a2505050565b6110836119aa565b6109c460006119d7565b6001600160a01b0382166000908152600760205260408120819081908190819086158015906110bd575060055487105b6110c85760006110da565b60008781526003820160205260409020545b6000881180156110eb575060055488105b6110f657600061110b565b60008881526003830160205260409020600101545b82546040516318ebd13160e11b81526001600160a01b038c16600482015230906331d7a26290602401602060405180830381865afa158015611151573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111759190611c78565b600290940154929b919a509850919650945092505050565b60055460009061119f90600190611c06565b905090565b336001600160a01b037f000000000000000000000000915b4145e169ce7352936e88546ac8667d22723c16146111ec5760405162461bcd60e51b815260040161051390611c52565b600855565b336001600160a01b037f000000000000000000000000915b4145e169ce7352936e88546ac8667d22723c16146112395760405162461bcd60e51b815260040161051390611c52565b6001600160a01b0382166000908152600660205260409020548061128f5760405162461bcd60e51b815260206004820152600d60248201526c24b73b30b634b2103a37b5b2b760991b6044820152606401610513565b6000600582815481106112a4576112a4611bda565b9060005260206000209060070201905080600601548311156113015760405162461bcd60e51b81526020600482015260166024820152754578636565647320617661696c61626c65206665657360501b6044820152606401610513565b828160060160008282546113159190611c06565b9091555061134f90506001600160a01b0385167f000000000000000000000000915b4145e169ce7352936e88546ac8667d22723c85611946565b50505050565b60008083118015611367575060055483105b6113835760405162461bcd60e51b815260040161051390611bb4565b670de0b6b3a76400006005848154811061139f5761139f611bda565b906000526020600020906007020160010154836113bc9190611c19565b6113c69190611c30565b90505b92915050565b6113d7611738565b6000821180156113e8575060055482105b6114045760405162461bcd60e51b815260040161051390611bb4565b6008548110156114465760405162461bcd60e51b815260206004820152600d60248201526c42656c6f77206d696e696d756d60981b6044820152606401610513565b60006005838154811061145b5761145b611bda565b60009182526020909120600790910201600281015490915060ff166114b25760405162461bcd60e51b815260206004820152600d60248201526c506f6f6c20696e61637469766560981b6044820152606401610513565b336000818152600760205260409020906114cb90611791565b6000670de0b6b3a76400008360010154856114e69190611c19565b6114f09190611c30565b9050600081116115375760405162461bcd60e51b8152602060048201526012602482015271139bc81cda185c995cc81c9958d95a5d995960721b6044820152606401610513565b825461154e906001600160a01b0316333087611a27565b60008581526003830160205260408120805486929061156e908490611c91565b9091555050600085815260038301602052604081206001018054839290611596908490611c91565b90915550508154819083906000906115af908490611c91565b90915550506002548254670de0b6b3a7640000916115cc91611c19565b6115d69190611c30565b8260010181905550838360030160008282546115f29190611c91565b925050819055508083600501600082825461160d9190611c91565b9250508190555080600360008282546116269190611c91565b90915550506040805185815260208101839052869133917f36af321ec8d3c75236829c5317affd40ddb308863a1236d2d277a4025cccee1e910160405180910390a3505050610dd260018055565b336001600160a01b037f000000000000000000000000915b4145e169ce7352936e88546ac8667d22723c16146116bc5760405162461bcd60e51b815260040161051390611c52565b6103e88111156116f85760405162461bcd60e51b81526020600482015260076024820152664d61782031302560c81b6044820152606401610513565b600955565b6117056119aa565b6001600160a01b03811661172f57604051631e4fbdf760e01b815260006004820152602401610513565b610f54816119d7565b60026001540361178a5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610513565b6002600155565b6001600160a01b038116600090815260076020526040812080549091036117b6575050565b6000670de0b6b3a764000060025483600001546117d39190611c19565b6117dd9190611c30565b9050816001015481116117ef57505050565b60008260010154826118019190611c06565b9050818360010181905550808360020160008282546118209190611c91565b909155505060405163a9059cbb60e01b81526001600160a01b038581166004830152602482018390527f00000000000000000000000069e23263927ae53e5ff3a898d082a83b7d6fb438169063a9059cbb906044016020604051808303816000875af1158015611894573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118b89190611ca4565b6118fd5760405162461bcd60e51b815260206004820152601660248201527514995dd85c99081d1c985b9cd9995c8819985a5b195960521b6044820152606401610513565b836001600160a01b03167ffc30cddea38e2bf4d6ea7d3f9ed3b6ad7f176419f4963bd81318067a4aee73fe8260405161193891815260200190565b60405180910390a250505050565b6040516001600160a01b038381166024830152604482018390526119a591859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050611a60565b505050565b6000546001600160a01b031633146109c45760405163118cdaa760e01b8152336004820152602401610513565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6040516001600160a01b03848116602483015283811660448301526064820183905261134f9186918216906323b872dd90608401611973565b600080602060008451602086016000885af180611a83576040513d6000823e3d81fd5b50506000513d91508115611a9b578060011415611aa8565b6001600160a01b0384163b155b1561134f57604051635274afe760e01b81526001600160a01b0385166004820152602401610513565b600060208284031215611ae357600080fd5b5035919050565b80356001600160a01b0381168114611b0157600080fd5b919050565b600060208284031215611b1857600080fd5b6113c682611aea565b60008060408385031215611b3457600080fd5b611b3d83611aea565b946020939093013593505050565b60008060408385031215611b5e57600080fd5b50508035926020909101359150565b8015158114610f5457600080fd5b600080600060608486031215611b9057600080fd5b83359250602084013591506040840135611ba981611b6d565b809150509250925092565b6020808252600c908201526b125b9d985b1a59081c1bdbdb60a21b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b818103818111156113c9576113c9611bf0565b80820281158282048414176113c9576113c9611bf0565b600082611c4d57634e487b7160e01b600052601260045260246000fd5b500490565b6020808252600c908201526b27b7363c9031b932b0ba37b960a11b604082015260600190565b600060208284031215611c8a57600080fd5b5051919050565b808201808211156113c9576113c9611bf0565b600060208284031215611cb657600080fd5b8151611cc181611b6d565b939250505056fea2646970667358221220f12f266c7f9efbb87fcb97991cc66f81c9a90a1cc62cf834a9bd0af9035b36d064736f6c63430008140033