ETH Price: $2,408.42 (-2.97%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Claim Rewards211065472024-11-03 10:34:1140 hrs ago1730630051IN
0x07E6F223...bBf973BcC
0 ETH0.00195694.14101994
Deposit211065042024-11-03 10:25:3540 hrs ago1730629535IN
0x07E6F223...bBf973BcC
0 ETH0.001342553.6551205
Stake Rewards211061982024-11-03 9:24:2341 hrs ago1730625863IN
0x07E6F223...bBf973BcC
0 ETH0.001260783.61287612
Stake Rewards211061872024-11-03 9:22:1141 hrs ago1730625731IN
0x07E6F223...bBf973BcC
0 ETH0.001217133.48776881
Stake Rewards211038162024-11-03 1:24:592 days ago1730597099IN
0x07E6F223...bBf973BcC
0 ETH0.002665853.62827133
Withdraw And Cla...211023362024-11-02 20:27:112 days ago1730579231IN
0x07E6F223...bBf973BcC
0 ETH0.001154275.7099906
Claim Rewards211023312024-11-02 20:25:592 days ago1730579159IN
0x07E6F223...bBf973BcC
0 ETH0.000805015.90307013
Stake Rewards211023292024-11-02 20:25:352 days ago1730579135IN
0x07E6F223...bBf973BcC
0 ETH0.000598875.48207509
Stake Rewards211023192024-11-02 20:23:352 days ago1730579015IN
0x07E6F223...bBf973BcC
0 ETH0.000549555.03058595
Stake Rewards211023152024-11-02 20:22:472 days ago1730578967IN
0x07E6F223...bBf973BcC
0 ETH0.000576595.27808508
Deposit211018182024-11-02 18:42:592 days ago1730572979IN
0x07E6F223...bBf973BcC
0 ETH0.003275119.83195906
Stake Rewards210984302024-11-02 7:20:232 days ago1730532023IN
0x07E6F223...bBf973BcC
0 ETH0.002454133.19215222
Stake Rewards210984092024-11-02 7:16:112 days ago1730531771IN
0x07E6F223...bBf973BcC
0 ETH0.002473233.21699384
Stake Rewards210983942024-11-02 7:13:112 days ago1730531591IN
0x07E6F223...bBf973BcC
0 ETH0.002447953.18411567
Stake Rewards210983912024-11-02 7:12:352 days ago1730531555IN
0x07E6F223...bBf973BcC
0 ETH0.002747753.57402106
Stake Rewards210983682024-11-02 7:07:472 days ago1730531267IN
0x07E6F223...bBf973BcC
0 ETH0.002761843.59234085
Claim Rewards210980862024-11-02 6:11:232 days ago1730527883IN
0x07E6F223...bBf973BcC
0 ETH0.001709383.77395861
Withdraw And Cla...210938082024-11-01 15:51:233 days ago1730476283IN
0x07E6F223...bBf973BcC
0 ETH0.0038975120.75909197
Claim Rewards210937072024-11-01 15:30:593 days ago1730475059IN
0x07E6F223...bBf973BcC
0 ETH0.002327715.16686131
Stake Rewards210908322024-11-01 5:53:473 days ago1730440427IN
0x07E6F223...bBf973BcC
0 ETH0.001133185.81730001
Claim Rewards210843912024-10-31 8:22:234 days ago1730362943IN
0x07E6F223...bBf973BcC
0 ETH0.001242539.11126138
Stake Rewards210785702024-10-30 12:50:595 days ago1730292659IN
0x07E6F223...bBf973BcC
0 ETH0.0024864611.84629538
Stake Rewards210785552024-10-30 12:47:595 days ago1730292479IN
0x07E6F223...bBf973BcC
0 ETH0.0021646210.31295801
Claim Rewards210782862024-10-30 11:54:115 days ago1730289251IN
0x07E6F223...bBf973BcC
0 ETH0.003742559.53079893
Withdraw And Cla...210781052024-10-30 11:17:475 days ago1730287067IN
0x07E6F223...bBf973BcC
0 ETH0.001946869.86561733
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Staking

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 800 runs

Other Settings:
default evmVersion
File 1 of 13 : Staking.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "./interfaces/ITreasury.sol";
import "./interfaces/IHelix.sol";
import "./interfaces/IKondux.sol";
import "./interfaces/IKonduxERC20.sol";
import "./types/AccessControlled.sol";

contract Staking is AccessControlled {
    using Counters for Counters.Counter;

    Counters.Counter private _depositIds;

    /**
     * @dev Struct representing a staker's information.
     */
    struct Staker {
        // The address of the staked token
        address token;
        // The address of the staker
        address staker;
        // The total amount of tokens deposited by the staker
        uint256 deposited;
        // The total amount of tokens redeemed by the staker
        uint256 redeemed;
        // The timestamp of the last update for this staker's deposit
        uint256 timeOfLastUpdate;
        // The timestamp of the staker's last deposit
        uint256 lastDepositTime;
        // The accumulated, but unclaimed rewards for the staker. These are calculated
        // each time a user writes to the contract
        uint256 unclaimedRewards;
        // The duration of the timelock applied to the staker's deposit
        uint256 timelock;
        // The category of the timelock applied to the staker's deposit
        uint8 timelockCategory;
        // ERC20 Ratio at the time of staking
        uint256 ratioERC20;
    } 

    enum LockingTimes {        
        OneMonth, // 0
        ThreeMonths, // 1
        SixMonths, // 2
        OneYear // 3
    }

    // The deposit IDs associated with a user's address
    mapping(address => uint[]) public userDepositsIds;

    // The Staker struct information associated with a deposit ID
    mapping(uint => Staker) public userDeposits;

    // Indicates whether a specific ERC20 token is authorized for staking
    mapping (address => bool) public authorizedERC20;

    // The minimum amount required to stake for a specific ERC20 token
    mapping (address => uint256) public minStakeERC20;

    // The compound frequency for a specific ERC20 token
    mapping (address => uint256) public compoundFreqERC20;

    // The rewards per hour for a specific ERC20 token
    mapping (address => uint256) public aprERC20;

    // The withdrawal fee for a specific ERC20 token
    mapping (address => uint256) public withdrawalFeeERC20;

    // The founders reward boost for a specific ERC20 token
    mapping (address => uint256) public foundersRewardBoostERC20;

    // The kNFT reward boost for a specific ERC20 token
    mapping (address => uint256) public kNFTRewardBoostERC20;

    // The ratio for a specific ERC20 token
    mapping (address => uint256) public ratioERC20;

    // The decimals of a specific ERC20 token
    mapping (address => uint8) public decimalsERC20;

    // The total amount staked for a specific ERC20 token
    mapping (address => uint256) public totalStaked;

    // The total amount staked by a user for a specific ERC20 token
    mapping (address => mapping (address => uint256)) public userTotalStakedByCoin;

    // The total amount rewarded for a specific ERC20 token
    mapping (address => uint256) public totalRewarded;

    // The total amount rewarded by a user for a specific ERC20 token
    mapping (address => mapping (address => uint256)) public userTotalRewardedByCoin;

    // The total amount paid as a withdrawal fee for a specific ERC20 token
    mapping (address => uint256) public totalWithdrawalFees;

    // The penalty for withdrawing early for a specific ERC20 token
    mapping (address => uint256) public earlyWithdrawalPenalty;

    // The boost for a specific timelock category
    mapping(uint => uint256) public timelockCategoryBoost;

    // The divisor for a specific token
    mapping (address => uint256) public divisorERC20;

    // The allowed dnaVersion for reward boost
    mapping (uint256 => bool) public allowedDnaVersions;

    // Map of timelock durartions
    mapping(uint8 => uint256) public timelockDurations;

    IHelix public helixERC20; // Helix ERC20 Token
    IERC721 public konduxERC721Founders; // Kondux ERC721 Founders Token
    address public konduxERC721kNFT; // Kondux ERC721 kNFT Token
    ITreasury public treasury; // Treasury Contract

    // Events
    // Emitted when a staker withdraws their rewards
    event Withdraw(address indexed user, uint256 liquidAmount, uint256 fees);

    // Emitted when a staker withdraws all their rewards
    event WithdrawAll(address indexed staker, uint256 amount);

    // Emitted when a staker compounds their rewards
    event Compound(address indexed staker, uint256 amount);

    // Emitted when a staker stakes their tokens
    event Stake(uint indexed id, address indexed staker, address token, uint256 amount);

    // Emitted when a staker unstakes their tokens
    event Unstake(address indexed staker, uint256 amount);

    // Emitted when a staker receives a reward
    event Reward(address indexed user, uint256 netRewards, uint256 fees);

    // Emitted when the rewards per hour is updated for a token
    event NewAPR(uint256 indexed amount, address indexed token);

    // Emitted when the minimum stake is updated for a token
    event NewMinStake(uint256 indexed amount, address indexed token);

    // Emitted when the compound frequency is updated for a token
    event NewCompoundFreq(uint256 indexed amount, address indexed token);

    // Emitted when the Helix ERC20 token is updated
    event NewHelixERC20(address indexed helixERC20);

    // Emitted when the Kondux ERC721 Founders token is updated
    event NewKonduxERC721Founders(address indexed konduxERC721Founders);

    // Emitted when the Kondux ERC721 kNFT token is updated
    event NewKonduxERC721kNFT(address indexed konduxERC721kNFT);

    // Emitted when the treasury address is updated
    event NewTreasury(address indexed treasury);

    // Emitted when the withdrawal fee is updated for a token
    event NewWithdrawalFee(uint256 indexed amount, address indexed token);

    // Emitted when the founders reward boost is updated for a token
    event NewFoundersRewardBoost(uint256 indexed amount, address indexed token);

    // Emitted when the kNFT reward boost is updated for a token
    event NewKNFTRewardBoost(uint256 indexed amount, address indexed token);

    // Emitted when a token is authorized or deauthorized for staking
    event NewAuthorizedERC20(address indexed token, bool indexed authorized);

    // Emitted when the ratio is updated for a token
    event NewRatio(uint256 indexed amount, address indexed token);

    // Emitted when a new divisor is set for a token
    event NewDivisorERC20(uint256 indexed amount, address indexed token);
 

    /**
     * @dev Initializes the staking contract with the provided parameters.
     *
     * @param _authority The address of the authority contract.
     * @param _konduxERC20 The address of the Kondux ERC20 token contract.
     * @param _treasury The address of the treasury contract.
     * @param _konduxERC721Founders The address of the Kondux ERC721 Founders token contract.
     * @param _konduxERC721kNFT The address of the Kondux ERC721 kNFT token contract.
     * @param _helixERC20 The address of the Helix ERC20 token contract.
     *
     * The constructor sets up the initial state of the staking contract by initializing contract variables,
     * setting up default staking token parameters, and authorizing the Kondux ERC20 token for staking.
     */
    constructor(
        address _authority,
        address _konduxERC20,
        address _treasury,
        address _konduxERC721Founders,
        address _konduxERC721kNFT,
        address _helixERC20
    ) AccessControlled(IAuthority(_authority)) {
        // Ensure the provided addresses are valid
        require(_konduxERC20 != address(0), "Kondux ERC20 address is not set");
        require(_treasury != address(0), "Treasury address is not set");
        require(_konduxERC721Founders != address(0), "Kondux ERC721 Founders address is not set");
        require(_konduxERC721kNFT != address(0), "Kondux ERC721 kNFT address is not set");
        require(_helixERC20 != address(0), "Helix ERC20 address is not set");

        // Initialize contract variables
        konduxERC721Founders = IERC721(_konduxERC721Founders);
        konduxERC721kNFT = _konduxERC721kNFT;
        helixERC20 = IHelix(_helixERC20);
        treasury = ITreasury(_treasury);

        timelockDurations[0] = 30 days;         // 1 month
        timelockDurations[1] = 90 days;         // 3 months
        timelockDurations[2] = 180 days;        // 6 months
        timelockDurations[3] = 365 days;        // 1 year

        // Set up default staking token parameters
        setDivisorERC20(10_000, _konduxERC20); // 10,000 basis points
        setWithdrawalFee(100, _konduxERC20); // 1% fee on withdrawal or 100 / 10_000
        setFoundersRewardBoost(1_000, _konduxERC20); // 10% boost (=110%) on rewards or 1,000,000/10,000,000
        setkNFTRewardBoost(500, _konduxERC20); // 5% boost on rewards or 500 / 
        setMinStake(10_000_000, _konduxERC20); // 10,000,000 wei
        setAPR(25, _konduxERC20); // 0.00285%/h or 25% APR
        setCompoundFreq(60 * 60 * 24, _konduxERC20); // 24 hours
        setRatio(10_000, _konduxERC20); // 10,000:1 ratio, adjusted for kondux ERC20 decimals
        setEarlyWithdrawalPenalty(_konduxERC20, 10); // 10% penalty
        setTimelockCategoryBoost(1, 100); // 1% boost for 90 days timelock
        setTimelockCategoryBoost(2, 300); // 3% boost for 180 days timelock 
        setTimelockCategoryBoost(3, 900); // 9% boost for 365 days timelock
        setAllowedDnaVersion(1, true); // allow DNA version 1
        setDecimalsERC20(helixERC20.decimals(), _helixERC20); // set decimals for Helix ERC20 token 
        setDecimalsERC20(IKonduxERC20(_konduxERC20).decimals(), _konduxERC20); // set decimals for Kondux ERC20 token

        _setAuthorizedERC20(_konduxERC20, true);
    }

    /**
     * @dev This function allows a user to deposit a specified amount of an authorized token with a selected timelock period.
     *      The function checks the user's token balance, allowance, and the timelock value before proceeding.
     *      It then creates a new deposit record, sets the timelock based on the selected category, and updates the user's
     *      deposit list and total staked amount. The specified amount of tokens is transferred from the user to the vault,
     *      and an equivalent amount of reward tokens is minted for the user.
     * @param _amount The amount of tokens to deposit.
     * @param _timelock The timelock category, represented as an integer (0-4).
     * @param _token The address of the token contract.
     * @return _id The deposit ID assigned to this deposit.
     */
    function deposit(uint256 _amount, uint8 _timelock, address _token) public returns (uint) {
        // Check if the token address is set
        require(_token != address(0), "Token address is not set");
        // Check if the token is authorized for staking
        require(authorizedERC20[_token], "Token not authorized");
        // Check if the deposit amount is greater than or equal to the minimum required stake
        require(_amount >= minStakeERC20[_token], "Amount smaller than minimimum deposit");
        IERC20 konduxERC20 = IERC20(_token);
        // Check if the user has enough balance to stake the specified amount
        require(konduxERC20.balanceOf(msg.sender) >= _amount, "Can't stake more than you own");
        // Check if the user has approved the staking contract to spend the specified amount
        require(konduxERC20.allowance(msg.sender, address(this)) >= _amount, "Allowance not set");
        // Check if the selected timelock category is valid (between 0 and 3)
        require(_timelock <= 3, "Invalid timelock");

        // Get the current deposit ID
        uint _id = _depositIds.current();

        // Create a new deposit record for the user
        userDeposits[_id] = Staker({
            token: _token,
            staker: msg.sender,
            deposited: _amount,
            unclaimedRewards: 0,
            timelock: block.timestamp + timelockDurations[_timelock], // Set the timelock period based on the selected category
            timelockCategory: _timelock,
            timeOfLastUpdate: block.timestamp,
            lastDepositTime: block.timestamp,
            redeemed: 0,
            ratioERC20: ratioERC20[_token]
        });

        // Add the deposit ID to the user's deposit list
        userDepositsIds[msg.sender].push(_id);

        // Update the user's total staked amount
        _addTotalStakedAmount(_amount, _token, msg.sender);
        
        // Mint an equivalent amount of reward tokens for the user
        // Get the decimals of the original staked token and Helix
        uint8 originalTokenDecimals = decimalsERC20[_token];
        uint8 helixDecimals = decimalsERC20[address(helixERC20)];

        // Calculate the decimal difference
        uint decimalDifference;
        if (helixDecimals > originalTokenDecimals) {
            decimalDifference = helixDecimals - originalTokenDecimals;
        } else {
            decimalDifference = 0;
        }

        // Transfer the deposited tokens from the user to the vault
        konduxERC20.transferFrom(msg.sender, authority.vault(), _amount);

        // Mint an equivalent amount of reward tokens for the user, adjusted based on the decimal difference
        helixERC20.mint(msg.sender, _amount * ratioERC20[_token] * (10 ** decimalDifference));

        // Increment the deposit ID counter
        _depositIds.increment();

        // Emit a Stake event
        emit Stake(_id, msg.sender, _token, _amount);

        return _id;
    }

    /**
     * @dev This function allows the owner of a deposit to stake their earned rewards.
     *      It verifies that the caller is the deposit owner and that the compounding is not happening too soon.
     *      The function calculates the rewards, resets the unclaimed rewards to zero, and updates the deposit record.
     *      The total staked amount is updated, and an equivalent amount of reward tokens is minted for the user.
     * @param _depositId The ID of the deposit whose rewards are to be staked.
     */
    function stakeRewards(uint _depositId) public {
        // Verify that the caller is the owner of the deposit
        require(msg.sender == userDeposits[_depositId].staker, "You are not the owner of this deposit");
        // Verify that the user is not trying to compound rewards too soon
        // require(compoundRewardsTimer(_depositId) == 0, "Tried to compound rewards too soon");

        // Calculate the rewards and add any unclaimed rewards
        uint256 rewards = calculateRewards(msg.sender, _depositId) + userDeposits[_depositId].unclaimedRewards;

        // Check if the rewards are non-zero
        require(rewards > 0, "No rewards available");

        // Reset the unclaimed rewards to zero
        userDeposits[_depositId].unclaimedRewards = 0;
        // Update the deposited amount with the compounded rewards
        userDeposits[_depositId].deposited += rewards;
        // Update the time of the last update
        userDeposits[_depositId].timeOfLastUpdate = block.timestamp;

        // Update the user's total staked amount
        _addTotalStakedAmount(rewards, userDeposits[_depositId].token, userDeposits[_depositId].staker);

        // Mint an equivalent amount of reward tokens for the user
        // Get the decimals of the original staked token and Helix
        uint8 originalTokenDecimals = decimalsERC20[userDeposits[_depositId].token];
        uint8 helixDecimals = decimalsERC20[address(helixERC20)];

        // Calculate the decimal difference
        uint decimalDifference;
        if (helixDecimals > originalTokenDecimals) {
            decimalDifference = helixDecimals - originalTokenDecimals;
        } else {
            decimalDifference = 0;
        }

        // Mint the calculated rewards for the user, adjusted based on the decimal difference
        helixERC20.mint(msg.sender, rewards * userDeposits[_depositId].ratioERC20 * (10 ** decimalDifference));

        // Emit a Compound event
        emit Compound(msg.sender, rewards);
    }

    /**
     * @dev This function allows the owner of a deposit to claim their earned rewards.
     *      It verifies that the caller is the deposit owner and that the timelock has passed.
     *      The function calculates the rewards, resets the unclaimed rewards to zero, and updates the deposit record.
     *      The reward tokens are burned, and the earned rewards are transferred to the user from the vault.
     *      The function emits a Reward event upon successful execution.
     * @param _depositId The ID of the deposit whose rewards are to be claimed.
     */
    function claimRewards(uint _depositId) public {
        require(msg.sender == userDeposits[_depositId].staker, "You are not the owner of this deposit");
        require(block.timestamp >= userDeposits[_depositId].timelock, "Timelock not passed");

        uint256 rewards = calculateRewards(msg.sender, _depositId) + userDeposits[_depositId].unclaimedRewards;

        require(rewards > 0, "You have no rewards");

        userDeposits[_depositId].unclaimedRewards = 0;
        userDeposits[_depositId].timeOfLastUpdate = block.timestamp;

        IERC20 konduxERC20 = IERC20(userDeposits[_depositId].token);

        uint256 netRewards = (rewards * (10_000 - withdrawalFeeERC20[userDeposits[_depositId].token])) / divisorERC20[userDeposits[_depositId].token];
        uint256 fees = rewards - netRewards;

        konduxERC20.transferFrom(authority.vault(), msg.sender, netRewards); 

        _addTotalRewardedAmount(netRewards, userDeposits[_depositId].token, userDeposits[_depositId].staker);
        _addTotalWithdrawalFees(rewards - netRewards, userDeposits[_depositId].token);

        emit Reward(msg.sender, netRewards, fees);
    }

    /**
     * @dev This function allows the owner of a deposit to withdraw a specified amount of their deposited tokens.
     *      It verifies that the timelock has passed, the caller is the deposit owner, and the withdrawal amount
     *      is within the available limits. The function calculates the rewards, updates the deposit record, and
     *      transfers the liquid amount to the user after applying the withdrawal fee. The collateral tokens are burned.
     *      The function emits a Withdraw event upon successful execution.
     * @param _amount The amount of tokens to withdraw.
     * @param _depositId The ID of the deposit from which to withdraw the tokens.
     */
    function withdraw(uint256 _amount, uint _depositId) public {
        // Verify that the timelock has passed
        require(block.timestamp >= userDeposits[_depositId].timelock, "Timelock not passed");
        // Verify that the caller is the owner of the deposit
        require(msg.sender == userDeposits[_depositId].staker, "You are not the owner of this deposit");
        // Verify that the withdrawal amount is within the available limits
        require(userDeposits[_depositId].deposited >= _amount, "Can't withdraw more than you have");
        // Verify that the withdrawal amount is less than or equal to the collateral tokens the user has
        require(_amount * userDeposits[_depositId].ratioERC20 <= helixERC20.balanceOf(msg.sender), "Can't withdraw more tokens than the collateral you have");

        // Calculate the rewards
        uint256 _rewards = calculateRewards(msg.sender, _depositId);
        // Update the deposit record
        userDeposits[_depositId].deposited -= _amount;
        userDeposits[_depositId].timeOfLastUpdate = block.timestamp;
        userDeposits[_depositId].unclaimedRewards += _rewards;

        // Calculate the liquid amount to transfer after applying the withdrawal fee
        uint256 _liquid = (_amount * (divisorERC20[userDeposits[_depositId].token] - withdrawalFeeERC20[userDeposits[_depositId].token])) / divisorERC20[userDeposits[_depositId].token];
        uint256 fees = _amount - _liquid;

        // Get the token contract
        IERC20 konduxERC20 = IERC20(userDeposits[_depositId].token);

        // Check if the treasury contract has approved the staking contract to withdraw the tokens
        require(konduxERC20.allowance(authority.vault(), address(this)) >= _liquid, "Treasury Contract need to approve Staking Contract to withdraw your tokens -- please call an Admin");

        // Subtract the staked amount
        _subtractStakedAmount(_amount, userDeposits[_depositId].token, userDeposits[_depositId].staker);

        // Get the decimals of the original staked token and Helix
        uint8 originalTokenDecimals = decimalsERC20[userDeposits[_depositId].token];
        uint8 helixDecimals = decimalsERC20[address(helixERC20)];

        // Calculate the decimal difference
        uint decimalDifference;
        if (originalTokenDecimals < helixDecimals) {
            decimalDifference = helixDecimals - originalTokenDecimals;
        } else {
            decimalDifference = 0;
        }

        // Burn the equivalent amount of collateral tokens, adjusted based on the decimal difference
        helixERC20.burn(msg.sender, _amount * userDeposits[_depositId].ratioERC20 * (10 ** decimalDifference));

        
        // Transfer the liquid amount to the user
        konduxERC20.transferFrom(authority.vault(), msg.sender, _liquid);

        // Update the user's total rewarded amount + total rewarded amount for the token
        _addTotalRewardedAmount(_liquid, userDeposits[_depositId].token, userDeposits[_depositId].staker); 
        _addTotalWithdrawalFees(_amount - _liquid, userDeposits[_depositId].token); 

        // Emit a Withdraw event
        emit Withdraw(msg.sender, _liquid, fees);
    }

    /**
     * @dev This function allows the owner of a deposit to withdraw a specified amount of their deposited tokens
     *      before the timelock has passed. The user is punished by not receiving any reward boosts and paying an extra
     *      fee proportional to the time left until the lock (the closer to the end of the locking time, the smaller the fee,
     *      starting at 10%).
     *      It verifies that the caller is the deposit owner, and the withdrawal amount is within the available limits.
     *      The function calculates the rewards, updates the deposit record, and transfers the liquid amount to the user
     *      after applying the extra fee and withdrawal fee. The collateral tokens are burned.
     *      The function emits a Withdraw event upon successful execution.
     * @param _amount The amount of tokens to withdraw.
     * @param _depositId The ID of the deposit from which to withdraw the tokens.
     */
    function earlyUnstake(uint256 _amount, uint _depositId) public {
        // Verify that the caller is the owner of the deposit
        require(msg.sender == userDeposits[_depositId].staker, "You are not the owner of this deposit");
        // Verify that the withdrawal amount is within the available limits
        require(userDeposits[_depositId].deposited >= _amount, "Can't withdraw more than you have");
        // Verify that the withdrawal amount is less than or equal to the collateral tokens the user has
        require(_amount * userDeposits[_depositId].ratioERC20 <= helixERC20.balanceOf(msg.sender), "Can't withdraw more tokens than the collateral you have");
        // Verify if the timelock has passed
        require(block.timestamp < userDeposits[_depositId].timelock, "Timelock has passed");

        // Calculate the extra fee proportional to the time left until the lock (the closer to the end of the locking time, the smaller the fee)
        uint256 timeLeft = userDeposits[_depositId].timelock - block.timestamp;
        uint256 lockDuration = userDeposits[_depositId].timelock - userDeposits[_depositId].lastDepositTime;
        uint256 extraFee = (_amount * earlyWithdrawalPenalty[userDeposits[_depositId].token] * timeLeft) / (lockDuration * 100);

        // If extra fee is more than the amount, set it to the amount
        if (extraFee > _amount) {
            extraFee = _amount;
        }

        // If extra fee is zero, apply 1% fee
        if (extraFee == 0) {
            extraFee = (_amount * 1) / 100;
        }

        // Calculate the total fee percentage
        uint256 totalFeePercentage = extraFee + withdrawalFeeERC20[userDeposits[_depositId].token];

        // Calculate the liquid amount to transfer after applying the total fee
        uint256 _liquid = (_amount - totalFeePercentage);
        uint256 fees = _amount - _liquid;

        // Update the deposit record
        userDeposits[_depositId].deposited -= _amount;
        userDeposits[_depositId].timeOfLastUpdate = block.timestamp;

        // Get the token contract
        IERC20 konduxERC20 = IERC20(userDeposits[_depositId].token);

        // Check if the treasury contract has approved the staking contract to withdraw the tokens
        require(konduxERC20.allowance(authority.vault(), address(this)) >= _liquid, "Treasury Contract need to approve Staking Contract to withdraw your tokens -- please call an Admin");

        // Subtract the staked amount
        _subtractStakedAmount(_amount, userDeposits[_depositId].token, userDeposits[_depositId].staker);

        // Calculate the decimal difference
        uint decimalDifference;
        if (decimalsERC20[userDeposits[_depositId].token] < decimalsERC20[address(helixERC20)]) {
            decimalDifference = decimalsERC20[address(helixERC20)] - decimalsERC20[userDeposits[_depositId].token];
        } else {
            decimalDifference = 0;
        }

        // Burn the equivalent amount of collateral tokens, adjusted based on the decimal difference
        helixERC20.burn(msg.sender, _amount * userDeposits[_depositId].ratioERC20 * (10 ** decimalDifference));
        
        // Transfer the liquid amount to the user
        konduxERC20.transferFrom(authority.vault(), msg.sender, _liquid);

        // Update the user's total rewarded amount + total rewarded amount for the token
        _addTotalRewardedAmount(_liquid, userDeposits[_depositId].token, userDeposits[_depositId].staker); 
        _addTotalWithdrawalFees(_amount - _liquid, userDeposits[_depositId].token); 

        // Emit a Withdraw event
        emit Withdraw(msg.sender, _liquid, fees);
    }

    /**
     * @dev This function allows the owner of a deposit to withdraw a specified amount of their deposited tokens
     *      and claim their earned rewards in a single transaction. It calls the withdraw and claimRewards functions.
     * @param _amount The amount of tokens to withdraw.
     * @param _depositId The ID of the deposit from which to withdraw the tokens and claim the rewards.
     */
    function withdrawAndClaim(uint256 _amount, uint _depositId) public {
        withdraw(_amount, _depositId);
        claimRewards(_depositId);
    }

    /**
     * @dev This function returns the remaining time until the next allowed compounding action for a given deposit ID.
     *      It calculates the remaining time based on the compound frequency for the deposited token.
     *      If the timer has already passed, it returns 0.
     * @param _depositId The ID of the deposit for which to return the compound timer.
     * @return remainingTime The remaining time until the next allowed compounding action in seconds.
     */
    function compoundRewardsTimer(uint _depositId) public view returns (uint256 remainingTime) {
        uint256 lastUpdateTime = userDeposits[_depositId].timeOfLastUpdate;
        uint256 compoundFrequency = compoundFreqERC20[userDeposits[_depositId].token];

        if (block.timestamp >= lastUpdateTime + compoundFrequency) {
            return 0;
        }

        remainingTime = (lastUpdateTime + compoundFrequency) - block.timestamp;
        return remainingTime;
    }

    /**
     * @dev This function calculates the rewards for a specified staker and deposit ID. The rewards calculation
     *      considers the deposit's elapsed time, staked amount, and a 25% APY compounded hourly.
     *      If the provided staker is not the owner of the deposit, the function returns 0.
     * @param _staker The address of the staker for which to calculate the rewards.
     * @param _depositId The ID of the deposit for which to calculate the rewards.
     * @return rewards The calculated rewards for the specified staker and deposit ID.
     */
    function calculateRewards(address _staker, uint _depositId) public view returns (uint256 rewards) {
        // Retrieve deposit details by _depositId
        Staker memory deposit_ = userDeposits[_depositId];

        // Check if the staker is the owner of the deposit; if not, return 0
        if (deposit_.staker != _staker) {
            return 0;
        }

        // Calculate the elapsed time since the last update
        uint256 elapsedTime = block.timestamp - deposit_.timeOfLastUpdate;
        // Get the deposited amount
        uint256 depositedAmount = deposit_.deposited;

        // Calculate the base reward per second using the token's APR
        uint256 tokenApr = aprERC20[deposit_.token];

        /**
         * @dev This line calculates the reward earned per second by a staker for their deposit, considering the deposit's APR (annual percentage rate).
         *
         * The formula breakdown:
         * 1. depositedAmount: The amount of tokens the staker deposited.
         * 2. tokenApr: The annual percentage rate for the token in question (e.g. 25% APR).
         * 3. 1e18: A scaling factor used to maintain precision in the calculations (10^18 or 1 followed by 18 zeros).
         * 4. 365 * 24 * 3600: The total number of seconds in a year, used to convert the APR to a per-second rate.
         * 5. 100: Used to convert the APR percentage to a decimal (e.g. 25% becomes 0.25).
         *
         * The formula calculates the per-second reward by multiplying the deposited amount and the token's APR, and then scaling it up by 1e18.
         * After that, it divides the result by the total number of seconds in a year and by 100 to adjust for the percentage.
         *
         * Using 1e18 maintains precision in the calculation, avoiding truncation errors due to integer division in Solidity.
         * By scaling up the result and performing the divisions afterward, the calculation maintains precision without truncating intermediate results to zero.
         */
        uint256 rewardPerSecond = (depositedAmount * tokenApr * 1e18) / (365 * 24 * 3600 * 100);
        
        // Calculate the base reward based on elapsed time
        uint256 _reward = elapsedTime * rewardPerSecond / 1e18;

        // Calculate the boost percentage
        uint256 boostPercentage = calculateBoostPercentage(_staker, _depositId);

        // Calculate the final reward by applying the boost percentage
        _reward = (_reward * boostPercentage) / divisorERC20[deposit_.token];

        // Return the calculated reward
        return _reward;
    }      

    // Internal functions:

    /**
     * @dev This internal function calculates the compounded rewards for a given deposited amount and number of elapsed periods.
     *      The function assumes a fixed 25% APR and 8760 periods per year (hourly compounding). It uses exponentiation to calculate
     *      the compounded rewards using the formula A = P * (1 + r/n)^(nt), where:
     *          A: final amount after compounding
     *          P: initial deposited amount
     *          r: annual interest rate (25%)
     *          n: number of periods in a year (8760)
     *          t: number of elapsed periods
     * @param _depositedAmount The initial deposited amount.
     * @param _periodsElapsed The number of elapsed periods (hours) since the deposit.
     * @return compound The calculated compounded rewards for the given deposited amount and elapsed periods.
     */
    function _calculateCompound(uint256 _depositedAmount, uint256 _periodsElapsed) internal pure returns (uint256 compound) {
        uint256 periodsInYear = 8760; // 24 hours * 365 days
        uint256 compoundFactor = 1 + (25 * 1e1 / periodsInYear);

        //Calculate compounded rewards using exponentiation (A = P * (1 + r/n)^(nt))
        compound = _depositedAmount * (compoundFactor ** _periodsElapsed) / (1e1 ** _periodsElapsed);

        return compound;        
    }
        
        
    // Functions for modifying  staking mechanism variables:
    /**
     * @dev This internal function is used to update the total rewarded amount and the total rewarded amount
     *      for a specific user and token. It is called when rewards are distributed or staked.
     * @param _amount The amount of tokens to add to the total rewarded and user's total rewarded.
     * @param _token The address of the token contract.
     * @param _user The address of the user receiving the rewards.
     */
    function _addTotalRewardedAmount(uint256 _amount, address _token, address _user) internal {
        totalRewarded[_token] += _amount;
        userTotalRewardedByCoin[_token][_user] += _amount;
    }


    /**
     * @dev This internal function adds the given amount to the total staked amount for a specified token
     *      and increases the staked amount for the user by the same amount.
     * @param _amount The amount to add to the total staked amount and user's staked amount.
     * @param _token The address of the token for which to update the staked amount.
     * @param _user The address of the user whose staked amount should be increased.
     */
    function _addTotalStakedAmount(uint256 _amount, address _token, address _user) internal {
        totalStaked[_token] += _amount;
        userTotalStakedByCoin[_token][_user] += _amount;
    }

    /**
     * @dev This internal function subtracts the given amount from the total staked amount for a specified token
     *      and decreases the staked amount for the user by the same amount.
     * @param _amount The amount to subtract from the total staked amount and user's staked amount.
     * @param _token The address of the token for which to update the staked amount.
     * @param _user The address of the user whose staked amount should be decreased.
     */
    function _subtractStakedAmount(uint256 _amount,  address _token, address _user) internal {
        // do a underflow check
        require(totalStaked[_token] >= _amount, "Staking: Not enough staked (Contract)");
        require(userTotalStakedByCoin[_token][_user] >= _amount, "Staking: Not enough staked (User)");
        totalStaked[_token] -= _amount;
        userTotalStakedByCoin[_token][_user] -= _amount;
    }

    /**
     * @dev This internal function adds the given amount to the total withdrawal fees for a specified token.
     * @param _amount The amount to add to the total withdrawal fees.
     * @param _token The address of the token for which to update the withdrawal fees.
     */
    function _addTotalWithdrawalFees(uint256 _amount, address _token) internal {
        totalWithdrawalFees[_token] += _amount;
    }
    
    /**
     * @dev This function sets the APR for a specified token.
     * @param _apr The rewards per hour value to be set, as x% APR. (e.g. 25 = 25%)
     * @param _tokenId The address of the token for which to set the rewards per hour.
     */
    function setAPR(uint256 _apr, address _tokenId) public onlyGovernor {
        // Check if the token address is set
        require(_tokenId != address(0), "Token address is not set"); 
        aprERC20[_tokenId] = _apr; 
        emit NewAPR(_apr, _tokenId);
    }

    /**
     * @dev This function sets the minimum staking amount for a specified token.
     * @param _minStake The minimum staking amount to be set, in wei.
     * @param _tokenId The address of the token for which to set the minimum staking amount.
     */
    function setMinStake(uint256 _minStake, address _tokenId) public onlyGovernor {
        // Check if the token address is set
        require(_tokenId != address(0), "Token address is not set"); 
        minStakeERC20[_tokenId] = _minStake;
        emit NewMinStake(_minStake, _tokenId);
    }

    /**
     * @dev This function sets the ratio for a specified ERC20 token.
     * @param _ratio The ratio value to be set.
     * @param _tokenId The address of the token for which to set the ratio.
     */
    function setRatio(uint256 _ratio, address _tokenId) public onlyGovernor {
        // Check if the token address is set
        require(_tokenId != address(0), "Token address is not set"); 
        ratioERC20[_tokenId] = _ratio;
        emit NewRatio(_ratio, _tokenId);
    }

    /**
     * @dev This function sets the address of the Helix ERC20 contract.
     * @param _helix The address of the Helix ERC20 contract.
     */
    function setHelixERC20(address _helix) public onlyGovernor {
        require(_helix != address(0), "Helix address cannot be 0x0");
        helixERC20 = IHelix(_helix);
        emit NewHelixERC20(_helix);
    }

    /**
     * @dev This function sets the address of the konduxERC721Founders contract.
     * @param _konduxERC721Founders The address of the konduxERC721Founders contract.
     */
    function setKonduxERC721Founders(address _konduxERC721Founders) public onlyGovernor {
        require(_konduxERC721Founders != address(0), "Founders address cannot be 0x0");
        konduxERC721Founders = IERC721(_konduxERC721Founders);
        emit NewKonduxERC721Founders(_konduxERC721Founders);
    }

    /**
     * @dev This function sets the address of the konduxERC721kNFT contract.
     * @param _konduxERC721kNFT The address of the konduxERC721kNFT contract.
     */
    function setKonduxERC721kNFT(address _konduxERC721kNFT) public onlyGovernor {
        require(_konduxERC721kNFT != address(0), "kNFT address cannot be 0x0");
        konduxERC721kNFT = _konduxERC721kNFT;
        emit NewKonduxERC721kNFT(_konduxERC721kNFT);
    }

    /**
     * @dev This function sets the address of the Treasury contract.
     * @param _treasury The address of the Treasury contract.
     */
    function setTreasury(address _treasury) public onlyGovernor {
        require(_treasury != address(0), "Treasury address cannot be 0x0");
        treasury = ITreasury(_treasury);
        emit NewTreasury(_treasury);
    }

    /**
     * @dev This function sets the withdrawal fee for a specified token.
     * @param _withdrawalFee The withdrawal fee value to be set.
     * @param _tokenId The address of the token for which to set the withdrawal fee.
     */
    function setWithdrawalFee(uint256 _withdrawalFee, address _tokenId) public onlyGovernor {
        // Check if the token address is set
        require(_tokenId != address(0), "Token address is not set"); 
        require(_withdrawalFee <= divisorERC20[_tokenId], "Withdrawal fee cannot be more than 100%");
        withdrawalFeeERC20[_tokenId] = _withdrawalFee;
        emit NewWithdrawalFee(_withdrawalFee, _tokenId); 
    }

    /**
     * @dev This function sets the founders reward boost for a specified token.
     * @param _foundersRewardBoost The founders reward boost value to be set.
     * @param _tokenId The address of the token for which to set the founders reward boost.
     */
    function setFoundersRewardBoost(uint256 _foundersRewardBoost, address _tokenId) public onlyGovernor {
        // Check if the token address is set
        require(_tokenId != address(0), "Token address is not set"); 
        foundersRewardBoostERC20[_tokenId] = _foundersRewardBoost;
        emit NewFoundersRewardBoost(_foundersRewardBoost, _tokenId);
    }

    /**
     * @dev This function sets the kNFT reward boost for a specified token.
     * @param _kNFTRewardBoost The kNFT reward boost value to be set.
     * @param _tokenId The address of the token for which to set the kNFT reward boost.
     */
    function setkNFTRewardBoost(uint256 _kNFTRewardBoost, address _tokenId) public onlyGovernor {
        // Check if the token address is set
        require(_tokenId != address(0), "Token address is not set"); 
        kNFTRewardBoostERC20[_tokenId] = _kNFTRewardBoost;
        emit NewKNFTRewardBoost(_kNFTRewardBoost, _tokenId); 
    }

    /**
    * @dev This function sets the compound frequency for a specified token.
    * @param _compoundFreq The compound frequency value to be set.
    * @param _tokenId The address of the token for which to set the compound frequency.
    */
    function setCompoundFreq(uint256 _compoundFreq, address _tokenId) public onlyGovernor {
        // Check if the token address is set
        require(_tokenId != address(0), "Token address is not set"); 
        compoundFreqERC20[_tokenId] = _compoundFreq;
        emit NewCompoundFreq(_compoundFreq, _tokenId);
    }

    /**
     * @dev This function sets the penalty percentage for early withdrawal of a specified token.
     * @param _token The address of the token for which to set the penalty percentage.
     * @param penaltyPercentage The penalty percentage value to be set. Must be between 0 and 100. 
     */
    function setEarlyWithdrawalPenalty(address _token, uint256 penaltyPercentage) public onlyGovernor {
        // Check if the token address is set
        require(_token != address(0), "Token address is not set"); 
        require(penaltyPercentage <= 100, "Penalty percentage must be between 0 and 100");
        earlyWithdrawalPenalty[_token] = penaltyPercentage;
    }  

    /**
     * @dev This function sets the timelock category boost for a specified category.
     * @param _category The category for which to set the boost.
     * @param _boost The boost value to be set.
     */
    function setTimelockCategoryBoost(uint _category, uint256 _boost) public onlyGovernor {
        timelockCategoryBoost[_category] = _boost;
    }

    /**
     * @dev This function sets the divisor for a specified token.
     * @param _divisor The divisor value to be set.
     * @param _tokenId The address of the token for which to set the divisor.
     */
    function setDivisorERC20(uint256 _divisor, address _tokenId) public onlyGovernor {
        // Check if the token address is set
        require(_tokenId != address(0), "Token address is not set"); 
        divisorERC20[_tokenId] = _divisor;
        emit NewDivisorERC20(_divisor, _tokenId);
    }

    /**
     * @dev This internal function sets whether an ERC20 token is authorized as a staking currency.
     * Emits a {NewAuthorizedERC20} event.
     * @param _token The address of the token to be authorized or deauthorized.
     * @param _authorized True to authorize the token, false to deauthorize.
     */
    function _setAuthorizedERC20(address _token, bool _authorized) internal {
        require(_token != address(0), "Token address cannot be 0x0");
        if (_authorized == true) {
            require(aprERC20[_token] > 0, "Rewards per hour must be greater than 0");
            require(compoundFreqERC20[_token] > 0, "Compound frequency must be greater than 0");
            require(withdrawalFeeERC20[_token] > 0, "Withdrawal fee must be greater than 0");
            require(foundersRewardBoostERC20[_token] > 0, "Founders reward boost must be greater than 0");
            require(kNFTRewardBoostERC20[_token] > 0, "kNFT reward boost must be greater than 0");
            require(ratioERC20[_token] > 0, "Ratio must be greater than 0");
            require(minStakeERC20[_token] > 0, "Minimum stake must be greater than 0");
            require(divisorERC20[_token] > 0, "Divisor must be greater than 0");
            require(IERC20(_token).totalSupply() > 0, "Token total supply must be greater than 0");
        }
        authorizedERC20[_token] = _authorized;
        emit NewAuthorizedERC20(_token, _authorized);
    }

    /**
     * @dev This function sets whether an ERC20 token is authorized as a staking currency.
     * Emits a {NewAuthorizedERC20} event.
     * @param _token The address of the token to be authorized or deauthorized.
     * @param _authorized True to authorize the token, false to deauthorize.
     */
    function setAuthorizedERC20(address _token, bool _authorized) public onlyGovernor {
        // Check if the token address is set
        require(_token != address(0), "Token address is not set"); 
        _setAuthorizedERC20(_token, _authorized);
    }

    /**
     * @dev This function sets the version of dna that is allowed to be used for reward bonus
     * @param _dnaVersion The dna version to be set.
     * @param _allowed True to allow the dna version, false to disallow.
     */
    function setAllowedDnaVersion(uint256 _dnaVersion, bool _allowed) public onlyGovernor {
        allowedDnaVersions[_dnaVersion] = _allowed;
    }

    /**
     * @dev This function sets the decimals of a specified token.
     * @param _decimals The decimals value to be set.
     * @param _tokenId The address of the token for which to set the decimals.
     */
    function setDecimalsERC20(uint8 _decimals, address _tokenId) public onlyGovernor {
        // Check if the token address is set
        require(_tokenId != address(0), "Token address is not set"); 
        decimalsERC20[_tokenId] = _decimals;
    }

    /**
     * @dev This function adds a new staking token with its parameters.
     * Emits various events based on the setter functions called during token addition.
     * Emits a {NewAuthorizedERC20} event at the end.
     * @param _token The address of the new staking token.
     * @param _apr The rewards per hour for the new staking token.
     * @param _compoundFreq The compound frequency for the new staking token.
     * @param _withdrawalFee The withdrawal fee for the new staking token.
     * @param _foundersRewardBoost The founders reward boost for the new staking token.
     * @param _kNFTRewardBoost The kNFT reward boost for the new staking token.
     * @param _ratio The ratio for the new staking token.
     * @param _minStake The minimum stake for the new staking token.
     */ 
    function addNewStakingToken(address _token, uint256 _apr, uint256 _compoundFreq, uint256 _withdrawalFee, uint256 _foundersRewardBoost, uint256 _kNFTRewardBoost, uint256 _ratio, uint256 _minStake) public onlyGovernor {
        require(_token != address(0), "Token address cannot be 0x0");
        require(_apr > 0, "Rewards per hour must be greater than 0"); 
        require(_compoundFreq > 0, "Compound frequency must be greater than 0");
        require(_withdrawalFee > 0, "Withdrawal fee must be greater than 0");
        require(_foundersRewardBoost > 0, "Founders reward boost must be greater than 0");
        require(_kNFTRewardBoost > 0, "kNFT reward boost must be greater than 0");
        require(_ratio > 0, "Ratio must be greater than 0");
        require(_minStake > 0, "Minimum stake must be greater than 0");
        require(IERC20(_token).totalSupply() > 0, "Token total supply must be greater than 0");

        setDivisorERC20(10_000, _token);
        setFoundersRewardBoost(_foundersRewardBoost, _token);
        setkNFTRewardBoost(_kNFTRewardBoost, _token);
        setAPR(_apr, _token); 
        setRatio(_ratio, _token);
        setWithdrawalFee(_withdrawalFee, _token);
        setCompoundFreq(_compoundFreq, _token);
        setMinStake(_minStake, _token);
        setDecimalsERC20(IERC20Metadata(_token).decimals(), _token);

        _setAuthorizedERC20(_token, true); 
    }


    // Functions for getting staking mechanism variables:

    /**
     * @dev This function returns the time of the last update for the specified deposit ID.
     * @param _depositId The ID of the deposit for which the time of the last update is requested.
     * @return _timeOfLastUpdate The time of the last update for the specified deposit ID.
     */
    function getTimeOfLastUpdate(uint _depositId) public view returns (uint256 _timeOfLastUpdate) {
        return userDeposits[_depositId].timeOfLastUpdate;
    }

    /**
     * @dev This function returns the staked amount for the specified deposit ID.
     * @param _depositId The ID of the deposit for which the staked amount is requested.
     * @return _deposited The staked amount for the specified deposit ID.
     */
    function getStakedAmount(uint _depositId) public view returns (uint256 _deposited) {
        return userDeposits[_depositId].deposited;
    }

    /**
     * @dev This function returns the APR for the specified token.
     * @param _tokenId The address of the token for which the rewards per hour are requested.
     * @return _rewardsPerHour The rewards per hour for the specified token.
     */
    function getAPR(address _tokenId) public view returns (uint256 _rewardsPerHour) {
        return aprERC20[_tokenId];
    }

    /**
     * @dev This function returns the Founder's reward boost for the specified token.
     * @param _tokenId The address of the token for which the Founder's reward boost is requested.
     * @return _foundersRewardBoost The Founder's reward boost for the specified token.
     */
    function getFoundersRewardBoost(address _tokenId) public view returns (uint256 _foundersRewardBoost) {
        return foundersRewardBoostERC20[_tokenId];
    }

    /**
     * @dev This function returns the kNFT reward boost for the specified token.
     * @param _tokenId The address of the token for which the kNFT reward boost is requested.
     * @return _kNFTRewardBoost The kNFT reward boost for the specified token.
     */
    function getkNFTRewardBoost(address _tokenId) public view returns (uint256 _kNFTRewardBoost) {
        return kNFTRewardBoostERC20[_tokenId];
    }

    /**
     * @dev This function returns the minimum stake for the specified token.
     * @param _tokenId The address of the token for which the minimum stake is requested.
     * @return _minStake The minimum stake for the specified token.
     */
    function getMinStake(address _tokenId) public view returns (uint256 _minStake) {
        return minStakeERC20[_tokenId];
    }

    /**
     * @dev This function returns the timelock category for the specified deposit ID.
     * @param _depositId The ID of the deposit for which the timelock category is requested.
     * @return _timelockCategory The timelock category for the specified deposit ID.
     */
    function getTimelockCategory(uint _depositId) public view returns (uint8 _timelockCategory) {
        return userDeposits[_depositId].timelockCategory;
    }

    /**
     * @dev This function returns the timelock for the specified deposit ID.
     * @param _depositId The ID of the deposit for which the timelock is requested.
     * @return _timelock The timelock for the specified deposit ID.
     */
    function getTimelock(uint _depositId) public view returns (uint256 _timelock) {
        return userDeposits[_depositId].timelock;
    }

    /**
     * @dev This function returns the deposit IDs for the specified user.
     * @param _user The address of the user for which the deposit IDs are requested.
     * @return An array of deposit IDs for the specified user.
     */
    function getDepositIds(address _user) public view returns (uint256[] memory) {
        return userDepositsIds[_user];
    }

    /**
     * @dev This function returns the withdrawal fee for the specified token.
     * @param _tokenId The address of the token for which the withdrawal fee is requested.
     * @return _withdrawalFee The withdrawal fee for the specified token.
     */
    function getWithdrawalFee(address _tokenId) public view returns (uint256 _withdrawalFee) {
        return withdrawalFeeERC20[_tokenId]; 
    }

    /**
     * @dev This function returns the total amount staked for a specific token.
     * @param _token The address of the token contract.
     * @return _totalStaked The total amount staked for the given token.
     */
    function getTotalStaked(address _token) public view returns (uint256 _totalStaked) {
        return totalStaked[_token];
    }

    /**
     * @dev This function returns the total amount staked by a specific user for a specific token.
     * @param _user The address of the user.
     * @param _token The address of the token contract.
     * @return _totalStaked The total amount staked by the user for the given token.
     */
    function getUserTotalStakedByCoin(address _user, address _token) public view returns (uint256 _totalStaked) {
        return userTotalStakedByCoin[_token][_user];
    }

    /**
     * @dev This function returns the total rewards earned for a specific token.
     * @param _token The address of the token contract.
     * @return _totalRewards The total rewards earned for the given token.
     */
    function getTotalRewards(address _token) public view returns (uint256 _totalRewards) {
        return totalRewarded[_token];
    }

    /**
     * @dev This function returns the total rewards earned by a specific user for a specific token.
     * @param _user The address of the user.
     * @param _token The address of the token contract.
     * @return _totalRewards The total rewards earned by the user for the given token.
     */
    function getUserTotalRewardsByCoin(address _user, address _token) public view returns (uint256 _totalRewards) {
        return userTotalRewardedByCoin[_token][_user]; 
    }

    /**
     * @dev This function returns the total withdrawal fees for a specific token.
     * @param _token The address of the token contract.
     * @return _totalWithdrawalFees The total withdrawal fees for the given token.
     */
    function getTotalWithdrawalFees(address _token) public view returns (uint256 _totalWithdrawalFees) {
        return totalWithdrawalFees[_token];
    }

    /**
     * @dev This function returns the timestamp of the deposit with the specified ID.
     * @param _depositId The id of the deposit for which the timestamp is requested.
     * @return _depositTimestamp The timestamp of the deposit
     */
    function getDepositTimestamp(uint _depositId) public view returns (uint256 _depositTimestamp) {
        return userDeposits[_depositId].lastDepositTime; 
    }

    /**
     * @dev This function returns the penalty for early withdrawal for the specified token in basis points. (X% = X * 100)
     * @param token The address of the token for which the penalty is requested.
     * @return The penalty for early withdrawal for the specified token in basis points.
     */
    function getEarlyWithdrawalPenalty(address token) public view returns (uint256) {
        return earlyWithdrawalPenalty[token];
    }

    /**
     * @dev This function returns the timelock category boost for the specified category.
     * @param _category The category for which the timelock category boost is requested.
     * @return The timelock category boost for the specified category.
     */
    function getTimelockCategoryBoost(uint _category) public view returns (uint256) {
        return timelockCategoryBoost[_category];
    }

    /**
     * @dev This function returns the divisor for the specified token.
     * @param _token The address of the token for which the divisor is requested.
     * @return The divisor for the specified token.
     */
    function getDivisorERC20(address _token) public view returns (uint256) {
        return divisorERC20[_token];
    }

    /**
     * @dev This function returns the permission of usage of a dna version as boost.
     * @param _dnaVersion The dna version for which the permission is requested.
     * @return The permission of usage of a dna version as boost
     */
    function getAllowedDnaVersion(uint256 _dnaVersion) public view returns (bool) {
        return allowedDnaVersions[_dnaVersion];
    }

    /**
     * @dev This function retrieves the deposit information for a given deposit ID. It returns the staked amount
     *      and the earned rewards (including unclaimed rewards) for the specified deposit.
     * @param _depositId The ID of the deposit for which to retrieve the information.
     * @return _stake The staked amount for the specified deposit.
     * @return _unclaimedRewards The earned rewards (including unclaimed rewards) for the specified deposit.
     */
    function getDepositInfo(uint _depositId) public view returns (uint256 _stake, uint256 _unclaimedRewards) {
        _stake = userDeposits[_depositId].deposited;  
        _unclaimedRewards = calculateRewards(msg.sender, _depositId) + userDeposits[_depositId].unclaimedRewards;
        return (_stake, _unclaimedRewards);  
    }

    /**
     * @dev This function returns the decimals for the specified token.
     * @param _token The address of the token for which the decimals are requested.
     * @return The decimals for the specified token.
     */
    function getDecimalsERC20(address _token) public view returns (uint8) {
        return decimalsERC20[_token];
    }

    /**
     * @dev This function returns the ratio for the specified token.
     * @param _token The address of the token for which the ratio is requested.
     * @return The ratio for the specified token.
     */
    function getRatioERC20(address _token) public view returns (uint256) {
        return ratioERC20[_token];
    }

    /**
     * @dev This function returns the ratio for the specified deposit.
     * @param _depositId The ID of the deposit for which to retrieve the information.
     * @return The ratio for the specified deposit.
     */
    function getDepositRatioERC20(uint256 _depositId) public view returns (uint256) {
        return userDeposits[_depositId].ratioERC20;
    }   

    /**
     * @dev This function returns the top 5 bonuses and their corresponding kNFT IDs.
     * @param _staker The address of the staker.
     * @param _stakeId The ID of the deposit for which to calculate the boost percentage.
     * @return top5Bonuses An array of the top 5 bonuses.
     * @return top5Ids An array of the corresponding kNFT IDs.
     */
    function getTop5BonusesAndIds(address _staker, uint256 _stakeId) public view returns (uint256[] memory top5Bonuses, uint256[] memory top5Ids) {
        uint256 kNFTBalance = IERC721(konduxERC721kNFT).balanceOf(_staker);

        // Initialize arrays to store the top 5 bonuses and their corresponding kNFT IDs
        top5Bonuses = new uint256[](5);
        top5Ids = new uint256[](5);

        // Iterate through the staker's kNFTs
        for (uint256 i = 0; i < kNFTBalance; i++) {
            uint256 tokenId = IERC721Enumerable(konduxERC721kNFT).tokenOfOwnerByIndex(_staker, i);

            // if the user's kNFT was received after the deposit date, continue
            if (IKondux(konduxERC721kNFT).getTransferDate(tokenId) > userDeposits[_stakeId].lastDepositTime) {
                continue;
            }

            // Get the kNFT's DNA version and check if it's allowed
            int256 dnaVersion = IKondux(konduxERC721kNFT).readGen(tokenId, 0, 1);
            if (!allowedDnaVersions[uint256(dnaVersion)]) { 
                continue;
            }

            // Get the kNFT's boost value and multiply it by 100 to get a percentage
            int256 dnaBoost = IKondux(konduxERC721kNFT).readGen(tokenId, 1, 2) * 100;

            // Clamp the boost value to 0 if it's negative
            if (dnaBoost < 0) {
                dnaBoost = 0;
            }

            // Update the top 5 bonuses array with the current kNFT boost
            for (uint256 j = 0; j < 5; j++) {
                if (uint256(dnaBoost) > top5Bonuses[j]) {
                    uint256 temp = top5Bonuses[j];
                    top5Bonuses[j] = uint256(dnaBoost);
                    dnaBoost = int256(temp);

                    uint256 tempId = top5Ids[j];
                    top5Ids[j] = tokenId;
                    tokenId = tempId;
                }
            }
        }

        return (top5Bonuses, top5Ids);
    }

    /**
     * @dev This function returns the top 5 bonuses and their corresponding kNFT IDs.
     * @param _staker The address of the staker.
     * @return top5Bonuses An array of the top 5 bonuses.
     * @return top5Ids An array of the corresponding kNFT IDs.
     */
    function getMaxTop5BonusesAndIds(address _staker) public view returns (uint256[] memory top5Bonuses, uint256[] memory top5Ids) {
        uint256 kNFTBalance = IERC721(konduxERC721kNFT).balanceOf(_staker);

        // Initialize arrays to store the top 5 bonuses and their corresponding kNFT IDs
        top5Bonuses = new uint256[](5);
        top5Ids = new uint256[](5);

        // Iterate through the staker's kNFTs
        for (uint256 i = 0; i < kNFTBalance; i++) {
            uint256 tokenId = IERC721Enumerable(konduxERC721kNFT).tokenOfOwnerByIndex(_staker, i);

            // Get the kNFT's DNA version and check if it's allowed
            int256 dnaVersion = IKondux(konduxERC721kNFT).readGen(tokenId, 0, 1);
            if (!allowedDnaVersions[uint256(dnaVersion)]) { 
                continue;
            }

            // Get the kNFT's boost value and multiply it by 100 to get a percentage
            int256 dnaBoost = IKondux(konduxERC721kNFT).readGen(tokenId, 1, 2) * 100;

            // Clamp the boost value to 0 if it's negative
            if (dnaBoost < 0) {
                dnaBoost = 0;
            }

            // Update the top 5 bonuses array with the current kNFT boost
            for (uint256 j = 0; j < 5; j++) {
                if (uint256(dnaBoost) > top5Bonuses[j]) {
                    uint256 temp = top5Bonuses[j];
                    top5Bonuses[j] = uint256(dnaBoost);
                    dnaBoost = int256(temp);

                    uint256 tempId = top5Ids[j];
                    top5Ids[j] = tokenId;
                    tokenId = tempId;
                }
            }
        }

        return (top5Bonuses, top5Ids);
    }

    /**
     * @dev This function calculates the boost percentage for a staker's deposit.
     * @param _staker The address of the staker.
     * @param _stakeId The ID of the deposit for which to calculate the boost percentage.
     * @return boostPercentage The boost percentage for the staker's deposit.
     */
    function calculateKNFTBoostPercentage(address _staker, uint256 _stakeId) public view returns (uint256 boostPercentage) {
        // Get the top 5 bonuses and their corresponding kNFT IDs
        (uint256[] memory top5Bonuses, ) = getTop5BonusesAndIds(_staker, _stakeId);

        // Add the top 5 bonuses to the boost percentage
        for (uint256 i = 0; i < 5; i++) {
            boostPercentage += top5Bonuses[i];
        }

        return boostPercentage;
    }

    /**
     * @dev This function calculates the boost percentage for a staker.
     * @param _staker The address of the staker.
     * @return boostPercentage The boost percentage for the staker's deposit.
     */
    function calculateMaxKNFTBoostPercentage(address _staker) public view returns (uint256 boostPercentage) {
        // Get the top 5 bonuses and their corresponding kNFT IDs
        (uint256[] memory top5Bonuses, ) = getMaxTop5BonusesAndIds(_staker);

        // Add the top 5 bonuses to the boost percentage
        for (uint256 i = 0; i < 5; i++) {
            boostPercentage += top5Bonuses[i];
        }

        return boostPercentage;
    }

    /**
     * @dev This function calculates the boost percentage for a specified staker and deposit ID.
     * @param _staker The address of the staker for which to calculate the boost.
     * @param _stakeId The ID of the stake for which to calculate the boost.
     * @return boostPercentage The calculated boost percentage for the specified staker and deposit ID.
     */
    function calculateBoostPercentage(address _staker, uint _stakeId) public view returns (uint256 boostPercentage) {
        // Retrieve deposit details by _depositId
        Staker memory deposit_ = userDeposits[_stakeId];

        // Initialize the boost percentage with the base boost percentage for the token
        boostPercentage = divisorERC20[deposit_.token];

        // Check if the staker has Founder's NFTs and add the boost percentage
        if (IERC721(konduxERC721Founders).balanceOf(_staker) > 0) {
            boostPercentage += foundersRewardBoostERC20[deposit_.token];
        }

        // Check if the staker has any kNFTs and calculate the top 5 boosts
        if (IERC721(konduxERC721kNFT).balanceOf(_staker) > 0) {
            boostPercentage += calculateKNFTBoostPercentage(_staker, _stakeId); 
        }

        // If the deposit has a timelock category, add the corresponding boost
        if (deposit_.timelockCategory > 0) {
            boostPercentage += timelockCategoryBoost[deposit_.timelockCategory];
        }

        return boostPercentage;
    }

    /**
     * @dev A function that agreggates the returned values of getTimelock, getDepositTimestamp, getTimelockCategory, getDepositInfo and calculateKNFTBoostPercentage
     * @param _staker The address of the staker for which to calculate the boost.
     * @param _stakeId The ID of the stake for which to calculate the boost.
     * @return _timelock The timelock for the specified deposit ID.
     * @return _depositTimestamp The timestamp of the deposit
     * @return _timelockCategory The timelock category for the specified deposit ID.
     * @return _stake The staked amount for the specified deposit.
     * @return _unclaimedRewards The earned rewards (including unclaimed rewards) for the specified deposit.
     * @return _boostPercentage The calculated boost percentage for the specified staker and deposit ID.
     */
    function getDepositDetails(address _staker, uint _stakeId) public view returns (uint256 _timelock, uint256 _depositTimestamp, uint8 _timelockCategory, uint256 _stake, uint256 _unclaimedRewards, uint256 _boostPercentage) {
        _timelock = getTimelock(_stakeId);
        _depositTimestamp = getDepositTimestamp(_stakeId);
        _timelockCategory = getTimelockCategory(_stakeId);
        (_stake, _unclaimedRewards) = getDepositInfo(_stakeId);
        _boostPercentage = calculateBoostPercentage(_staker, _stakeId);
    }
 
}

File 2 of 13 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

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

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

File 3 of 13 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
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 amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

    /**
     * @dev Moves `amount` 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 amount) 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 `amount` 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 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` 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 amount
    ) external returns (bool);
}

File 4 of 13 : IERC721Enumerable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol)

pragma solidity ^0.8.0;

import "../IERC721.sol";

/**
 * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Enumerable is IERC721 {
    /**
     * @dev Returns the total amount of tokens stored by the contract.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns a token ID owned by `owner` at a given `index` of its token list.
     * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
     */
    function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);

    /**
     * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
     * Use along with {totalSupply} to enumerate all tokens.
     */
    function tokenByIndex(uint256 index) external view returns (uint256);
}

File 5 of 13 : IERC721.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool _approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}

File 6 of 13 : Counters.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)

pragma solidity ^0.8.0;

/**
 * @title Counters
 * @author Matt Condon (@shrugs)
 * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
 * of elements in a mapping, issuing ERC721 ids, or counting request ids.
 *
 * Include with `using Counters for Counters.Counter;`
 */
library Counters {
    struct Counter {
        // This variable should never be directly accessed by users of the library: interactions must be restricted to
        // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
        // this feature: see https://github.com/ethereum/solidity/issues/4637
        uint256 _value; // default: 0
    }

    function current(Counter storage counter) internal view returns (uint256) {
        return counter._value;
    }

    function increment(Counter storage counter) internal {
        unchecked {
            counter._value += 1;
        }
    }

    function decrement(Counter storage counter) internal {
        uint256 value = counter._value;
        require(value > 0, "Counter: decrement overflow");
        unchecked {
            counter._value = value - 1;
        }
    }

    function reset(Counter storage counter) internal {
        counter._value = 0;
    }
}

File 7 of 13 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * 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[EIP 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);
}

File 8 of 13 : IAuthority.sol
// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.8.9;

interface IAuthority {
    /* ========== EVENTS ========== */

    event GovernorPushed(address indexed from, address indexed to, bool _effectiveImmediately);
    event GuardianPushed(address indexed from, address indexed to, bool _effectiveImmediately);
    event PolicyPushed(address indexed from, address indexed to, bool _effectiveImmediately);
    event VaultPushed(address indexed from, address indexed to, bool _effectiveImmediately);
    event RolePushed(address indexed account, bytes32 _role);

    event GovernorPulled(address indexed from, address indexed to);
    event GuardianPulled(address indexed from, address indexed to);
    event PolicyPulled(address indexed from, address indexed to);
    event VaultPulled(address indexed from, address indexed to);

    /* ========== VIEW ========== */

    function governor() external view returns (address);

    function guardian() external view returns (address);

    function policy() external view returns (address);

    function vault() external view returns (address);

    function roles(address _addr) external view returns (bytes32);

}

File 9 of 13 : IHelix.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

interface IHelix is IERC20, IERC20Metadata {
    function increaseAllowance(address spender, uint256 addedValue) external returns (bool);
    function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);
    function burn(address _to, uint256 _amount) external;
    function mint(address _to, uint256 _amount) external; 
}

File 10 of 13 : IKondux.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";

interface IKondux {
    function changeDenominator(uint96 _denominator) external returns (uint96);
    function setDefaultRoyalty(address receiver, uint96 feeNumerator) external;
    function setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator) external;
    function setBaseURI(string memory _newURI) external returns (string memory);
    function tokenURI(uint256 tokenId) external view returns (string memory);
    function pause() external;
    function unpause() external;
    function safeMint(address to, uint256 dna) external returns (uint256);
    function setDna(uint256 _tokenID, uint256 _dna) external;
    function getDna(uint256 _tokenID) external view returns (uint256);
    function readGen(uint256 _tokenID, uint8 startIndex, uint8 endIndex) external view returns (int256);
    function writeGen(uint256 _tokenID, uint256 inputValue, uint8 startIndex, uint8 endIndex) external;
    function getTransferDate(uint256 _tokenID) external view returns (uint256);
}

File 11 of 13 : IKonduxERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

interface IKonduxERC20 is IERC20 {
    function excludedFromFees(address) external view returns (bool);
    function tradingOpen() external view returns (bool);
    function taxSwapMin() external view returns (uint256);
    function taxSwapMax() external view returns (uint256);
    function _isLiqPool(address) external view returns (bool);
    function taxRateBuy() external view returns (uint8);
    function taxRateSell() external view returns (uint8);
    function antiBotEnabled() external view returns (bool);
    function excludedFromAntiBot(address) external view returns (bool);
    function _lastSwapBlock(address) external view returns (uint256);
    function taxWallet() external view returns (address);

    event TokensAirdropped(uint256 totalWallets, uint256 totalTokens);
    event TokensBurned(address indexed burnedByWallet, uint256 tokenAmount);
    event TaxWalletChanged(address newTaxWallet);
    event TaxRateChanged(uint8 newBuyTax, uint8 newSellTax);

    function initLP() external;
    function enableTrading() external;
    function burnTokens(uint256 amount) external;
    function enableAntiBot(bool isEnabled) external;
    function excludeFromAntiBot(address wallet, bool isExcluded) external;
    function excludeFromFees(address wallet, bool isExcluded) external;
    function adjustTaxRate(uint8 newBuyTax, uint8 newSellTax) external;
    function setTaxWallet(address newTaxWallet) external;
    function taxSwapSettings(uint32 minValue, uint32 minDivider, uint32 maxValue, uint32 maxDivider) external;

    function totalSupply() external view returns (uint256);
	function decimals() external view returns (uint8);
	function symbol() external view returns (string memory);
	function name() external view returns (string memory);
	function getOwner() external view returns (address);
	function balanceOf(address account) external view returns (uint256);
	function transfer(address recipient, uint256 amount) external returns (bool);
	function allowance(address _owner, address spender) external view returns (uint256);
	function approve(address spender, uint256 amount) external returns (bool);
	function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
}

File 12 of 13 : ITreasury.sol
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.9;

interface ITreasury {
    function deposit(
        uint256 _amount,
        address _token
    ) external;

    function depositEther() external payable;

    function withdraw(
        uint256 _amount,
        address _token
    ) external;

    function withdrawTo(
        uint256 _amount,
        address _token,
        address _to
    ) external;

    function withdrawEther(
        uint256 _amount
    ) external;
}

File 13 of 13 : AccessControlled.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import "../interfaces/IAuthority.sol";

/// @dev Reasoning for this contract = modifiers literaly copy code
/// instead of pointing towards the logic to execute. Over many
/// functions this bloats contract size unnecessarily.
/// imho modifiers are a meme.
abstract contract AccessControlled {
    /* ========== EVENTS ========== */

    event AuthorityUpdated(IAuthority authority);

    /* ========== STATE VARIABLES ========== */

    IAuthority public authority;

    /* ========== Constructor ========== */

    constructor(IAuthority _authority) {
        require(address(_authority) != address(0), "Authority cannot be zero address");
        authority = _authority;
        emit AuthorityUpdated(_authority);
    }

    /* ========== "MODIFIERS" ========== */

    modifier onlyGovernor {
        _onlyGovernor();
        _;
    }

    modifier onlyGuardian {
        _onlyGuardian();
        _;
    }

    modifier onlyPolicy {
        _onlyPolicy();
        _;
    }

    modifier onlyVault {
        _onlyVault();
        _;
    }

    modifier onlyGlobalRole(bytes32 _role){
        _onlyRole(_role);
        _;
    }

    /* ========== GOV ONLY ========== */

    function initializeAuthority(IAuthority _newAuthority) internal {
        require(authority == IAuthority(address(0)), "AUTHORITY_INITIALIZED");
        authority = _newAuthority;
        emit AuthorityUpdated(_newAuthority);
    }

    function setAuthority(IAuthority _newAuthority) external {
        _onlyGovernor();
        authority = _newAuthority;
        emit AuthorityUpdated(_newAuthority);
    }

    /* ========== INTERNAL CHECKS ========== */

    function _onlyGovernor() internal view {
        require(msg.sender == authority.governor(), "UNAUTHORIZED");
    }

    function _onlyGuardian() internal view {
        require(msg.sender == authority.guardian(), "UNAUTHORIZED");
    }

    function _onlyPolicy() internal view {
        require(msg.sender == authority.policy(), "UNAUTHORIZED");        
    }

    function _onlyVault() internal view {
        require(msg.sender == authority.vault(), "UNAUTHORIZED");                
    }

    function _onlyRole(bytes32 _role) internal view {
        require(authority.roles(msg.sender) == _role, "UNAUTHORIZED");
    }
  
}

Settings
{
  "metadata": {
    "bytecodeHash": "none",
    "useLiteralContent": true
  },
  "optimizer": {
    "enabled": true,
    "runs": 800
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_authority","type":"address"},{"internalType":"address","name":"_konduxERC20","type":"address"},{"internalType":"address","name":"_treasury","type":"address"},{"internalType":"address","name":"_konduxERC721Founders","type":"address"},{"internalType":"address","name":"_konduxERC721kNFT","type":"address"},{"internalType":"address","name":"_helixERC20","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IAuthority","name":"authority","type":"address"}],"name":"AuthorityUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Compound","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"token","type":"address"}],"name":"NewAPR","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"bool","name":"authorized","type":"bool"}],"name":"NewAuthorizedERC20","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"token","type":"address"}],"name":"NewCompoundFreq","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"token","type":"address"}],"name":"NewDivisorERC20","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"token","type":"address"}],"name":"NewFoundersRewardBoost","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"helixERC20","type":"address"}],"name":"NewHelixERC20","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"token","type":"address"}],"name":"NewKNFTRewardBoost","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"konduxERC721Founders","type":"address"}],"name":"NewKonduxERC721Founders","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"konduxERC721kNFT","type":"address"}],"name":"NewKonduxERC721kNFT","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"token","type":"address"}],"name":"NewMinStake","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"token","type":"address"}],"name":"NewRatio","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"treasury","type":"address"}],"name":"NewTreasury","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"token","type":"address"}],"name":"NewWithdrawalFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"netRewards","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fees","type":"uint256"}],"name":"Reward","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Stake","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Unstake","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"liquidAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fees","type":"uint256"}],"name":"Withdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawAll","type":"event"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_apr","type":"uint256"},{"internalType":"uint256","name":"_compoundFreq","type":"uint256"},{"internalType":"uint256","name":"_withdrawalFee","type":"uint256"},{"internalType":"uint256","name":"_foundersRewardBoost","type":"uint256"},{"internalType":"uint256","name":"_kNFTRewardBoost","type":"uint256"},{"internalType":"uint256","name":"_ratio","type":"uint256"},{"internalType":"uint256","name":"_minStake","type":"uint256"}],"name":"addNewStakingToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allowedDnaVersions","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"aprERC20","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"authority","outputs":[{"internalType":"contract IAuthority","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"authorizedERC20","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_staker","type":"address"},{"internalType":"uint256","name":"_stakeId","type":"uint256"}],"name":"calculateBoostPercentage","outputs":[{"internalType":"uint256","name":"boostPercentage","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_staker","type":"address"},{"internalType":"uint256","name":"_stakeId","type":"uint256"}],"name":"calculateKNFTBoostPercentage","outputs":[{"internalType":"uint256","name":"boostPercentage","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_staker","type":"address"}],"name":"calculateMaxKNFTBoostPercentage","outputs":[{"internalType":"uint256","name":"boostPercentage","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_staker","type":"address"},{"internalType":"uint256","name":"_depositId","type":"uint256"}],"name":"calculateRewards","outputs":[{"internalType":"uint256","name":"rewards","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_depositId","type":"uint256"}],"name":"claimRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"compoundFreqERC20","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_depositId","type":"uint256"}],"name":"compoundRewardsTimer","outputs":[{"internalType":"uint256","name":"remainingTime","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"decimalsERC20","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint8","name":"_timelock","type":"uint8"},{"internalType":"address","name":"_token","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"divisorERC20","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_depositId","type":"uint256"}],"name":"earlyUnstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"earlyWithdrawalPenalty","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"foundersRewardBoostERC20","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenId","type":"address"}],"name":"getAPR","outputs":[{"internalType":"uint256","name":"_rewardsPerHour","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_dnaVersion","type":"uint256"}],"name":"getAllowedDnaVersion","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getDecimalsERC20","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_staker","type":"address"},{"internalType":"uint256","name":"_stakeId","type":"uint256"}],"name":"getDepositDetails","outputs":[{"internalType":"uint256","name":"_timelock","type":"uint256"},{"internalType":"uint256","name":"_depositTimestamp","type":"uint256"},{"internalType":"uint8","name":"_timelockCategory","type":"uint8"},{"internalType":"uint256","name":"_stake","type":"uint256"},{"internalType":"uint256","name":"_unclaimedRewards","type":"uint256"},{"internalType":"uint256","name":"_boostPercentage","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getDepositIds","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_depositId","type":"uint256"}],"name":"getDepositInfo","outputs":[{"internalType":"uint256","name":"_stake","type":"uint256"},{"internalType":"uint256","name":"_unclaimedRewards","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_depositId","type":"uint256"}],"name":"getDepositRatioERC20","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_depositId","type":"uint256"}],"name":"getDepositTimestamp","outputs":[{"internalType":"uint256","name":"_depositTimestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getDivisorERC20","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getEarlyWithdrawalPenalty","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenId","type":"address"}],"name":"getFoundersRewardBoost","outputs":[{"internalType":"uint256","name":"_foundersRewardBoost","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_staker","type":"address"}],"name":"getMaxTop5BonusesAndIds","outputs":[{"internalType":"uint256[]","name":"top5Bonuses","type":"uint256[]"},{"internalType":"uint256[]","name":"top5Ids","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenId","type":"address"}],"name":"getMinStake","outputs":[{"internalType":"uint256","name":"_minStake","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getRatioERC20","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_depositId","type":"uint256"}],"name":"getStakedAmount","outputs":[{"internalType":"uint256","name":"_deposited","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_depositId","type":"uint256"}],"name":"getTimeOfLastUpdate","outputs":[{"internalType":"uint256","name":"_timeOfLastUpdate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_depositId","type":"uint256"}],"name":"getTimelock","outputs":[{"internalType":"uint256","name":"_timelock","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_depositId","type":"uint256"}],"name":"getTimelockCategory","outputs":[{"internalType":"uint8","name":"_timelockCategory","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_category","type":"uint256"}],"name":"getTimelockCategoryBoost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_staker","type":"address"},{"internalType":"uint256","name":"_stakeId","type":"uint256"}],"name":"getTop5BonusesAndIds","outputs":[{"internalType":"uint256[]","name":"top5Bonuses","type":"uint256[]"},{"internalType":"uint256[]","name":"top5Ids","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getTotalRewards","outputs":[{"internalType":"uint256","name":"_totalRewards","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getTotalStaked","outputs":[{"internalType":"uint256","name":"_totalStaked","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getTotalWithdrawalFees","outputs":[{"internalType":"uint256","name":"_totalWithdrawalFees","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_token","type":"address"}],"name":"getUserTotalRewardsByCoin","outputs":[{"internalType":"uint256","name":"_totalRewards","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_token","type":"address"}],"name":"getUserTotalStakedByCoin","outputs":[{"internalType":"uint256","name":"_totalStaked","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenId","type":"address"}],"name":"getWithdrawalFee","outputs":[{"internalType":"uint256","name":"_withdrawalFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenId","type":"address"}],"name":"getkNFTRewardBoost","outputs":[{"internalType":"uint256","name":"_kNFTRewardBoost","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"helixERC20","outputs":[{"internalType":"contract IHelix","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"kNFTRewardBoostERC20","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"konduxERC721Founders","outputs":[{"internalType":"contract IERC721","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"konduxERC721kNFT","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"minStakeERC20","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"ratioERC20","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_apr","type":"uint256"},{"internalType":"address","name":"_tokenId","type":"address"}],"name":"setAPR","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_dnaVersion","type":"uint256"},{"internalType":"bool","name":"_allowed","type":"bool"}],"name":"setAllowedDnaVersion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IAuthority","name":"_newAuthority","type":"address"}],"name":"setAuthority","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"bool","name":"_authorized","type":"bool"}],"name":"setAuthorizedERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_compoundFreq","type":"uint256"},{"internalType":"address","name":"_tokenId","type":"address"}],"name":"setCompoundFreq","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_decimals","type":"uint8"},{"internalType":"address","name":"_tokenId","type":"address"}],"name":"setDecimalsERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_divisor","type":"uint256"},{"internalType":"address","name":"_tokenId","type":"address"}],"name":"setDivisorERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"penaltyPercentage","type":"uint256"}],"name":"setEarlyWithdrawalPenalty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_foundersRewardBoost","type":"uint256"},{"internalType":"address","name":"_tokenId","type":"address"}],"name":"setFoundersRewardBoost","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_helix","type":"address"}],"name":"setHelixERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_konduxERC721Founders","type":"address"}],"name":"setKonduxERC721Founders","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_konduxERC721kNFT","type":"address"}],"name":"setKonduxERC721kNFT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minStake","type":"uint256"},{"internalType":"address","name":"_tokenId","type":"address"}],"name":"setMinStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ratio","type":"uint256"},{"internalType":"address","name":"_tokenId","type":"address"}],"name":"setRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_category","type":"uint256"},{"internalType":"uint256","name":"_boost","type":"uint256"}],"name":"setTimelockCategoryBoost","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_treasury","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_withdrawalFee","type":"uint256"},{"internalType":"address","name":"_tokenId","type":"address"}],"name":"setWithdrawalFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_kNFTRewardBoost","type":"uint256"},{"internalType":"address","name":"_tokenId","type":"address"}],"name":"setkNFTRewardBoost","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_depositId","type":"uint256"}],"name":"stakeRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"timelockCategoryBoost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"timelockDurations","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"totalRewarded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"totalStaked","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"totalWithdrawalFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"contract ITreasury","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"userDeposits","outputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"staker","type":"address"},{"internalType":"uint256","name":"deposited","type":"uint256"},{"internalType":"uint256","name":"redeemed","type":"uint256"},{"internalType":"uint256","name":"timeOfLastUpdate","type":"uint256"},{"internalType":"uint256","name":"lastDepositTime","type":"uint256"},{"internalType":"uint256","name":"unclaimedRewards","type":"uint256"},{"internalType":"uint256","name":"timelock","type":"uint256"},{"internalType":"uint8","name":"timelockCategory","type":"uint8"},{"internalType":"uint256","name":"ratioERC20","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"userDepositsIds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"userTotalRewardedByCoin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"userTotalStakedByCoin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_depositId","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_depositId","type":"uint256"}],"name":"withdrawAndClaim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"withdrawalFeeERC20","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

60806040523480156200001157600080fd5b506040516200689a3803806200689a83398101604081905262000034916200122b565b856001600160a01b038116620000915760405162461bcd60e51b815260206004820181905260248201527f417574686f726974792063616e6e6f74206265207a65726f206164647265737360448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0383169081179091556040519081527f2f658b440c35314f52658ea8a740e05b284cdc84dc9ae01e891f21b8933e7cad9060200160405180910390a1506001600160a01b0385166200013b5760405162461bcd60e51b815260206004820152601f60248201527f4b6f6e6475782045524332302061646472657373206973206e6f742073657400604482015260640162000088565b6001600160a01b038416620001935760405162461bcd60e51b815260206004820152601b60248201527f54726561737572792061646472657373206973206e6f74207365740000000000604482015260640162000088565b6001600160a01b038316620001fd5760405162461bcd60e51b815260206004820152602960248201527f4b6f6e6475782045524337323120466f756e64657273206164647265737320696044820152681cc81b9bdd081cd95d60ba1b606482015260840162000088565b6001600160a01b038216620002635760405162461bcd60e51b815260206004820152602560248201527f4b6f6e64757820455243373231206b4e46542061646472657373206973206e6f6044820152641d081cd95d60da1b606482015260840162000088565b6001600160a01b038116620002bb5760405162461bcd60e51b815260206004820152601e60248201527f48656c69782045524332302061646472657373206973206e6f74207365740000604482015260640162000088565b601880546001600160a01b038086166001600160a01b0319928316179092556019805485841690831617905560178054848416908316179055601a805492871692909116919091179055601660205262278d007f0263c2b778d062355049effc2dece97bc6547ff8a88a3258daa512061c2153dd556276a7007f4c4dc693d7db52f85fe052106f4b4b920e78e8ef37dee82878a60ab8585faf495562ed4e007fcaff291fe014adc6b72a172705750b4cabe8f8667664d2924a166caab28856485560036000526301e133807ff06d282f967055cb1eee17e04aa005b9682a620f4bbcfaee55ba78607a3d87ae55620003b66127108662000561565b620003c3606486620005f8565b620003d16103e88662000709565b620003df6101f486620007a0565b620003ee629896808662000837565b620003fb601986620008ce565b6200040a620151808662000965565b6200041861271086620009fc565b6200042585600a62000a93565b620004336001606462000b68565b62000442600261012c62000b68565b62000451600361038462000b68565b6200045e60018062000b84565b6017546040805163313ce56760e01b81529051620004d8926001600160a01b03169163313ce5679160048083019260209291908290030181865afa158015620004ab573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004d19190620012ac565b8262000bae565b62000548856001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200051b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620005419190620012ac565b8662000bae565b6200055585600162000c2a565b50505050505062001310565b6200056b62001143565b6001600160a01b038116620005b25760405162461bcd60e51b815260206004820152601860248201526000805160206200687a833981519152604482015260640162000088565b6001600160a01b0381166000818152601460205260408082208590555184917f6a437d814668577dce2f82ae56ed67161e12e20b59b9464687859d6a2ce0faa591a35050565b6200060262001143565b6001600160a01b038116620006495760405162461bcd60e51b815260206004820152601860248201526000805160206200687a833981519152604482015260640162000088565b6001600160a01b038116600090815260146020526040902054821115620006c35760405162461bcd60e51b815260206004820152602760248201527f5769746864726177616c206665652063616e6e6f74206265206d6f7265207468604482015266616e203130302560c81b606482015260840162000088565b6001600160a01b0381166000818152600860205260408082208590555184917f5d5169bb1fbf418e612b1934f181b6ce300a1aad27fdb0e6f6aadbd96f50bb8f91a35050565b6200071362001143565b6001600160a01b0381166200075a5760405162461bcd60e51b815260206004820152601860248201526000805160206200687a833981519152604482015260640162000088565b6001600160a01b0381166000818152600960205260408082208590555184917f1677c34b69a09796446af7a4c75943a1bb36202c16eb82199ef7d37d0ee4b28891a35050565b620007aa62001143565b6001600160a01b038116620007f15760405162461bcd60e51b815260206004820152601860248201526000805160206200687a833981519152604482015260640162000088565b6001600160a01b0381166000818152600a60205260408082208590555184917f11ef1060a695a1277b08edcbb2c364d43d4eb52f1060daaabf0df445cb6cdfdf91a35050565b6200084162001143565b6001600160a01b038116620008885760405162461bcd60e51b815260206004820152601860248201526000805160206200687a833981519152604482015260640162000088565b6001600160a01b0381166000818152600560205260408082208590555184917fef3cb734d88702dbb1c3bc381c52176876be95e70b66d3970d16653ee992a6c291a35050565b620008d862001143565b6001600160a01b0381166200091f5760405162461bcd60e51b815260206004820152601860248201526000805160206200687a833981519152604482015260640162000088565b6001600160a01b0381166000818152600760205260408082208590555184917fef97689adaec5b60041d413c3baef6876d5d01bb6c17b60cc980e2e244ef851791a35050565b6200096f62001143565b6001600160a01b038116620009b65760405162461bcd60e51b815260206004820152601860248201526000805160206200687a833981519152604482015260640162000088565b6001600160a01b0381166000818152600660205260408082208590555184917fd0d3d840363c3a773f4578f92d7914f6b37985570c79ee2889d69d7d8f12c29591a35050565b62000a0662001143565b6001600160a01b03811662000a4d5760405162461bcd60e51b815260206004820152601860248201526000805160206200687a833981519152604482015260640162000088565b6001600160a01b0381166000818152600b60205260408082208590555184917f62b574cc62ed3db0ae736cb4349346a234832cc8b215c6423fd67505addc2ffa91a35050565b62000a9d62001143565b6001600160a01b03821662000ae45760405162461bcd60e51b815260206004820152601860248201526000805160206200687a833981519152604482015260640162000088565b606481111562000b4c5760405162461bcd60e51b815260206004820152602c60248201527f50656e616c74792070657263656e74616765206d75737420626520626574776560448201526b0656e203020616e64203130360a41b606482015260840162000088565b6001600160a01b03909116600090815260126020526040902055565b62000b7262001143565b60009182526013602052604090912055565b62000b8e62001143565b600091825260156020526040909120805460ff1916911515919091179055565b62000bb862001143565b6001600160a01b03811662000bff5760405162461bcd60e51b815260206004820152601860248201526000805160206200687a833981519152604482015260640162000088565b6001600160a01b03166000908152600c60205260409020805460ff191660ff92909216919091179055565b6001600160a01b03821662000c825760405162461bcd60e51b815260206004820152601b60248201527f546f6b656e20616464726573732063616e6e6f74206265203078300000000000604482015260640162000088565b801515600103620010ef576001600160a01b03821660009081526007602052604090205462000d045760405162461bcd60e51b815260206004820152602760248201527f526577617264732070657220686f7572206d75737420626520677265617465726044820152660207468616e20360cc1b606482015260840162000088565b6001600160a01b03821660009081526006602052604090205462000d7d5760405162461bcd60e51b815260206004820152602960248201527f436f6d706f756e64206672657175656e6379206d75737420626520677265617460448201526806572207468616e20360bc1b606482015260840162000088565b6001600160a01b03821660009081526008602052604090205462000df25760405162461bcd60e51b815260206004820152602560248201527f5769746864726177616c20666565206d75737420626520677265617465722074604482015264068616e20360dc1b606482015260840162000088565b6001600160a01b03821660009081526009602052604090205462000e6e5760405162461bcd60e51b815260206004820152602c60248201527f466f756e646572732072657761726420626f6f7374206d75737420626520677260448201526b06561746572207468616e20360a41b606482015260840162000088565b6001600160a01b0382166000908152600a602052604090205462000ee65760405162461bcd60e51b815260206004820152602860248201527f6b4e46542072657761726420626f6f7374206d75737420626520677265617465604482015267072207468616e20360c41b606482015260840162000088565b6001600160a01b0382166000908152600b602052604090205462000f4d5760405162461bcd60e51b815260206004820152601c60248201527f526174696f206d7573742062652067726561746572207468616e203000000000604482015260640162000088565b6001600160a01b03821660009081526005602052604090205462000fc05760405162461bcd60e51b8152602060048201526024808201527f4d696e696d756d207374616b65206d75737420626520677265617465722074686044820152630616e20360e41b606482015260840162000088565b6001600160a01b038216600090815260146020526040902054620010275760405162461bcd60e51b815260206004820152601e60248201527f44697669736f72206d7573742062652067726561746572207468616e20300000604482015260640162000088565b6000826001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562001068573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200108e9190620012d8565b11620010ef5760405162461bcd60e51b815260206004820152602960248201527f546f6b656e20746f74616c20737570706c79206d75737420626520677265617460448201526806572207468616e20360bc1b606482015260840162000088565b6001600160a01b038216600081815260046020526040808220805460ff191685151590811790915590519092917f59261974a183535ca20bb33ae77db42c679a079844739a2e10f0b6ecb847379a91a35050565b60008054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b8152600401602060405180830381865afa15801562001195573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620011bb9190620012f2565b6001600160a01b0316336001600160a01b0316146200120c5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b604482015260640162000088565b565b80516001600160a01b03811681146200122657600080fd5b919050565b60008060008060008060c087890312156200124557600080fd5b62001250876200120e565b955062001260602088016200120e565b945062001270604088016200120e565b935062001280606088016200120e565b925062001290608088016200120e565b9150620012a060a088016200120e565b90509295509295509295565b600060208284031215620012bf57600080fd5b815160ff81168114620012d157600080fd5b9392505050565b600060208284031215620012eb57600080fd5b5051919050565b6000602082840312156200130557600080fd5b620012d1826200120e565b61555a80620013206000396000f3fe608060405234801561001057600080fd5b50600436106105a15760003560e01c806384d3d586116102ed578063d55111c511610191578063f0d33cad116100ee578063f384fe76116100a2578063fb68d53b1161007c578063fb68d53b14610f99578063fe1686b814610fd3578063fe31b2281461100d57600080fd5b8063f384fe7614610f30578063f91159e314610f50578063fad68d1f14610f7957600080fd5b8063f16b41f4116100d3578063f16b41f414610e2a578063f19d684914610ef4578063f2760e9d14610f0757600080fd5b8063f0d33cad14610deb578063f0f4426014610e1757600080fd5b8063e519cf1711610145578063ec6401531161012a578063ec64015314610da2578063f02842a514610db5578063f02d4a4514610dd857600080fd5b8063e519cf1714610d59578063ea425a6d14610d8257600080fd5b8063dad775b111610176578063dad775b114610d0a578063dd2a8b1114610d1d578063e37d47e414610d4657600080fd5b8063d55111c514610cd7578063d6b9243414610cea57600080fd5b8063b54b9c881161024a578063bf811fbc116101fe578063c706fee5116101d8578063c706fee514610c88578063cf717c8c14610cb1578063cfb656a514610cc457600080fd5b8063bf811fbc14610c2c578063c39ccf8814610c3f578063c5ebc2f714610c6857600080fd5b8063ba5771481161022f578063ba57714814610bf3578063beb8314c14610c06578063bf7e214f14610c1957600080fd5b8063b54b9c8814610bb0578063b6740c3b14610bd057600080fd5b80639bfd8d61116102a1578063a55dfa1c11610286578063a55dfa1c14610b77578063a9b2940714610b8a578063aaa78db414610b9d57600080fd5b80639bfd8d6114610b44578063a13d507914610b6457600080fd5b806389d5e38a116102d257806389d5e38a14610b0b578063911ddf0a14610b1e57806396ce362714610b3157600080fd5b806384d3d58614610ad857806387eebaea14610af857600080fd5b80634715f40c116104545780635a5392be116103b157806372aa9d91116103655780637b16c5431161033f5780637b16c54314610a7a5780637bf7f3d314610aa55780637cbfd14414610ab857600080fd5b806372aa9d9114610a3457806378e2816b14610a545780637a9e5e4b14610a6757600080fd5b80635dfa4596116103965780635dfa4596146109d657806361d027b314610a015780636e3c115414610a1457600080fd5b80635a5392be146109a05780635cd3667e146109c357600080fd5b80635385689c116104085780635722dee0116103ed5780635722dee014610931578063580e26a11461095a57806359b0e5901461097d57600080fd5b80635385689c146108e6578063546f2b661461091157600080fd5b80634a912ce5116104395780634a912ce5146108785780634e781513146108ab5780635328c2bf146108be57600080fd5b80634715f40c1461083c5780634774dc931461086557600080fd5b80632bcf161c116105025780633d0132e7116104b6578063404d221a1161049b578063404d221a14610803578063441a3e70146108165780634477c9741461082957600080fd5b80633d0132e7146107a85780633dc60a70146107f057600080fd5b806338c26d18116104e757806338c26d181461072d5780633a46a46d146107655780633ae5713d1461078557600080fd5b80632bcf161c146106f1578063336cada81461071a57600080fd5b8063171f9ce4116105595780631c5122d91161053e5780631c5122d9146106955780631e78e9a2146106be5780631f6514db146106de57600080fd5b8063171f9ce41461065f57806319720be11461067257600080fd5b80630962ef791161058a5780630962ef79146105fe57806310b1843814610613578063151a63491461063657600080fd5b80630399be55146105a657806306811c92146105d0575b600080fd5b6105b96105b4366004615030565b61102d565b6040516105c7929190615097565b60405180910390f35b6105f06105de3660046150c5565b60076020526000908152604090205481565b6040519081526020016105c7565b61061161060c3660046150e9565b611409565b005b6105f06106213660046150e9565b60009081526003602052604090206007015490565b6105f06106443660046150c5565b6001600160a01b031660009081526011602052604090205490565b61061161066d366004615102565b611765565b6105f06106803660046150e9565b60009081526003602052604090206005015490565b6105f06106a33660046150c5565b6001600160a01b031660009081526007602052604090205490565b6105f06106cc3660046150c5565b600a6020526000908152604090205481565b6106116106ec366004615102565b6117f7565b6105f06106ff3660046150c5565b6001600160a01b03166000908152600f602052604090205490565b610611610728366004615102565b611889565b61075361073b3660046150e9565b60009081526003602052604090206008015460ff1690565b60405160ff90911681526020016105c7565b6105f06107733660046150c5565b600b6020526000908152604090205481565b6107536107933660046150c5565b600c6020526000908152604090205460ff1681565b6107bb6107b6366004615030565b61191b565b60408051968752602087019590955260ff909316938501939093526060840152608083019190915260a082015260c0016105c7565b6105f06107fe366004615030565b611984565b610611610811366004615102565b611b79565b610611610824366004615132565b611c0b565b6106116108373660046150e9565b61236d565b6105f061084a3660046150c5565b6001600160a01b031660009081526009602052604090205490565b6105f0610873366004615163565b6125ec565b61089b6108863660046150e9565b60156020526000908152604090205460ff1681565b60405190151581526020016105c7565b6106116108b9366004615132565b612ca6565b6108d16108cc3660046150e9565b6134c9565b604080519283526020830191909152016105c7565b6019546108f9906001600160a01b031681565b6040516001600160a01b0390911681526020016105c7565b6105f061091f3660046150c5565b60096020526000908152604090205481565b6105f061093f3660046150c5565b6001600160a01b031660009081526008602052604090205490565b61089b6109683660046150c5565b60046020526000908152604090205460ff1681565b6105f061098b3660046150e9565b60009081526003602052604090206004015490565b6105f06109ae3660046150e9565b60009081526003602052604090206002015490565b6106116109d1366004615132565b613500565b6105f06109e43660046151a5565b600e60209081526000928352604080842090915290825290205481565b601a546108f9906001600160a01b031681565b6105f0610a223660046150e9565b60009081526013602052604090205490565b6105f0610a423660046150c5565b60056020526000908152604090205481565b610611610a623660046150c5565b61351a565b610611610a753660046150c5565b6135c2565b6105f0610a883660046151a5565b601060209081526000928352604080842090915290825290205481565b610611610ab33660046151e1565b61361e565b6105f0610ac63660046150c5565b60116020526000908152604090205481565b6105f0610ae63660046150c5565b60126020526000908152604090205481565b610611610b06366004615132565b613678565b6105f0610b193660046150c5565b61368b565b610611610b2c36600461520f565b6136e6565b610611610b3f366004615030565b613b6b565b6105f0610b523660046150c5565b600d6020526000908152604090205481565b610611610b72366004615102565b613c4a565b6105f0610b853660046150e9565b613cdc565b6017546108f9906001600160a01b031681565b610611610bab36600461526d565b613d3e565b6105f0610bbe3660046150c5565b60086020526000908152604090205481565b6105f0610bde3660046150e9565b60009081526003602052604090206009015490565b6105f0610c01366004615030565b613d66565b6105f0610c14366004615030565b613d97565b6000546108f9906001600160a01b031681565b610611610c3a3660046150c5565b613f02565b6105f0610c4d3660046150c5565b6001600160a01b031660009081526005602052604090205490565b610c7b610c763660046150c5565b613faa565b6040516105c79190615292565b6105f0610c963660046150c5565b6001600160a01b03166000908152600b602052604090205490565b610611610cbf366004615102565b614016565b610611610cd23660046150c5565b614136565b6018546108f9906001600160a01b031681565b6105f0610cf83660046150c5565b60146020526000908152604090205481565b610611610d18366004615102565b6141de565b6105f0610d2b3660046150c5565b6001600160a01b03166000908152600d602052604090205490565b610611610d54366004615102565b614270565b6105f0610d673660046150c5565b6001600160a01b03166000908152600a602052604090205490565b6105f0610d903660046150c5565b60066020526000908152604090205481565b6105f0610db0366004615030565b614302565b61089b610dc33660046150e9565b60009081526015602052604090205460ff1690565b6105b9610de63660046150c5565b61435f565b610753610df93660046150c5565b6001600160a01b03166000908152600c602052604090205460ff1690565b610611610e253660046150c5565b6146ad565b610e9c610e383660046150e9565b600360208190526000918252604090912080546001820154600283015493830154600484015460058501546006860154600787015460088801546009909801546001600160a01b0397881699969097169795969495939492939192909160ff16908a565b604080516001600160a01b039b8c1681529a90991660208b0152978901969096526060880194909452608087019290925260a086015260c085015260e084015260ff16610100830152610120820152610140016105c7565b610611610f023660046152a5565b614755565b6105f0610f153660046150c5565b6001600160a01b031660009081526012602052604090205490565b6105f0610f3e3660046150c5565b600f6020526000908152604090205481565b6105f0610f5e3660046150c5565b6001600160a01b031660009081526014602052604090205490565b6105f0610f873660046150e9565b60136020526000908152604090205481565b6105f0610fa73660046151a5565b6001600160a01b0380821660009081526010602090815260408083209386168352929052205492915050565b6105f0610fe13660046151a5565b6001600160a01b038082166000908152600e602090815260408083209386168352929052205492915050565b6105f061101b3660046152c3565b60166020526000908152604090205481565b6019546040516370a0823160e01b81526001600160a01b0384811660048301526060928392600092909116906370a0823190602401602060405180830381865afa15801561107f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110a391906152e0565b60408051600580825260c082019092529192506020820160a080368337505060408051600580825260c0820190925292955090506020820160a08036833701905050915060005b8181101561140057601954604051632f745c5960e01b81526001600160a01b038881166004830152602482018490526000921690632f745c5990604401602060405180830381865afa158015611144573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061116891906152e0565b600087815260036020526040908190206005015460195491516319d42f2f60e21b815260048101849052929350916001600160a01b0390911690636750bcbc90602401602060405180830381865afa1580156111c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ec91906152e0565b11156111f857506113ee565b60195460405163032bbfbd60e21b81526004810183905260006024820181905260016044830152916001600160a01b031690630caefef490606401602060405180830381865afa158015611250573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127491906152e0565b60008181526015602052604090205490915060ff166112945750506113ee565b60195460405163032bbfbd60e21b81526004810184905260016024820152600260448201526000916001600160a01b031690630caefef490606401602060405180830381865afa1580156112ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061131091906152e0565b61131b90606461530f565b9050600081121561132a575060005b60005b60058110156113e9578781815181106113485761134861533f565b60200260200101518211156113d757600088828151811061136b5761136b61533f565b60200260200101519050828983815181106113885761138861533f565b60200260200101818152505080925060008883815181106113ab576113ab61533f565b60200260200101519050858984815181106113c8576113c861533f565b60209081029190910101529450505b806113e181615355565b91505061132d565b505050505b806113f881615355565b9150506110ea565b50509250929050565b6000818152600360205260409020600101546001600160a01b031633146114855760405162461bcd60e51b815260206004820152602560248201527f596f7520617265206e6f7420746865206f776e6572206f6620746869732064656044820152641c1bdcda5d60da1b60648201526084015b60405180910390fd5b6000818152600360205260409020600701544210156114e65760405162461bcd60e51b815260206004820152601360248201527f54696d656c6f636b206e6f742070617373656400000000000000000000000000604482015260640161147c565b6000818152600360205260408120600601546115023384613d97565b61150c919061536e565b90506000811161155e5760405162461bcd60e51b815260206004820152601360248201527f596f752068617665206e6f207265776172647300000000000000000000000000604482015260640161147c565b600082815260036020908152604080832060068101849055426004820155546001600160a01b03168084526014835281842054600890935290832054909291906115aa90612710615381565b6115b49085615394565b6115be91906153ab565b905060006115cc8285615381565b9050826001600160a01b03166323b872dd60008054906101000a90046001600160a01b03166001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561162e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061165291906153cd565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152336024820152604481018590526064016020604051808303816000875af11580156116a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116c991906153ea565b50600085815260036020526040902080546001909101546116f89184916001600160a01b0391821691166147cc565b6117226117058386615381565b6000878152600360205260409020546001600160a01b031661483a565b604080518381526020810183905233917f02a6a2be713fedf52f113c0a759f1c1a23a113476d9b1b1a2a453c910660de4e91015b60405180910390a25050505050565b61176d61486b565b6001600160a01b0381166117b15760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6001600160a01b0381166000818152600b60205260408082208590555184917f62b574cc62ed3db0ae736cb4349346a234832cc8b215c6423fd67505addc2ffa91a35050565b6117ff61486b565b6001600160a01b0381166118435760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6001600160a01b0381166000818152600960205260408082208590555184917f1677c34b69a09796446af7a4c75943a1bb36202c16eb82199ef7d37d0ee4b28891a35050565b61189161486b565b6001600160a01b0381166118d55760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6001600160a01b0381166000818152600760205260408082208590555184917fef97689adaec5b60041d413c3baef6876d5d01bb6c17b60cc980e2e244ef851791a35050565b60008060008060008061193d8760009081526003602052604090206007015490565b60008881526003602052604090206005810154600890910154919750955060ff169350611969876134c9565b90935091506119788888611984565b90509295509295509295565b600081815260036020818152604080842081516101408101835281546001600160a01b0390811680835260018401548216838701526002840154838601529583015460608301526004808401546080840152600584015460a0840152600684015460c0840152600784015460e0840152600884015460ff1661010084015260099093015461012083015294865260149093528185205460185492516370a0823160e01b81528886169281019290925294929391909116906370a0823190602401602060405180830381865afa158015611a61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a8591906152e0565b1115611ab25780516001600160a01b0316600090815260096020526040902054611aaf908361536e565b91505b6019546040516370a0823160e01b81526001600160a01b03868116600483015260009216906370a0823190602401602060405180830381865afa158015611afd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b2191906152e0565b1115611b3e57611b318484614302565b611b3b908361536e565b91505b61010081015160ff1615611b715761010081015160ff16600090815260136020526040902054611b6e908361536e565b91505b505b92915050565b611b8161486b565b6001600160a01b038116611bc55760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6001600160a01b0381166000818152600560205260408082208590555184917fef3cb734d88702dbb1c3bc381c52176876be95e70b66d3970d16653ee992a6c291a35050565b600081815260036020526040902060070154421015611c6c5760405162461bcd60e51b815260206004820152601360248201527f54696d656c6f636b206e6f742070617373656400000000000000000000000000604482015260640161147c565b6000818152600360205260409020600101546001600160a01b03163314611ce35760405162461bcd60e51b815260206004820152602560248201527f596f7520617265206e6f7420746865206f776e6572206f6620746869732064656044820152641c1bdcda5d60da1b606482015260840161147c565b600081815260036020526040902060020154821115611d4e5760405162461bcd60e51b815260206004820152602160248201527f43616e2774207769746864726177206d6f7265207468616e20796f75206861766044820152606560f81b606482015260840161147c565b6017546040516370a0823160e01b81523360048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015611d96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dba91906152e0565b600082815260036020526040902060090154611dd69084615394565b1115611e4a5760405162461bcd60e51b815260206004820152603760248201527f43616e2774207769746864726177206d6f726520746f6b656e73207468616e2060448201527f74686520636f6c6c61746572616c20796f752068617665000000000000000000606482015260840161147c565b6000611e563383613d97565b905082600360008481526020019081526020016000206002016000828254611e7e9190615381565b909155505060008281526003602052604081204260048201556006018054839290611eaa90849061536e565b90915550506000828152600360209081526040808320546001600160a01b031683526014808352818420546008845291842054925290611eea9082615381565b611ef49086615394565b611efe91906153ab565b90506000611f0c8286615381565b6000858152600360209081526040808320549254815163fbfa77cf60e01b815291519495506001600160a01b03938416948794869463dd62ed3e94919093169263fbfa77cf926004808401938290030181865afa158015611f71573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f9591906153cd565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152306024820152604401602060405180830381865afa158015611fdf573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061200391906152e0565b10156120a85760405162461bcd60e51b815260206004820152606260248201527f547265617375727920436f6e7472616374206e65656420746f20617070726f7660448201527f65205374616b696e6720436f6e747261637420746f207769746864726177207960648201527f6f757220746f6b656e73202d2d20706c656173652063616c6c20616e2041646d60848201526134b760f11b60a482015260c40161147c565b600085815260036020526040902080546001909101546120d69188916001600160a01b039182169116614942565b6000858152600360209081526040808320546001600160a01b039081168452600c90925280832054601754909216835282205460ff918216929116908183101561212e576121248383615407565b60ff169050612132565b5060005b6017546001600160a01b0316639dc29fac3361214f84600a615504565b60008c81526003602052604090206009015461216b908e615394565b6121759190615394565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b1580156121bb57600080fd5b505af11580156121cf573d6000803e3d6000fd5b50505050836001600160a01b03166323b872dd60008054906101000a90046001600160a01b03166001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612233573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061225791906153cd565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152336024820152604481018990526064016020604051808303816000875af11580156122aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122ce91906153ea565b50600088815260036020526040902080546001909101546122fd9188916001600160a01b0391821691166147cc565b61232761230a878b615381565b60008a8152600360205260409020546001600160a01b031661483a565b604080518781526020810187905233917ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568910160405180910390a2505050505050505050565b6000818152600360205260409020600101546001600160a01b031633146123e45760405162461bcd60e51b815260206004820152602560248201527f596f7520617265206e6f7420746865206f776e6572206f6620746869732064656044820152641c1bdcda5d60da1b606482015260840161147c565b6000818152600360205260408120600601546124003384613d97565b61240a919061536e565b90506000811161245c5760405162461bcd60e51b815260206004820152601460248201527f4e6f207265776172647320617661696c61626c65000000000000000000000000604482015260640161147c565b600082815260036020526040812060068101829055600201805483929061248490849061536e565b9091555050600082815260036020526040902042600482015580546001909101546124bd9183916001600160a01b039182169116614ab3565b6000828152600360209081526040808320546001600160a01b039081168452600c90925280832054601754909216835282205460ff91821692911690828211156125155761250b8383615407565b60ff169050612519565b5060005b6017546001600160a01b03166340c10f193361253684600a615504565b6000898152600360205260409020600901546125529089615394565b61255c9190615394565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b1580156125a257600080fd5b505af11580156125b6573d6000803e3d6000fd5b50506040518681523392507f169f1815ebdea059aac3bb00ec9a9594c7a5ffcb64a17e8392b5d84909a145569150602001611756565b60006001600160a01b0382166126325760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6001600160a01b03821660009081526004602052604090205460ff1661269a5760405162461bcd60e51b815260206004820152601460248201527f546f6b656e206e6f7420617574686f72697a6564000000000000000000000000604482015260640161147c565b6001600160a01b0382166000908152600560205260409020548410156127105760405162461bcd60e51b815260206004820152602560248201527f416d6f756e7420736d616c6c6572207468616e206d696e696d696d756d2064656044820152641c1bdcda5d60da1b606482015260840161147c565b6040516370a0823160e01b8152336004820152829085906001600160a01b038316906370a0823190602401602060405180830381865afa158015612758573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061277c91906152e0565b10156127ca5760405162461bcd60e51b815260206004820152601d60248201527f43616e2774207374616b65206d6f7265207468616e20796f75206f776e000000604482015260640161147c565b604051636eb1769f60e11b815233600482015230602482015285906001600160a01b0383169063dd62ed3e90604401602060405180830381865afa158015612816573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061283a91906152e0565b10156128885760405162461bcd60e51b815260206004820152601160248201527f416c6c6f77616e6365206e6f7420736574000000000000000000000000000000604482015260640161147c565b60038460ff1611156128dc5760405162461bcd60e51b815260206004820152601060248201527f496e76616c69642074696d656c6f636b00000000000000000000000000000000604482015260640161147c565b60006128e760015490565b9050604051806101400160405280856001600160a01b03168152602001336001600160a01b031681526020018781526020016000815260200142815260200142815260200160008152602001601660008860ff1660ff1681526020019081526020016000205442612958919061536e565b815260ff8781166020808401919091526001600160a01b038881166000908152600b8352604080822054958101959095528681526003808452858220875181546001600160a01b0319908116918616919091178255888601516001808401805490931691909616179055878701516002808301919091556060890151928201929092556080880151600482015560a0880151600582015560c0880151600682015560e0880151600782015561010088015160088201805460ff191691909716179095556101209096015160099094019390935533808452948252928220805493840181558252902001829055612a519087908690614ab3565b6001600160a01b038085166000908152600c602052604080822054601754909316825281205460ff92831692169082821115612a9b57612a918383615407565b60ff169050612a9f565b5060005b846001600160a01b03166323b872dd3360008054906101000a90046001600160a01b03166001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b00573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b2491906153cd565b6040516001600160e01b031960e085901b1681526001600160a01b03928316600482015291166024820152604481018c90526064016020604051808303816000875af1158015612b78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b9c91906153ea565b506017546001600160a01b03166340c10f1933612bba84600a615504565b6001600160a01b038b166000908152600b6020526040902054612bdd908e615394565b612be79190615394565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b158015612c2d57600080fd5b505af1158015612c41573d6000803e3d6000fd5b50505050612c53600180546001019055565b604080516001600160a01b0389168152602081018b9052339186917ff7373f56c201647feae85a62d3cf56286ed3a43d20c5eb7f9883d6ea690ef7c0910160405180910390a35091979650505050505050565b6000818152600360205260409020600101546001600160a01b03163314612d1d5760405162461bcd60e51b815260206004820152602560248201527f596f7520617265206e6f7420746865206f776e6572206f6620746869732064656044820152641c1bdcda5d60da1b606482015260840161147c565b600081815260036020526040902060020154821115612d885760405162461bcd60e51b815260206004820152602160248201527f43616e2774207769746864726177206d6f7265207468616e20796f75206861766044820152606560f81b606482015260840161147c565b6017546040516370a0823160e01b81523360048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015612dd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612df491906152e0565b600082815260036020526040902060090154612e109084615394565b1115612e845760405162461bcd60e51b815260206004820152603760248201527f43616e2774207769746864726177206d6f726520746f6b656e73207468616e2060448201527f74686520636f6c6c61746572616c20796f752068617665000000000000000000606482015260840161147c565b6000818152600360205260409020600701544210612ee45760405162461bcd60e51b815260206004820152601360248201527f54696d656c6f636b206861732070617373656400000000000000000000000000604482015260640161147c565b600081815260036020526040812060070154612f01904290615381565b600083815260036020526040812060058101546007909101549293509091612f299190615381565b90506000612f38826064615394565b6000858152600360209081526040808320546001600160a01b0316835260129091529020548490612f699088615394565b612f739190615394565b612f7d91906153ab565b905084811115612f8a5750835b80600003612fac576064612f9f866001615394565b612fa991906153ab565b90505b6000848152600360209081526040808320546001600160a01b031683526008909152812054612fdb908361536e565b90506000612fe98288615381565b90506000612ff78289615381565b90508760036000898152602001908152602001600020600201600082825461301f9190615381565b909155505060008781526003602090815260408083204260048083019190915590549354825163fbfa77cf60e01b815292516001600160a01b03958616958895879563dd62ed3e95929094169363fbfa77cf938184019390918290030181865afa158015613091573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130b591906153cd565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152306024820152604401602060405180830381865afa1580156130ff573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061312391906152e0565b10156131c85760405162461bcd60e51b815260206004820152606260248201527f547265617375727920436f6e7472616374206e65656420746f20617070726f7660448201527f65205374616b696e6720436f6e747261637420746f207769746864726177207960648201527f6f757220746f6b656e73202d2d20706c656173652063616c6c20616e2041646d60848201526134b760f11b60a482015260c40161147c565b600088815260036020526040902080546001909101546131f6918b916001600160a01b039182169116614942565b6017546001600160a01b039081166000908152600c60208181526040808420548d855260038352818520549095168452919052812054909160ff90811691161015613289576000898152600360209081526040808320546001600160a01b039081168452600c9092528083205460175490921683529091205461327f9160ff9081169116615407565b60ff16905061328d565b5060005b6017546001600160a01b0316639dc29fac336132aa84600a615504565b60008d8152600360205260409020600901546132c6908f615394565b6132d09190615394565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b15801561331657600080fd5b505af115801561332a573d6000803e3d6000fd5b50505050816001600160a01b03166323b872dd60008054906101000a90046001600160a01b03166001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561338e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133b291906153cd565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152336024820152604481018790526064016020604051808303816000875af1158015613405573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061342991906153ea565b50600089815260036020526040902080546001909101546134589186916001600160a01b0391821691166147cc565b613482613465858c615381565b60008b8152600360205260409020546001600160a01b031661483a565b604080518581526020810185905233917ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568910160405180910390a250505050505050505050565b600081815260036020526040812060028101546006909101549091906134ef3385613d97565b6134f9919061536e565b9050915091565b61350861486b565b60009182526013602052604090912055565b61352261486b565b6001600160a01b0381166135785760405162461bcd60e51b815260206004820152601e60248201527f466f756e6465727320616464726573732063616e6e6f74206265203078300000604482015260640161147c565b601880546001600160a01b0319166001600160a01b0383169081179091556040517f23008753c65029d55e051a14341d50cf19b808653ba432a5faeb07bd7865e25b90600090a250565b6135ca61486b565b600080546001600160a01b0319166001600160a01b0383169081179091556040519081527f2f658b440c35314f52658ea8a740e05b284cdc84dc9ae01e891f21b8933e7cad9060200160405180910390a150565b61362661486b565b6001600160a01b03821661366a5760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6136748282614b17565b5050565b6136828282611c0b565b61367481611409565b6000806136978361435f565b50905060005b60058110156136df578181815181106136b8576136b861533f565b6020026020010151836136cb919061536e565b9250806136d781615355565b91505061369d565b5050919050565b6136ee61486b565b6001600160a01b0388166137445760405162461bcd60e51b815260206004820152601b60248201527f546f6b656e20616464726573732063616e6e6f74206265203078300000000000604482015260640161147c565b600087116137a45760405162461bcd60e51b815260206004820152602760248201527f526577617264732070657220686f7572206d75737420626520677265617465726044820152660207468616e20360cc1b606482015260840161147c565b600086116138065760405162461bcd60e51b815260206004820152602960248201527f436f6d706f756e64206672657175656e6379206d75737420626520677265617460448201526806572207468616e20360bc1b606482015260840161147c565b600085116138645760405162461bcd60e51b815260206004820152602560248201527f5769746864726177616c20666565206d75737420626520677265617465722074604482015264068616e20360dc1b606482015260840161147c565b600084116138c95760405162461bcd60e51b815260206004820152602c60248201527f466f756e646572732072657761726420626f6f7374206d75737420626520677260448201526b06561746572207468616e20360a41b606482015260840161147c565b6000831161392a5760405162461bcd60e51b815260206004820152602860248201527f6b4e46542072657761726420626f6f7374206d75737420626520677265617465604482015267072207468616e20360c41b606482015260840161147c565b6000821161397a5760405162461bcd60e51b815260206004820152601c60248201527f526174696f206d7573742062652067726561746572207468616e203000000000604482015260640161147c565b600081116139d65760405162461bcd60e51b8152602060048201526024808201527f4d696e696d756d207374616b65206d75737420626520677265617465722074686044820152630616e20360e41b606482015260840161147c565b6000886001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613a16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a3a91906152e0565b11613a995760405162461bcd60e51b815260206004820152602960248201527f546f6b656e20746f74616c20737570706c79206d75737420626520677265617460448201526806572207468616e20360bc1b606482015260840161147c565b613aa5612710896141de565b613aaf84896117f7565b613ab98389613c4a565b613ac38789611889565b613acd8289611765565b613ad78589614016565b613ae18689614270565b613aeb8189611b79565b613b56886001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015613b2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b509190615510565b89614755565b613b61886001614b17565b5050505050505050565b613b7361486b565b6001600160a01b038216613bb75760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6064811115613c2e5760405162461bcd60e51b815260206004820152602c60248201527f50656e616c74792070657263656e74616765206d75737420626520626574776560448201527f656e203020616e64203130300000000000000000000000000000000000000000606482015260840161147c565b6001600160a01b03909116600090815260126020526040902055565b613c5261486b565b6001600160a01b038116613c965760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6001600160a01b0381166000818152600a60205260408082208590555184917f11ef1060a695a1277b08edcbb2c364d43d4eb52f1060daaabf0df445cb6cdfdf91a35050565b6000818152600360209081526040808320600481015490546001600160a01b031684526006909252822054613d11818361536e565b4210613d21575060009392505050565b42613d2c828461536e565b613d369190615381565b949350505050565b613d4661486b565b600091825260156020526040909120805460ff1916911515919091179055565b60026020528160005260406000208181548110613d8257600080fd5b90600052602060002001600091509150505481565b600081815260036020818152604080842081516101408101835281546001600160a01b0390811682526001830154811694820185905260028301549382019390935293810154606085015260048101546080850152600581015460a0850152600681015460c0850152600781015460e0850152600881015460ff1661010085015260090154610120840152851614613e33576000915050611b73565b6000816080015142613e459190615381565b60408084015184516001600160a01b03166000908152600760205291822054929350919063bbf81e00613e788385615394565b613e8a90670de0b6b3a7640000615394565b613e9491906153ab565b90506000670de0b6b3a7640000613eab8387615394565b613eb591906153ab565b90506000613ec38a8a611984565b87516001600160a01b0316600090815260146020526040902054909150613eea8284615394565b613ef491906153ab565b9a9950505050505050505050565b613f0a61486b565b6001600160a01b038116613f605760405162461bcd60e51b815260206004820152601a60248201527f6b4e465420616464726573732063616e6e6f7420626520307830000000000000604482015260640161147c565b601980546001600160a01b0319166001600160a01b0383169081179091556040517fc8e08c5b2fa487609cdc92d5cfcc240f3c8fc73ac5e58fafc5d465d20aaaf31290600090a250565b6001600160a01b03811660009081526002602090815260409182902080548351818402810184019094528084526060939283018282801561400a57602002820191906000526020600020905b815481526020019060010190808311613ff6575b50505050509050919050565b61401e61486b565b6001600160a01b0381166140625760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6001600160a01b0381166000908152601460205260409020548211156140f05760405162461bcd60e51b815260206004820152602760248201527f5769746864726177616c206665652063616e6e6f74206265206d6f726520746860448201527f616e203130302500000000000000000000000000000000000000000000000000606482015260840161147c565b6001600160a01b0381166000818152600860205260408082208590555184917f5d5169bb1fbf418e612b1934f181b6ce300a1aad27fdb0e6f6aadbd96f50bb8f91a35050565b61413e61486b565b6001600160a01b0381166141945760405162461bcd60e51b815260206004820152601b60248201527f48656c697820616464726573732063616e6e6f74206265203078300000000000604482015260640161147c565b601780546001600160a01b0319166001600160a01b0383169081179091556040517fdcbeffeaf77a19486e34d4b5fc3809913d1e7125a43b8dcdb17944ab2c17579090600090a250565b6141e661486b565b6001600160a01b03811661422a5760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6001600160a01b0381166000818152601460205260408082208590555184917f6a437d814668577dce2f82ae56ed67161e12e20b59b9464687859d6a2ce0faa591a35050565b61427861486b565b6001600160a01b0381166142bc5760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6001600160a01b0381166000818152600660205260408082208590555184917fd0d3d840363c3a773f4578f92d7914f6b37985570c79ee2889d69d7d8f12c29591a35050565b60008061430f848461102d565b50905060005b6005811015614357578181815181106143305761433061533f565b602002602001015183614343919061536e565b92508061434f81615355565b915050614315565b505092915050565b6019546040516370a0823160e01b81526001600160a01b0383811660048301526060928392600092909116906370a0823190602401602060405180830381865afa1580156143b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143d591906152e0565b60408051600580825260c082019092529192506020820160a080368337505060408051600580825260c0820190925292955090506020820160a08036833701905050915060005b818110156146a657601954604051632f745c5960e01b81526001600160a01b038781166004830152602482018490526000921690632f745c5990604401602060405180830381865afa158015614476573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061449a91906152e0565b60195460405163032bbfbd60e21b815260048101839052600060248201819052600160448301529293506001600160a01b0390911690630caefef490606401602060405180830381865afa1580156144f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061451a91906152e0565b60008181526015602052604090205490915060ff1661453a575050614694565b60195460405163032bbfbd60e21b81526004810184905260016024820152600260448201526000916001600160a01b031690630caefef490606401602060405180830381865afa158015614592573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145b691906152e0565b6145c190606461530f565b905060008112156145d0575060005b60005b600581101561468f578781815181106145ee576145ee61533f565b602002602001015182111561467d5760008882815181106146115761461161533f565b602002602001015190508289838151811061462e5761462e61533f565b60200260200101818152505080925060008883815181106146515761465161533f565b602002602001015190508589848151811061466e5761466e61533f565b60209081029190910101529450505b8061468781615355565b9150506145d3565b505050505b8061469e81615355565b91505061441c565b5050915091565b6146b561486b565b6001600160a01b03811661470b5760405162461bcd60e51b815260206004820152601e60248201527f547265617375727920616464726573732063616e6e6f74206265203078300000604482015260640161147c565b601a80546001600160a01b0319166001600160a01b0383169081179091556040517fafa147634b29e2c7bd53ce194256b9f41cfb9ba3036f2b822fdd1d965beea08690600090a250565b61475d61486b565b6001600160a01b0381166147a15760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6001600160a01b03166000908152600c60205260409020805460ff191660ff92909216919091179055565b6001600160a01b0382166000908152600f6020526040812080548592906147f490849061536e565b90915550506001600160a01b0380831660009081526010602090815260408083209385168352929052908120805485929061483090849061536e565b9091555050505050565b6001600160a01b0381166000908152601160205260408120805484929061486290849061536e565b90915550505050565b60008054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b8152600401602060405180830381865afa1580156148bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148e091906153cd565b6001600160a01b0316336001600160a01b0316146149405760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a45440000000000000000000000000000000000000000604482015260640161147c565b565b6001600160a01b0382166000908152600d60205260409020548311156149d05760405162461bcd60e51b815260206004820152602560248201527f5374616b696e673a204e6f7420656e6f756768207374616b65642028436f6e7460448201527f7261637429000000000000000000000000000000000000000000000000000000606482015260840161147c565b6001600160a01b038083166000908152600e6020908152604080832093851683529290522054831115614a4f5760405162461bcd60e51b815260206004820152602160248201527f5374616b696e673a204e6f7420656e6f756768207374616b65642028557365726044820152602960f81b606482015260840161147c565b6001600160a01b0382166000908152600d602052604081208054859290614a77908490615381565b90915550506001600160a01b038083166000908152600e6020908152604080832093851683529290529081208054859290614830908490615381565b6001600160a01b0382166000908152600d602052604081208054859290614adb90849061536e565b90915550506001600160a01b038083166000908152600e602090815260408083209385168352929052908120805485929061483090849061536e565b6001600160a01b038216614b6d5760405162461bcd60e51b815260206004820152601b60248201527f546f6b656e20616464726573732063616e6e6f74206265203078300000000000604482015260640161147c565b801515600103614fc4576001600160a01b038216600090815260076020526040902054614bec5760405162461bcd60e51b815260206004820152602760248201527f526577617264732070657220686f7572206d75737420626520677265617465726044820152660207468616e20360cc1b606482015260840161147c565b6001600160a01b038216600090815260066020526040902054614c635760405162461bcd60e51b815260206004820152602960248201527f436f6d706f756e64206672657175656e6379206d75737420626520677265617460448201526806572207468616e20360bc1b606482015260840161147c565b6001600160a01b038216600090815260086020526040902054614cd65760405162461bcd60e51b815260206004820152602560248201527f5769746864726177616c20666565206d75737420626520677265617465722074604482015264068616e20360dc1b606482015260840161147c565b6001600160a01b038216600090815260096020526040902054614d505760405162461bcd60e51b815260206004820152602c60248201527f466f756e646572732072657761726420626f6f7374206d75737420626520677260448201526b06561746572207468616e20360a41b606482015260840161147c565b6001600160a01b0382166000908152600a6020526040902054614dc65760405162461bcd60e51b815260206004820152602860248201527f6b4e46542072657761726420626f6f7374206d75737420626520677265617465604482015267072207468616e20360c41b606482015260840161147c565b6001600160a01b0382166000908152600b6020526040902054614e2b5760405162461bcd60e51b815260206004820152601c60248201527f526174696f206d7573742062652067726561746572207468616e203000000000604482015260640161147c565b6001600160a01b038216600090815260056020526040902054614e9c5760405162461bcd60e51b8152602060048201526024808201527f4d696e696d756d207374616b65206d75737420626520677265617465722074686044820152630616e20360e41b606482015260840161147c565b6001600160a01b038216600090815260146020526040902054614f015760405162461bcd60e51b815260206004820152601e60248201527f44697669736f72206d7573742062652067726561746572207468616e20300000604482015260640161147c565b6000826001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614f41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614f6591906152e0565b11614fc45760405162461bcd60e51b815260206004820152602960248201527f546f6b656e20746f74616c20737570706c79206d75737420626520677265617460448201526806572207468616e20360bc1b606482015260840161147c565b6001600160a01b038216600081815260046020526040808220805460ff191685151590811790915590519092917f59261974a183535ca20bb33ae77db42c679a079844739a2e10f0b6ecb847379a91a35050565b6001600160a01b038116811461502d57600080fd5b50565b6000806040838503121561504357600080fd5b823561504e81615018565b946020939093013593505050565b600081518084526020808501945080840160005b8381101561508c57815187529582019590820190600101615070565b509495945050505050565b6040815260006150aa604083018561505c565b82810360208401526150bc818561505c565b95945050505050565b6000602082840312156150d757600080fd5b81356150e281615018565b9392505050565b6000602082840312156150fb57600080fd5b5035919050565b6000806040838503121561511557600080fd5b82359150602083013561512781615018565b809150509250929050565b6000806040838503121561514557600080fd5b50508035926020909101359150565b60ff8116811461502d57600080fd5b60008060006060848603121561517857600080fd5b83359250602084013561518a81615154565b9150604084013561519a81615018565b809150509250925092565b600080604083850312156151b857600080fd5b82356151c381615018565b9150602083013561512781615018565b801515811461502d57600080fd5b600080604083850312156151f457600080fd5b82356151ff81615018565b91506020830135615127816151d3565b600080600080600080600080610100898b03121561522c57600080fd5b883561523781615018565b9a60208a01359a5060408a013599606081013599506080810135985060a0810135975060c0810135965060e00135945092505050565b6000806040838503121561528057600080fd5b823591506020830135615127816151d3565b6020815260006150e2602083018461505c565b600080604083850312156152b857600080fd5b82356151c381615154565b6000602082840312156152d557600080fd5b81356150e281615154565b6000602082840312156152f257600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b80820260008212600160ff1b8414161561532b5761532b6152f9565b8181058314821517611b7357611b736152f9565b634e487b7160e01b600052603260045260246000fd5b600060018201615367576153676152f9565b5060010190565b80820180821115611b7357611b736152f9565b81810381811115611b7357611b736152f9565b8082028115828204841417611b7357611b736152f9565b6000826153c857634e487b7160e01b600052601260045260246000fd5b500490565b6000602082840312156153df57600080fd5b81516150e281615018565b6000602082840312156153fc57600080fd5b81516150e2816151d3565b60ff8281168282160390811115611b7357611b736152f9565b600181815b8085111561545b578160001904821115615441576154416152f9565b8085161561544e57918102915b93841c9390800290615425565b509250929050565b60008261547257506001611b73565b8161547f57506000611b73565b8160018114615495576002811461549f576154bb565b6001915050611b73565b60ff8411156154b0576154b06152f9565b50506001821b611b73565b5060208310610133831016604e8410600b84101617156154de575081810a611b73565b6154e88383615420565b80600019048211156154fc576154fc6152f9565b029392505050565b60006150e28383615463565b60006020828403121561552257600080fd5b81516150e28161515456fe546f6b656e2061646472657373206973206e6f74207365740000000000000000a164736f6c6343000811000a546f6b656e2061646472657373206973206e6f742073657400000000000000000000000000000000000000006a005c11217863c4e300ce009c5ddc7e1672150a0000000000000000000000007ca5af5ba3472af6049f63c1abc324475d44efc1000000000000000000000000ad2e62e90c63d5c2b905c3f709cc3045aecdaa1e0000000000000000000000000fd5576c2842bd62dd00c5256491d11ccad84306000000000000000000000000ea6ab2871d5b3bbe6ded740c812d85700bae33c000000000000000000000000069a4a1cd8f2f2c3500f64634b9d69c642e9a5ca4

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106105a15760003560e01c806384d3d586116102ed578063d55111c511610191578063f0d33cad116100ee578063f384fe76116100a2578063fb68d53b1161007c578063fb68d53b14610f99578063fe1686b814610fd3578063fe31b2281461100d57600080fd5b8063f384fe7614610f30578063f91159e314610f50578063fad68d1f14610f7957600080fd5b8063f16b41f4116100d3578063f16b41f414610e2a578063f19d684914610ef4578063f2760e9d14610f0757600080fd5b8063f0d33cad14610deb578063f0f4426014610e1757600080fd5b8063e519cf1711610145578063ec6401531161012a578063ec64015314610da2578063f02842a514610db5578063f02d4a4514610dd857600080fd5b8063e519cf1714610d59578063ea425a6d14610d8257600080fd5b8063dad775b111610176578063dad775b114610d0a578063dd2a8b1114610d1d578063e37d47e414610d4657600080fd5b8063d55111c514610cd7578063d6b9243414610cea57600080fd5b8063b54b9c881161024a578063bf811fbc116101fe578063c706fee5116101d8578063c706fee514610c88578063cf717c8c14610cb1578063cfb656a514610cc457600080fd5b8063bf811fbc14610c2c578063c39ccf8814610c3f578063c5ebc2f714610c6857600080fd5b8063ba5771481161022f578063ba57714814610bf3578063beb8314c14610c06578063bf7e214f14610c1957600080fd5b8063b54b9c8814610bb0578063b6740c3b14610bd057600080fd5b80639bfd8d61116102a1578063a55dfa1c11610286578063a55dfa1c14610b77578063a9b2940714610b8a578063aaa78db414610b9d57600080fd5b80639bfd8d6114610b44578063a13d507914610b6457600080fd5b806389d5e38a116102d257806389d5e38a14610b0b578063911ddf0a14610b1e57806396ce362714610b3157600080fd5b806384d3d58614610ad857806387eebaea14610af857600080fd5b80634715f40c116104545780635a5392be116103b157806372aa9d91116103655780637b16c5431161033f5780637b16c54314610a7a5780637bf7f3d314610aa55780637cbfd14414610ab857600080fd5b806372aa9d9114610a3457806378e2816b14610a545780637a9e5e4b14610a6757600080fd5b80635dfa4596116103965780635dfa4596146109d657806361d027b314610a015780636e3c115414610a1457600080fd5b80635a5392be146109a05780635cd3667e146109c357600080fd5b80635385689c116104085780635722dee0116103ed5780635722dee014610931578063580e26a11461095a57806359b0e5901461097d57600080fd5b80635385689c146108e6578063546f2b661461091157600080fd5b80634a912ce5116104395780634a912ce5146108785780634e781513146108ab5780635328c2bf146108be57600080fd5b80634715f40c1461083c5780634774dc931461086557600080fd5b80632bcf161c116105025780633d0132e7116104b6578063404d221a1161049b578063404d221a14610803578063441a3e70146108165780634477c9741461082957600080fd5b80633d0132e7146107a85780633dc60a70146107f057600080fd5b806338c26d18116104e757806338c26d181461072d5780633a46a46d146107655780633ae5713d1461078557600080fd5b80632bcf161c146106f1578063336cada81461071a57600080fd5b8063171f9ce4116105595780631c5122d91161053e5780631c5122d9146106955780631e78e9a2146106be5780631f6514db146106de57600080fd5b8063171f9ce41461065f57806319720be11461067257600080fd5b80630962ef791161058a5780630962ef79146105fe57806310b1843814610613578063151a63491461063657600080fd5b80630399be55146105a657806306811c92146105d0575b600080fd5b6105b96105b4366004615030565b61102d565b6040516105c7929190615097565b60405180910390f35b6105f06105de3660046150c5565b60076020526000908152604090205481565b6040519081526020016105c7565b61061161060c3660046150e9565b611409565b005b6105f06106213660046150e9565b60009081526003602052604090206007015490565b6105f06106443660046150c5565b6001600160a01b031660009081526011602052604090205490565b61061161066d366004615102565b611765565b6105f06106803660046150e9565b60009081526003602052604090206005015490565b6105f06106a33660046150c5565b6001600160a01b031660009081526007602052604090205490565b6105f06106cc3660046150c5565b600a6020526000908152604090205481565b6106116106ec366004615102565b6117f7565b6105f06106ff3660046150c5565b6001600160a01b03166000908152600f602052604090205490565b610611610728366004615102565b611889565b61075361073b3660046150e9565b60009081526003602052604090206008015460ff1690565b60405160ff90911681526020016105c7565b6105f06107733660046150c5565b600b6020526000908152604090205481565b6107536107933660046150c5565b600c6020526000908152604090205460ff1681565b6107bb6107b6366004615030565b61191b565b60408051968752602087019590955260ff909316938501939093526060840152608083019190915260a082015260c0016105c7565b6105f06107fe366004615030565b611984565b610611610811366004615102565b611b79565b610611610824366004615132565b611c0b565b6106116108373660046150e9565b61236d565b6105f061084a3660046150c5565b6001600160a01b031660009081526009602052604090205490565b6105f0610873366004615163565b6125ec565b61089b6108863660046150e9565b60156020526000908152604090205460ff1681565b60405190151581526020016105c7565b6106116108b9366004615132565b612ca6565b6108d16108cc3660046150e9565b6134c9565b604080519283526020830191909152016105c7565b6019546108f9906001600160a01b031681565b6040516001600160a01b0390911681526020016105c7565b6105f061091f3660046150c5565b60096020526000908152604090205481565b6105f061093f3660046150c5565b6001600160a01b031660009081526008602052604090205490565b61089b6109683660046150c5565b60046020526000908152604090205460ff1681565b6105f061098b3660046150e9565b60009081526003602052604090206004015490565b6105f06109ae3660046150e9565b60009081526003602052604090206002015490565b6106116109d1366004615132565b613500565b6105f06109e43660046151a5565b600e60209081526000928352604080842090915290825290205481565b601a546108f9906001600160a01b031681565b6105f0610a223660046150e9565b60009081526013602052604090205490565b6105f0610a423660046150c5565b60056020526000908152604090205481565b610611610a623660046150c5565b61351a565b610611610a753660046150c5565b6135c2565b6105f0610a883660046151a5565b601060209081526000928352604080842090915290825290205481565b610611610ab33660046151e1565b61361e565b6105f0610ac63660046150c5565b60116020526000908152604090205481565b6105f0610ae63660046150c5565b60126020526000908152604090205481565b610611610b06366004615132565b613678565b6105f0610b193660046150c5565b61368b565b610611610b2c36600461520f565b6136e6565b610611610b3f366004615030565b613b6b565b6105f0610b523660046150c5565b600d6020526000908152604090205481565b610611610b72366004615102565b613c4a565b6105f0610b853660046150e9565b613cdc565b6017546108f9906001600160a01b031681565b610611610bab36600461526d565b613d3e565b6105f0610bbe3660046150c5565b60086020526000908152604090205481565b6105f0610bde3660046150e9565b60009081526003602052604090206009015490565b6105f0610c01366004615030565b613d66565b6105f0610c14366004615030565b613d97565b6000546108f9906001600160a01b031681565b610611610c3a3660046150c5565b613f02565b6105f0610c4d3660046150c5565b6001600160a01b031660009081526005602052604090205490565b610c7b610c763660046150c5565b613faa565b6040516105c79190615292565b6105f0610c963660046150c5565b6001600160a01b03166000908152600b602052604090205490565b610611610cbf366004615102565b614016565b610611610cd23660046150c5565b614136565b6018546108f9906001600160a01b031681565b6105f0610cf83660046150c5565b60146020526000908152604090205481565b610611610d18366004615102565b6141de565b6105f0610d2b3660046150c5565b6001600160a01b03166000908152600d602052604090205490565b610611610d54366004615102565b614270565b6105f0610d673660046150c5565b6001600160a01b03166000908152600a602052604090205490565b6105f0610d903660046150c5565b60066020526000908152604090205481565b6105f0610db0366004615030565b614302565b61089b610dc33660046150e9565b60009081526015602052604090205460ff1690565b6105b9610de63660046150c5565b61435f565b610753610df93660046150c5565b6001600160a01b03166000908152600c602052604090205460ff1690565b610611610e253660046150c5565b6146ad565b610e9c610e383660046150e9565b600360208190526000918252604090912080546001820154600283015493830154600484015460058501546006860154600787015460088801546009909801546001600160a01b0397881699969097169795969495939492939192909160ff16908a565b604080516001600160a01b039b8c1681529a90991660208b0152978901969096526060880194909452608087019290925260a086015260c085015260e084015260ff16610100830152610120820152610140016105c7565b610611610f023660046152a5565b614755565b6105f0610f153660046150c5565b6001600160a01b031660009081526012602052604090205490565b6105f0610f3e3660046150c5565b600f6020526000908152604090205481565b6105f0610f5e3660046150c5565b6001600160a01b031660009081526014602052604090205490565b6105f0610f873660046150e9565b60136020526000908152604090205481565b6105f0610fa73660046151a5565b6001600160a01b0380821660009081526010602090815260408083209386168352929052205492915050565b6105f0610fe13660046151a5565b6001600160a01b038082166000908152600e602090815260408083209386168352929052205492915050565b6105f061101b3660046152c3565b60166020526000908152604090205481565b6019546040516370a0823160e01b81526001600160a01b0384811660048301526060928392600092909116906370a0823190602401602060405180830381865afa15801561107f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110a391906152e0565b60408051600580825260c082019092529192506020820160a080368337505060408051600580825260c0820190925292955090506020820160a08036833701905050915060005b8181101561140057601954604051632f745c5960e01b81526001600160a01b038881166004830152602482018490526000921690632f745c5990604401602060405180830381865afa158015611144573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061116891906152e0565b600087815260036020526040908190206005015460195491516319d42f2f60e21b815260048101849052929350916001600160a01b0390911690636750bcbc90602401602060405180830381865afa1580156111c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ec91906152e0565b11156111f857506113ee565b60195460405163032bbfbd60e21b81526004810183905260006024820181905260016044830152916001600160a01b031690630caefef490606401602060405180830381865afa158015611250573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127491906152e0565b60008181526015602052604090205490915060ff166112945750506113ee565b60195460405163032bbfbd60e21b81526004810184905260016024820152600260448201526000916001600160a01b031690630caefef490606401602060405180830381865afa1580156112ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061131091906152e0565b61131b90606461530f565b9050600081121561132a575060005b60005b60058110156113e9578781815181106113485761134861533f565b60200260200101518211156113d757600088828151811061136b5761136b61533f565b60200260200101519050828983815181106113885761138861533f565b60200260200101818152505080925060008883815181106113ab576113ab61533f565b60200260200101519050858984815181106113c8576113c861533f565b60209081029190910101529450505b806113e181615355565b91505061132d565b505050505b806113f881615355565b9150506110ea565b50509250929050565b6000818152600360205260409020600101546001600160a01b031633146114855760405162461bcd60e51b815260206004820152602560248201527f596f7520617265206e6f7420746865206f776e6572206f6620746869732064656044820152641c1bdcda5d60da1b60648201526084015b60405180910390fd5b6000818152600360205260409020600701544210156114e65760405162461bcd60e51b815260206004820152601360248201527f54696d656c6f636b206e6f742070617373656400000000000000000000000000604482015260640161147c565b6000818152600360205260408120600601546115023384613d97565b61150c919061536e565b90506000811161155e5760405162461bcd60e51b815260206004820152601360248201527f596f752068617665206e6f207265776172647300000000000000000000000000604482015260640161147c565b600082815260036020908152604080832060068101849055426004820155546001600160a01b03168084526014835281842054600890935290832054909291906115aa90612710615381565b6115b49085615394565b6115be91906153ab565b905060006115cc8285615381565b9050826001600160a01b03166323b872dd60008054906101000a90046001600160a01b03166001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561162e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061165291906153cd565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152336024820152604481018590526064016020604051808303816000875af11580156116a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116c991906153ea565b50600085815260036020526040902080546001909101546116f89184916001600160a01b0391821691166147cc565b6117226117058386615381565b6000878152600360205260409020546001600160a01b031661483a565b604080518381526020810183905233917f02a6a2be713fedf52f113c0a759f1c1a23a113476d9b1b1a2a453c910660de4e91015b60405180910390a25050505050565b61176d61486b565b6001600160a01b0381166117b15760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6001600160a01b0381166000818152600b60205260408082208590555184917f62b574cc62ed3db0ae736cb4349346a234832cc8b215c6423fd67505addc2ffa91a35050565b6117ff61486b565b6001600160a01b0381166118435760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6001600160a01b0381166000818152600960205260408082208590555184917f1677c34b69a09796446af7a4c75943a1bb36202c16eb82199ef7d37d0ee4b28891a35050565b61189161486b565b6001600160a01b0381166118d55760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6001600160a01b0381166000818152600760205260408082208590555184917fef97689adaec5b60041d413c3baef6876d5d01bb6c17b60cc980e2e244ef851791a35050565b60008060008060008061193d8760009081526003602052604090206007015490565b60008881526003602052604090206005810154600890910154919750955060ff169350611969876134c9565b90935091506119788888611984565b90509295509295509295565b600081815260036020818152604080842081516101408101835281546001600160a01b0390811680835260018401548216838701526002840154838601529583015460608301526004808401546080840152600584015460a0840152600684015460c0840152600784015460e0840152600884015460ff1661010084015260099093015461012083015294865260149093528185205460185492516370a0823160e01b81528886169281019290925294929391909116906370a0823190602401602060405180830381865afa158015611a61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a8591906152e0565b1115611ab25780516001600160a01b0316600090815260096020526040902054611aaf908361536e565b91505b6019546040516370a0823160e01b81526001600160a01b03868116600483015260009216906370a0823190602401602060405180830381865afa158015611afd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b2191906152e0565b1115611b3e57611b318484614302565b611b3b908361536e565b91505b61010081015160ff1615611b715761010081015160ff16600090815260136020526040902054611b6e908361536e565b91505b505b92915050565b611b8161486b565b6001600160a01b038116611bc55760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6001600160a01b0381166000818152600560205260408082208590555184917fef3cb734d88702dbb1c3bc381c52176876be95e70b66d3970d16653ee992a6c291a35050565b600081815260036020526040902060070154421015611c6c5760405162461bcd60e51b815260206004820152601360248201527f54696d656c6f636b206e6f742070617373656400000000000000000000000000604482015260640161147c565b6000818152600360205260409020600101546001600160a01b03163314611ce35760405162461bcd60e51b815260206004820152602560248201527f596f7520617265206e6f7420746865206f776e6572206f6620746869732064656044820152641c1bdcda5d60da1b606482015260840161147c565b600081815260036020526040902060020154821115611d4e5760405162461bcd60e51b815260206004820152602160248201527f43616e2774207769746864726177206d6f7265207468616e20796f75206861766044820152606560f81b606482015260840161147c565b6017546040516370a0823160e01b81523360048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015611d96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dba91906152e0565b600082815260036020526040902060090154611dd69084615394565b1115611e4a5760405162461bcd60e51b815260206004820152603760248201527f43616e2774207769746864726177206d6f726520746f6b656e73207468616e2060448201527f74686520636f6c6c61746572616c20796f752068617665000000000000000000606482015260840161147c565b6000611e563383613d97565b905082600360008481526020019081526020016000206002016000828254611e7e9190615381565b909155505060008281526003602052604081204260048201556006018054839290611eaa90849061536e565b90915550506000828152600360209081526040808320546001600160a01b031683526014808352818420546008845291842054925290611eea9082615381565b611ef49086615394565b611efe91906153ab565b90506000611f0c8286615381565b6000858152600360209081526040808320549254815163fbfa77cf60e01b815291519495506001600160a01b03938416948794869463dd62ed3e94919093169263fbfa77cf926004808401938290030181865afa158015611f71573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f9591906153cd565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152306024820152604401602060405180830381865afa158015611fdf573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061200391906152e0565b10156120a85760405162461bcd60e51b815260206004820152606260248201527f547265617375727920436f6e7472616374206e65656420746f20617070726f7660448201527f65205374616b696e6720436f6e747261637420746f207769746864726177207960648201527f6f757220746f6b656e73202d2d20706c656173652063616c6c20616e2041646d60848201526134b760f11b60a482015260c40161147c565b600085815260036020526040902080546001909101546120d69188916001600160a01b039182169116614942565b6000858152600360209081526040808320546001600160a01b039081168452600c90925280832054601754909216835282205460ff918216929116908183101561212e576121248383615407565b60ff169050612132565b5060005b6017546001600160a01b0316639dc29fac3361214f84600a615504565b60008c81526003602052604090206009015461216b908e615394565b6121759190615394565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b1580156121bb57600080fd5b505af11580156121cf573d6000803e3d6000fd5b50505050836001600160a01b03166323b872dd60008054906101000a90046001600160a01b03166001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612233573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061225791906153cd565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152336024820152604481018990526064016020604051808303816000875af11580156122aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122ce91906153ea565b50600088815260036020526040902080546001909101546122fd9188916001600160a01b0391821691166147cc565b61232761230a878b615381565b60008a8152600360205260409020546001600160a01b031661483a565b604080518781526020810187905233917ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568910160405180910390a2505050505050505050565b6000818152600360205260409020600101546001600160a01b031633146123e45760405162461bcd60e51b815260206004820152602560248201527f596f7520617265206e6f7420746865206f776e6572206f6620746869732064656044820152641c1bdcda5d60da1b606482015260840161147c565b6000818152600360205260408120600601546124003384613d97565b61240a919061536e565b90506000811161245c5760405162461bcd60e51b815260206004820152601460248201527f4e6f207265776172647320617661696c61626c65000000000000000000000000604482015260640161147c565b600082815260036020526040812060068101829055600201805483929061248490849061536e565b9091555050600082815260036020526040902042600482015580546001909101546124bd9183916001600160a01b039182169116614ab3565b6000828152600360209081526040808320546001600160a01b039081168452600c90925280832054601754909216835282205460ff91821692911690828211156125155761250b8383615407565b60ff169050612519565b5060005b6017546001600160a01b03166340c10f193361253684600a615504565b6000898152600360205260409020600901546125529089615394565b61255c9190615394565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b1580156125a257600080fd5b505af11580156125b6573d6000803e3d6000fd5b50506040518681523392507f169f1815ebdea059aac3bb00ec9a9594c7a5ffcb64a17e8392b5d84909a145569150602001611756565b60006001600160a01b0382166126325760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6001600160a01b03821660009081526004602052604090205460ff1661269a5760405162461bcd60e51b815260206004820152601460248201527f546f6b656e206e6f7420617574686f72697a6564000000000000000000000000604482015260640161147c565b6001600160a01b0382166000908152600560205260409020548410156127105760405162461bcd60e51b815260206004820152602560248201527f416d6f756e7420736d616c6c6572207468616e206d696e696d696d756d2064656044820152641c1bdcda5d60da1b606482015260840161147c565b6040516370a0823160e01b8152336004820152829085906001600160a01b038316906370a0823190602401602060405180830381865afa158015612758573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061277c91906152e0565b10156127ca5760405162461bcd60e51b815260206004820152601d60248201527f43616e2774207374616b65206d6f7265207468616e20796f75206f776e000000604482015260640161147c565b604051636eb1769f60e11b815233600482015230602482015285906001600160a01b0383169063dd62ed3e90604401602060405180830381865afa158015612816573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061283a91906152e0565b10156128885760405162461bcd60e51b815260206004820152601160248201527f416c6c6f77616e6365206e6f7420736574000000000000000000000000000000604482015260640161147c565b60038460ff1611156128dc5760405162461bcd60e51b815260206004820152601060248201527f496e76616c69642074696d656c6f636b00000000000000000000000000000000604482015260640161147c565b60006128e760015490565b9050604051806101400160405280856001600160a01b03168152602001336001600160a01b031681526020018781526020016000815260200142815260200142815260200160008152602001601660008860ff1660ff1681526020019081526020016000205442612958919061536e565b815260ff8781166020808401919091526001600160a01b038881166000908152600b8352604080822054958101959095528681526003808452858220875181546001600160a01b0319908116918616919091178255888601516001808401805490931691909616179055878701516002808301919091556060890151928201929092556080880151600482015560a0880151600582015560c0880151600682015560e0880151600782015561010088015160088201805460ff191691909716179095556101209096015160099094019390935533808452948252928220805493840181558252902001829055612a519087908690614ab3565b6001600160a01b038085166000908152600c602052604080822054601754909316825281205460ff92831692169082821115612a9b57612a918383615407565b60ff169050612a9f565b5060005b846001600160a01b03166323b872dd3360008054906101000a90046001600160a01b03166001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b00573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b2491906153cd565b6040516001600160e01b031960e085901b1681526001600160a01b03928316600482015291166024820152604481018c90526064016020604051808303816000875af1158015612b78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b9c91906153ea565b506017546001600160a01b03166340c10f1933612bba84600a615504565b6001600160a01b038b166000908152600b6020526040902054612bdd908e615394565b612be79190615394565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b158015612c2d57600080fd5b505af1158015612c41573d6000803e3d6000fd5b50505050612c53600180546001019055565b604080516001600160a01b0389168152602081018b9052339186917ff7373f56c201647feae85a62d3cf56286ed3a43d20c5eb7f9883d6ea690ef7c0910160405180910390a35091979650505050505050565b6000818152600360205260409020600101546001600160a01b03163314612d1d5760405162461bcd60e51b815260206004820152602560248201527f596f7520617265206e6f7420746865206f776e6572206f6620746869732064656044820152641c1bdcda5d60da1b606482015260840161147c565b600081815260036020526040902060020154821115612d885760405162461bcd60e51b815260206004820152602160248201527f43616e2774207769746864726177206d6f7265207468616e20796f75206861766044820152606560f81b606482015260840161147c565b6017546040516370a0823160e01b81523360048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015612dd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612df491906152e0565b600082815260036020526040902060090154612e109084615394565b1115612e845760405162461bcd60e51b815260206004820152603760248201527f43616e2774207769746864726177206d6f726520746f6b656e73207468616e2060448201527f74686520636f6c6c61746572616c20796f752068617665000000000000000000606482015260840161147c565b6000818152600360205260409020600701544210612ee45760405162461bcd60e51b815260206004820152601360248201527f54696d656c6f636b206861732070617373656400000000000000000000000000604482015260640161147c565b600081815260036020526040812060070154612f01904290615381565b600083815260036020526040812060058101546007909101549293509091612f299190615381565b90506000612f38826064615394565b6000858152600360209081526040808320546001600160a01b0316835260129091529020548490612f699088615394565b612f739190615394565b612f7d91906153ab565b905084811115612f8a5750835b80600003612fac576064612f9f866001615394565b612fa991906153ab565b90505b6000848152600360209081526040808320546001600160a01b031683526008909152812054612fdb908361536e565b90506000612fe98288615381565b90506000612ff78289615381565b90508760036000898152602001908152602001600020600201600082825461301f9190615381565b909155505060008781526003602090815260408083204260048083019190915590549354825163fbfa77cf60e01b815292516001600160a01b03958616958895879563dd62ed3e95929094169363fbfa77cf938184019390918290030181865afa158015613091573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130b591906153cd565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152306024820152604401602060405180830381865afa1580156130ff573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061312391906152e0565b10156131c85760405162461bcd60e51b815260206004820152606260248201527f547265617375727920436f6e7472616374206e65656420746f20617070726f7660448201527f65205374616b696e6720436f6e747261637420746f207769746864726177207960648201527f6f757220746f6b656e73202d2d20706c656173652063616c6c20616e2041646d60848201526134b760f11b60a482015260c40161147c565b600088815260036020526040902080546001909101546131f6918b916001600160a01b039182169116614942565b6017546001600160a01b039081166000908152600c60208181526040808420548d855260038352818520549095168452919052812054909160ff90811691161015613289576000898152600360209081526040808320546001600160a01b039081168452600c9092528083205460175490921683529091205461327f9160ff9081169116615407565b60ff16905061328d565b5060005b6017546001600160a01b0316639dc29fac336132aa84600a615504565b60008d8152600360205260409020600901546132c6908f615394565b6132d09190615394565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b15801561331657600080fd5b505af115801561332a573d6000803e3d6000fd5b50505050816001600160a01b03166323b872dd60008054906101000a90046001600160a01b03166001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561338e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133b291906153cd565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152336024820152604481018790526064016020604051808303816000875af1158015613405573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061342991906153ea565b50600089815260036020526040902080546001909101546134589186916001600160a01b0391821691166147cc565b613482613465858c615381565b60008b8152600360205260409020546001600160a01b031661483a565b604080518581526020810185905233917ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568910160405180910390a250505050505050505050565b600081815260036020526040812060028101546006909101549091906134ef3385613d97565b6134f9919061536e565b9050915091565b61350861486b565b60009182526013602052604090912055565b61352261486b565b6001600160a01b0381166135785760405162461bcd60e51b815260206004820152601e60248201527f466f756e6465727320616464726573732063616e6e6f74206265203078300000604482015260640161147c565b601880546001600160a01b0319166001600160a01b0383169081179091556040517f23008753c65029d55e051a14341d50cf19b808653ba432a5faeb07bd7865e25b90600090a250565b6135ca61486b565b600080546001600160a01b0319166001600160a01b0383169081179091556040519081527f2f658b440c35314f52658ea8a740e05b284cdc84dc9ae01e891f21b8933e7cad9060200160405180910390a150565b61362661486b565b6001600160a01b03821661366a5760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6136748282614b17565b5050565b6136828282611c0b565b61367481611409565b6000806136978361435f565b50905060005b60058110156136df578181815181106136b8576136b861533f565b6020026020010151836136cb919061536e565b9250806136d781615355565b91505061369d565b5050919050565b6136ee61486b565b6001600160a01b0388166137445760405162461bcd60e51b815260206004820152601b60248201527f546f6b656e20616464726573732063616e6e6f74206265203078300000000000604482015260640161147c565b600087116137a45760405162461bcd60e51b815260206004820152602760248201527f526577617264732070657220686f7572206d75737420626520677265617465726044820152660207468616e20360cc1b606482015260840161147c565b600086116138065760405162461bcd60e51b815260206004820152602960248201527f436f6d706f756e64206672657175656e6379206d75737420626520677265617460448201526806572207468616e20360bc1b606482015260840161147c565b600085116138645760405162461bcd60e51b815260206004820152602560248201527f5769746864726177616c20666565206d75737420626520677265617465722074604482015264068616e20360dc1b606482015260840161147c565b600084116138c95760405162461bcd60e51b815260206004820152602c60248201527f466f756e646572732072657761726420626f6f7374206d75737420626520677260448201526b06561746572207468616e20360a41b606482015260840161147c565b6000831161392a5760405162461bcd60e51b815260206004820152602860248201527f6b4e46542072657761726420626f6f7374206d75737420626520677265617465604482015267072207468616e20360c41b606482015260840161147c565b6000821161397a5760405162461bcd60e51b815260206004820152601c60248201527f526174696f206d7573742062652067726561746572207468616e203000000000604482015260640161147c565b600081116139d65760405162461bcd60e51b8152602060048201526024808201527f4d696e696d756d207374616b65206d75737420626520677265617465722074686044820152630616e20360e41b606482015260840161147c565b6000886001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613a16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a3a91906152e0565b11613a995760405162461bcd60e51b815260206004820152602960248201527f546f6b656e20746f74616c20737570706c79206d75737420626520677265617460448201526806572207468616e20360bc1b606482015260840161147c565b613aa5612710896141de565b613aaf84896117f7565b613ab98389613c4a565b613ac38789611889565b613acd8289611765565b613ad78589614016565b613ae18689614270565b613aeb8189611b79565b613b56886001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015613b2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b509190615510565b89614755565b613b61886001614b17565b5050505050505050565b613b7361486b565b6001600160a01b038216613bb75760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6064811115613c2e5760405162461bcd60e51b815260206004820152602c60248201527f50656e616c74792070657263656e74616765206d75737420626520626574776560448201527f656e203020616e64203130300000000000000000000000000000000000000000606482015260840161147c565b6001600160a01b03909116600090815260126020526040902055565b613c5261486b565b6001600160a01b038116613c965760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6001600160a01b0381166000818152600a60205260408082208590555184917f11ef1060a695a1277b08edcbb2c364d43d4eb52f1060daaabf0df445cb6cdfdf91a35050565b6000818152600360209081526040808320600481015490546001600160a01b031684526006909252822054613d11818361536e565b4210613d21575060009392505050565b42613d2c828461536e565b613d369190615381565b949350505050565b613d4661486b565b600091825260156020526040909120805460ff1916911515919091179055565b60026020528160005260406000208181548110613d8257600080fd5b90600052602060002001600091509150505481565b600081815260036020818152604080842081516101408101835281546001600160a01b0390811682526001830154811694820185905260028301549382019390935293810154606085015260048101546080850152600581015460a0850152600681015460c0850152600781015460e0850152600881015460ff1661010085015260090154610120840152851614613e33576000915050611b73565b6000816080015142613e459190615381565b60408084015184516001600160a01b03166000908152600760205291822054929350919063bbf81e00613e788385615394565b613e8a90670de0b6b3a7640000615394565b613e9491906153ab565b90506000670de0b6b3a7640000613eab8387615394565b613eb591906153ab565b90506000613ec38a8a611984565b87516001600160a01b0316600090815260146020526040902054909150613eea8284615394565b613ef491906153ab565b9a9950505050505050505050565b613f0a61486b565b6001600160a01b038116613f605760405162461bcd60e51b815260206004820152601a60248201527f6b4e465420616464726573732063616e6e6f7420626520307830000000000000604482015260640161147c565b601980546001600160a01b0319166001600160a01b0383169081179091556040517fc8e08c5b2fa487609cdc92d5cfcc240f3c8fc73ac5e58fafc5d465d20aaaf31290600090a250565b6001600160a01b03811660009081526002602090815260409182902080548351818402810184019094528084526060939283018282801561400a57602002820191906000526020600020905b815481526020019060010190808311613ff6575b50505050509050919050565b61401e61486b565b6001600160a01b0381166140625760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6001600160a01b0381166000908152601460205260409020548211156140f05760405162461bcd60e51b815260206004820152602760248201527f5769746864726177616c206665652063616e6e6f74206265206d6f726520746860448201527f616e203130302500000000000000000000000000000000000000000000000000606482015260840161147c565b6001600160a01b0381166000818152600860205260408082208590555184917f5d5169bb1fbf418e612b1934f181b6ce300a1aad27fdb0e6f6aadbd96f50bb8f91a35050565b61413e61486b565b6001600160a01b0381166141945760405162461bcd60e51b815260206004820152601b60248201527f48656c697820616464726573732063616e6e6f74206265203078300000000000604482015260640161147c565b601780546001600160a01b0319166001600160a01b0383169081179091556040517fdcbeffeaf77a19486e34d4b5fc3809913d1e7125a43b8dcdb17944ab2c17579090600090a250565b6141e661486b565b6001600160a01b03811661422a5760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6001600160a01b0381166000818152601460205260408082208590555184917f6a437d814668577dce2f82ae56ed67161e12e20b59b9464687859d6a2ce0faa591a35050565b61427861486b565b6001600160a01b0381166142bc5760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6001600160a01b0381166000818152600660205260408082208590555184917fd0d3d840363c3a773f4578f92d7914f6b37985570c79ee2889d69d7d8f12c29591a35050565b60008061430f848461102d565b50905060005b6005811015614357578181815181106143305761433061533f565b602002602001015183614343919061536e565b92508061434f81615355565b915050614315565b505092915050565b6019546040516370a0823160e01b81526001600160a01b0383811660048301526060928392600092909116906370a0823190602401602060405180830381865afa1580156143b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143d591906152e0565b60408051600580825260c082019092529192506020820160a080368337505060408051600580825260c0820190925292955090506020820160a08036833701905050915060005b818110156146a657601954604051632f745c5960e01b81526001600160a01b038781166004830152602482018490526000921690632f745c5990604401602060405180830381865afa158015614476573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061449a91906152e0565b60195460405163032bbfbd60e21b815260048101839052600060248201819052600160448301529293506001600160a01b0390911690630caefef490606401602060405180830381865afa1580156144f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061451a91906152e0565b60008181526015602052604090205490915060ff1661453a575050614694565b60195460405163032bbfbd60e21b81526004810184905260016024820152600260448201526000916001600160a01b031690630caefef490606401602060405180830381865afa158015614592573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145b691906152e0565b6145c190606461530f565b905060008112156145d0575060005b60005b600581101561468f578781815181106145ee576145ee61533f565b602002602001015182111561467d5760008882815181106146115761461161533f565b602002602001015190508289838151811061462e5761462e61533f565b60200260200101818152505080925060008883815181106146515761465161533f565b602002602001015190508589848151811061466e5761466e61533f565b60209081029190910101529450505b8061468781615355565b9150506145d3565b505050505b8061469e81615355565b91505061441c565b5050915091565b6146b561486b565b6001600160a01b03811661470b5760405162461bcd60e51b815260206004820152601e60248201527f547265617375727920616464726573732063616e6e6f74206265203078300000604482015260640161147c565b601a80546001600160a01b0319166001600160a01b0383169081179091556040517fafa147634b29e2c7bd53ce194256b9f41cfb9ba3036f2b822fdd1d965beea08690600090a250565b61475d61486b565b6001600160a01b0381166147a15760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6001600160a01b03166000908152600c60205260409020805460ff191660ff92909216919091179055565b6001600160a01b0382166000908152600f6020526040812080548592906147f490849061536e565b90915550506001600160a01b0380831660009081526010602090815260408083209385168352929052908120805485929061483090849061536e565b9091555050505050565b6001600160a01b0381166000908152601160205260408120805484929061486290849061536e565b90915550505050565b60008054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b8152600401602060405180830381865afa1580156148bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148e091906153cd565b6001600160a01b0316336001600160a01b0316146149405760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a45440000000000000000000000000000000000000000604482015260640161147c565b565b6001600160a01b0382166000908152600d60205260409020548311156149d05760405162461bcd60e51b815260206004820152602560248201527f5374616b696e673a204e6f7420656e6f756768207374616b65642028436f6e7460448201527f7261637429000000000000000000000000000000000000000000000000000000606482015260840161147c565b6001600160a01b038083166000908152600e6020908152604080832093851683529290522054831115614a4f5760405162461bcd60e51b815260206004820152602160248201527f5374616b696e673a204e6f7420656e6f756768207374616b65642028557365726044820152602960f81b606482015260840161147c565b6001600160a01b0382166000908152600d602052604081208054859290614a77908490615381565b90915550506001600160a01b038083166000908152600e6020908152604080832093851683529290529081208054859290614830908490615381565b6001600160a01b0382166000908152600d602052604081208054859290614adb90849061536e565b90915550506001600160a01b038083166000908152600e602090815260408083209385168352929052908120805485929061483090849061536e565b6001600160a01b038216614b6d5760405162461bcd60e51b815260206004820152601b60248201527f546f6b656e20616464726573732063616e6e6f74206265203078300000000000604482015260640161147c565b801515600103614fc4576001600160a01b038216600090815260076020526040902054614bec5760405162461bcd60e51b815260206004820152602760248201527f526577617264732070657220686f7572206d75737420626520677265617465726044820152660207468616e20360cc1b606482015260840161147c565b6001600160a01b038216600090815260066020526040902054614c635760405162461bcd60e51b815260206004820152602960248201527f436f6d706f756e64206672657175656e6379206d75737420626520677265617460448201526806572207468616e20360bc1b606482015260840161147c565b6001600160a01b038216600090815260086020526040902054614cd65760405162461bcd60e51b815260206004820152602560248201527f5769746864726177616c20666565206d75737420626520677265617465722074604482015264068616e20360dc1b606482015260840161147c565b6001600160a01b038216600090815260096020526040902054614d505760405162461bcd60e51b815260206004820152602c60248201527f466f756e646572732072657761726420626f6f7374206d75737420626520677260448201526b06561746572207468616e20360a41b606482015260840161147c565b6001600160a01b0382166000908152600a6020526040902054614dc65760405162461bcd60e51b815260206004820152602860248201527f6b4e46542072657761726420626f6f7374206d75737420626520677265617465604482015267072207468616e20360c41b606482015260840161147c565b6001600160a01b0382166000908152600b6020526040902054614e2b5760405162461bcd60e51b815260206004820152601c60248201527f526174696f206d7573742062652067726561746572207468616e203000000000604482015260640161147c565b6001600160a01b038216600090815260056020526040902054614e9c5760405162461bcd60e51b8152602060048201526024808201527f4d696e696d756d207374616b65206d75737420626520677265617465722074686044820152630616e20360e41b606482015260840161147c565b6001600160a01b038216600090815260146020526040902054614f015760405162461bcd60e51b815260206004820152601e60248201527f44697669736f72206d7573742062652067726561746572207468616e20300000604482015260640161147c565b6000826001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614f41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614f6591906152e0565b11614fc45760405162461bcd60e51b815260206004820152602960248201527f546f6b656e20746f74616c20737570706c79206d75737420626520677265617460448201526806572207468616e20360bc1b606482015260840161147c565b6001600160a01b038216600081815260046020526040808220805460ff191685151590811790915590519092917f59261974a183535ca20bb33ae77db42c679a079844739a2e10f0b6ecb847379a91a35050565b6001600160a01b038116811461502d57600080fd5b50565b6000806040838503121561504357600080fd5b823561504e81615018565b946020939093013593505050565b600081518084526020808501945080840160005b8381101561508c57815187529582019590820190600101615070565b509495945050505050565b6040815260006150aa604083018561505c565b82810360208401526150bc818561505c565b95945050505050565b6000602082840312156150d757600080fd5b81356150e281615018565b9392505050565b6000602082840312156150fb57600080fd5b5035919050565b6000806040838503121561511557600080fd5b82359150602083013561512781615018565b809150509250929050565b6000806040838503121561514557600080fd5b50508035926020909101359150565b60ff8116811461502d57600080fd5b60008060006060848603121561517857600080fd5b83359250602084013561518a81615154565b9150604084013561519a81615018565b809150509250925092565b600080604083850312156151b857600080fd5b82356151c381615018565b9150602083013561512781615018565b801515811461502d57600080fd5b600080604083850312156151f457600080fd5b82356151ff81615018565b91506020830135615127816151d3565b600080600080600080600080610100898b03121561522c57600080fd5b883561523781615018565b9a60208a01359a5060408a013599606081013599506080810135985060a0810135975060c0810135965060e00135945092505050565b6000806040838503121561528057600080fd5b823591506020830135615127816151d3565b6020815260006150e2602083018461505c565b600080604083850312156152b857600080fd5b82356151c381615154565b6000602082840312156152d557600080fd5b81356150e281615154565b6000602082840312156152f257600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b80820260008212600160ff1b8414161561532b5761532b6152f9565b8181058314821517611b7357611b736152f9565b634e487b7160e01b600052603260045260246000fd5b600060018201615367576153676152f9565b5060010190565b80820180821115611b7357611b736152f9565b81810381811115611b7357611b736152f9565b8082028115828204841417611b7357611b736152f9565b6000826153c857634e487b7160e01b600052601260045260246000fd5b500490565b6000602082840312156153df57600080fd5b81516150e281615018565b6000602082840312156153fc57600080fd5b81516150e2816151d3565b60ff8281168282160390811115611b7357611b736152f9565b600181815b8085111561545b578160001904821115615441576154416152f9565b8085161561544e57918102915b93841c9390800290615425565b509250929050565b60008261547257506001611b73565b8161547f57506000611b73565b8160018114615495576002811461549f576154bb565b6001915050611b73565b60ff8411156154b0576154b06152f9565b50506001821b611b73565b5060208310610133831016604e8410600b84101617156154de575081810a611b73565b6154e88383615420565b80600019048211156154fc576154fc6152f9565b029392505050565b60006150e28383615463565b60006020828403121561552257600080fd5b81516150e28161515456fe546f6b656e2061646472657373206973206e6f74207365740000000000000000a164736f6c6343000811000a

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

0000000000000000000000006a005c11217863c4e300ce009c5ddc7e1672150a0000000000000000000000007ca5af5ba3472af6049f63c1abc324475d44efc1000000000000000000000000ad2e62e90c63d5c2b905c3f709cc3045aecdaa1e0000000000000000000000000fd5576c2842bd62dd00c5256491d11ccad84306000000000000000000000000ea6ab2871d5b3bbe6ded740c812d85700bae33c000000000000000000000000069a4a1cd8f2f2c3500f64634b9d69c642e9a5ca4

-----Decoded View---------------
Arg [0] : _authority (address): 0x6A005c11217863c4e300Ce009c5Ddc7e1672150A
Arg [1] : _konduxERC20 (address): 0x7CA5af5bA3472AF6049F63c1AbC324475D44EFC1
Arg [2] : _treasury (address): 0xaD2E62E90C63D5c2b905C3F709cC3045AecDAa1E
Arg [3] : _konduxERC721Founders (address): 0x0fD5576c2842bD62dd00C5256491D11CcAD84306
Arg [4] : _konduxERC721kNFT (address): 0xeA6aB2871d5B3bbe6Ded740C812D85700Bae33c0
Arg [5] : _helixERC20 (address): 0x69a4A1CD8F2f2c3500F64634B9d69C642e9A5CA4

-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 0000000000000000000000006a005c11217863c4e300ce009c5ddc7e1672150a
Arg [1] : 0000000000000000000000007ca5af5ba3472af6049f63c1abc324475d44efc1
Arg [2] : 000000000000000000000000ad2e62e90c63d5c2b905c3f709cc3045aecdaa1e
Arg [3] : 0000000000000000000000000fd5576c2842bd62dd00c5256491d11ccad84306
Arg [4] : 000000000000000000000000ea6ab2871d5b3bbe6ded740c812d85700bae33c0
Arg [5] : 00000000000000000000000069a4a1cd8f2f2c3500f64634b9d69c642e9a5ca4


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

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