ETH Price: $3,004.71 (+4.30%)
Gas: 1 Gwei

Contract

0x8913476dA83de04b9a2Ea930d5C283035Dd5D769
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
Withdraw Stake201040892024-06-16 11:35:1119 days ago1718537711IN
0x8913476d...35Dd5D769
0 ETH0.000089783.37986283
Withdraw Stake200999232024-06-15 21:38:1120 days ago1718487491IN
0x8913476d...35Dd5D769
0 ETH0.000095453.59347651
Withdraw Stake200943562024-06-15 2:54:4721 days ago1718420087IN
0x8913476d...35Dd5D769
0 ETH0.000087693.30118508
Withdraw Stake200927252024-06-14 21:26:4721 days ago1718400407IN
0x8913476d...35Dd5D769
0 ETH0.0002659710.01249882
Withdraw Stake200904192024-06-14 13:43:2321 days ago1718372603IN
0x8913476d...35Dd5D769
0 ETH0.000237518.9410789
Withdraw Stake200903902024-06-14 13:37:3521 days ago1718372255IN
0x8913476d...35Dd5D769
0 ETH0.00023128.70361524
Withdraw Stake197864592024-05-03 1:58:1164 days ago1714701491IN
0x8913476d...35Dd5D769
0 ETH0.000152895.76108852
Withdraw Stake197863972024-05-03 1:45:4764 days ago1714700747IN
0x8913476d...35Dd5D769
0 ETH0.000144645.45765738
Withdraw Stake195406152024-03-29 15:42:1198 days ago1711726931IN
0x8913476d...35Dd5D769
0 ETH0.0059419842.2748268
Withdraw Stake195031872024-03-24 8:21:23103 days ago1711268483IN
0x8913476d...35Dd5D769
0 ETH0.0019200415.55245265
Withdraw Stake195031692024-03-24 8:17:35103 days ago1711268255IN
0x8913476d...35Dd5D769
0 ETH0.0023285916.56704903
Withdraw Stake194810282024-03-21 5:41:47107 days ago1710999707IN
0x8913476d...35Dd5D769
0 ETH0.003286623.38488304
Withdraw Stake194780692024-03-20 19:44:23107 days ago1710963863IN
0x8913476d...35Dd5D769
0 ETH0.0047184933.57023803
Withdraw Stake194290982024-03-13 22:27:11114 days ago1710368831IN
0x8913476d...35Dd5D769
0 ETH0.0057747952.94093869
Withdraw Stake190918962024-01-26 16:13:23161 days ago1706285603IN
0x8913476d...35Dd5D769
0 ETH0.0029842521.24082334
Withdraw Stake187774852023-12-13 13:15:59205 days ago1702473359IN
0x8913476d...35Dd5D769
0 ETH0.0062067356.90075798
Withdraw Stake181880352023-09-22 1:10:47288 days ago1695345047IN
0x8913476d...35Dd5D769
0 ETH0.000859897.88230076
Withdraw Stake181506852023-09-16 19:11:35293 days ago1694891495IN
0x8913476d...35Dd5D769
0 ETH0.0014669313.44970892
Withdraw Stake180985352023-09-09 11:28:23300 days ago1694258903IN
0x8913476d...35Dd5D769
0 ETH0.0016186612.83064526
Withdraw Stake179842282023-08-24 11:20:47316 days ago1692876047IN
0x8913476d...35Dd5D769
0 ETH0.002566120.34073693
Withdraw Stake179773992023-08-23 12:26:35317 days ago1692793595IN
0x8913476d...35Dd5D769
0 ETH0.0022109917.52251574
Withdraw Stake179337402023-08-17 9:47:47323 days ago1692265667IN
0x8913476d...35Dd5D769
0 ETH0.0020099315.92759379
Withdraw Stake178152392023-07-31 19:59:59340 days ago1690833599IN
0x8913476d...35Dd5D769
0 ETH0.0052417641.54987896
Withdraw Stake178088252023-07-30 22:29:23341 days ago1690756163IN
0x8913476d...35Dd5D769
0 ETH0.0021636517.14737237
Withdraw Stake177886412023-07-28 2:41:59344 days ago1690512119IN
0x8913476d...35Dd5D769
0 ETH0.002919123.13441305
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:
KatanaInuStakingContract

Compiler Version
v0.8.0+commit.c7dfd78e

Optimization Enabled:
No with 200 runs

Other Settings:
default evmVersion
File 1 of 8 : KatanaInuStakingContract.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "./Ownable.sol";

/**
 * @notice
 * A stake struct is used to represent the way we store stakes,
 * A Stake will contain the users address, the duration (0 for imediate withdrawal or 1 / 2 / 3 years), the amount staked and a timestamp,
 * Since which is when the stake was made
 * _stakeCheckPointIndex: The index in the checkpoints array of the current stake
 */
struct Stake {
    uint256 _amount;
    uint256 _since;
    IERC20 _stakingToken;
    uint256 _stakaAmount;
    uint256 _estimatedReward;
    APY _estimatedAPY;
    uint256 _rewardStartDate; //This date will change as the amount staked increases
    bool _exists;
}

/***@notice Struct to store Staking Contract Parameters */
struct StakingContractParameters {
    uint256 _minimumStake;
    uint256 _maxSupply;
    uint256 _totalReward;
    IERC20 _stakingToken;
    uint256 _stakingDuration;
    uint256 _maximumStake;
    //staking starting parameters
    uint256 _minimumNumberStakeHoldersBeforeStart;
    uint256 _minimumTotalStakeBeforeStart;
    uint256 _startDate;
    uint256 _endDate;
    //vesting parameters
    Percentage _immediateRewardPercentage;
    uint256 _cliffDuration;
    Percentage _cliffRewardPercentage;
    uint256 _linearDuration;
}

struct Percentage {
    uint256 _percentage;
    uint256 _percentageBase;
}

struct StakingContractParametersUpdate {
    uint256 _minimumStake;
    uint256 _maxSupply;
    uint256 _totalReward;
    IERC20 _stakingToken;
    uint256 _stakingDuration;
    uint256 _maximumStake;
    uint256 _minimumNumberStakeHoldersBeforeStart;
    uint256 _minimumTotalStakeBeforeStart;
    Percentage _immediateRewardPercentage;
    uint256 _cliffDuration;
    Percentage _cliffRewardPercentage;
    uint256 _linearDuration;
}

struct APY {
    uint256 _apy;
    uint256 _base;
}

/**
 * @dev Implementation of the {IERC20} interface.
 *
 */
contract KatanaInuStakingContract is
    ERC20("STAKA Token", "STAKA"),
    Ownable,
    Pausable
{
    using SafeMath for uint256;

    ///////////// Events ///////////////////
    /**
     * @dev Emitted when a user stakes tokens
     */
    event Staked(
        address indexed stakeholder,
        uint256 amountStaked,
        IERC20 stakingToken,
        uint256 xKataAmount
    );

    /**
     * @dev Emitted when a user withdraw stake
     */
    event Withdrawn(
        address indexed stakeholder,
        uint256 amountStaked,
        uint256 amountReceived,
        IERC20 stakingToken
    );

    /**
     * @dev Emitted when a user withdraw stake
     */
    event EmergencyWithdraw(
        address indexed stakeholder,
        uint256 amountSKataBurned,
        uint256 amountReceived
    );

    ///////////////////////////////////////

    ///// Fields //////////
    /*** @notice Stakes by stakeholder address */
    mapping(address => Stake) public _stakeholdersMapping;
    uint256 _currentNumberOfStakeholders;

    /*** @notice Staking contract parameters */
    StakingContractParameters private _stakingParameters;

    /***@notice Total Kata Staked */
    uint256 private _totalKataStaked;

    /***@notice Total Kata rewards claimed */
    uint256 private _totalKataRewardsClaimed;

    bool private _stakingStarted;

    ////////////////////////////////////////

    constructor(address stakingTokenAddress) {
        _stakingParameters._stakingToken = IERC20(stakingTokenAddress);
        _stakingParameters._minimumNumberStakeHoldersBeforeStart = 1;
    }

    /***@notice Update Staking Parameters: _startDate can't be updated, it is automatically set when the first stake is created */
    function updateStakingParameters(
        StakingContractParametersUpdate calldata stakingParameters
    ) external onlyOwner {
        _stakingParameters._minimumStake = stakingParameters._minimumStake;
        _stakingParameters._maxSupply = stakingParameters._maxSupply;
        _stakingParameters._totalReward = stakingParameters._totalReward;
        _stakingParameters._stakingToken = IERC20(
            stakingParameters._stakingToken
        );
        _stakingParameters._stakingDuration = stakingParameters
            ._stakingDuration;
        if (_stakingStarted) {
            _stakingParameters._endDate =
                _stakingParameters._startDate +
                _stakingParameters._stakingDuration;
        }
        if (!_stakingStarted) {
            // No need to update these paraeter if the staking has already started
            _stakingParameters
                ._minimumNumberStakeHoldersBeforeStart = stakingParameters
                ._minimumNumberStakeHoldersBeforeStart;
            _stakingParameters._minimumTotalStakeBeforeStart = stakingParameters
                ._minimumTotalStakeBeforeStart;
            if (
                (_stakingParameters._minimumTotalStakeBeforeStart == 0 ||
                    _totalKataStaked >=
                    _stakingParameters._minimumTotalStakeBeforeStart) &&
                (_stakingParameters._minimumNumberStakeHoldersBeforeStart ==
                    0 ||
                    _currentNumberOfStakeholders >=
                    _stakingParameters._minimumNumberStakeHoldersBeforeStart)
            ) {
                _stakingStarted = true;
                _stakingParameters._startDate = block.timestamp;
                _stakingParameters._endDate =
                    _stakingParameters._startDate +
                    _stakingParameters._stakingDuration;
            }
        }
        _stakingParameters._maximumStake = stakingParameters._maximumStake;

        //Update reward schedule array
        _stakingParameters._immediateRewardPercentage = stakingParameters
            ._immediateRewardPercentage;
        _stakingParameters._cliffDuration = stakingParameters._cliffDuration;
        _stakingParameters._cliffRewardPercentage = stakingParameters
            ._cliffRewardPercentage;
        _stakingParameters._linearDuration = stakingParameters._linearDuration;
    }

    /***@notice Stake Kata coins in exchange for xKata coins to earn a share of the rewards */
    function stake(uint256 amount) external onlyUser whenNotPaused {
        //Check the amount is >= _minimumStake
        require(
            amount >= _stakingParameters._minimumStake,
            "Amount below the minimum stake"
        );
        //Check the amount is <= _maximumStake
        require(
            _stakingParameters._maximumStake == 0 ||
                amount <= _stakingParameters._maximumStake,
            "amount exceeds maximum stake"
        );
        //Check if the new stake will exceed the maximum supply for this pool
        require(
            (_totalKataStaked + amount) <= _stakingParameters._maxSupply,
            "You can not exceeed maximum supply for staking"
        );

        require(
            !_stakingStarted || block.timestamp < _stakingParameters._endDate,
            "The staking period has ended"
        );
        //Check if the totalReward have been already claimed, in theory this should always be true,
        //but added the extra check for additional safety
        require(
            _totalKataRewardsClaimed < _stakingParameters._totalReward,
            "All rewards have been distributed"
        );

        Stake memory newStake = createStake(amount);
        _totalKataStaked += amount;
        if (!_stakeholdersMapping[msg.sender]._exists) {
            _currentNumberOfStakeholders += 1;
        }
        //Check if the staking period did not end
        if (
            !_stakingStarted &&
            (_stakingParameters._minimumTotalStakeBeforeStart == 0 ||
                _totalKataStaked >=
                _stakingParameters._minimumTotalStakeBeforeStart) &&
            (_stakingParameters._minimumNumberStakeHoldersBeforeStart == 0 ||
                _currentNumberOfStakeholders >=
                _stakingParameters._minimumNumberStakeHoldersBeforeStart)
        ) {
            _stakingStarted = true;
            _stakingParameters._startDate = block.timestamp;
            _stakingParameters._endDate =
                _stakingParameters._startDate +
                _stakingParameters._stakingDuration;
        }
        //Transfer amount to contract (this)
        if (
            !_stakingParameters._stakingToken.transferFrom(
                msg.sender,
                address(this),
                amount
            )
        ) {
            revert("couldn 't transfer tokens from sender to contract");
        }

        _mint(msg.sender, newStake._stakaAmount);

        //Update stakeholders

        if (!_stakeholdersMapping[msg.sender]._exists) {
            _stakeholdersMapping[msg.sender] = newStake;
            _stakeholdersMapping[msg.sender]._exists = true;
        } else {
            _stakeholdersMapping[msg.sender]
                ._rewardStartDate = calculateNewRewardStartDate(
                _stakeholdersMapping[msg.sender],
                newStake
            );
            _stakeholdersMapping[msg.sender]._amount += newStake._amount;
            _stakeholdersMapping[msg.sender]._stakaAmount += newStake
                ._stakaAmount;
        }
        //Emit event
        emit Staked(
            msg.sender,
            amount,
            _stakingParameters._stakingToken,
            newStake._stakaAmount
        );
    }

    function calculateNewRewardStartDate(
        Stake memory existingStake,
        Stake memory newStake
    ) private pure returns (uint256) {
        uint256 multiplier = (
            existingStake._rewardStartDate.mul(existingStake._stakaAmount)
        ).add(newStake._rewardStartDate.mul(newStake._stakaAmount));
        uint256 divider = existingStake._stakaAmount.add(newStake._stakaAmount);
        return multiplier.div(divider);
    }

    /*** @notice Withdraw stake and get initial amount staked + share of the reward */
    function withdrawStake(uint256 amount) external onlyUser whenNotPaused {
        require(
            _stakeholdersMapping[msg.sender]._exists,
            "Can not find stake for sender"
        );
        require(
            _stakeholdersMapping[msg.sender]._amount >= amount,
            "Can not withdraw more than actual stake"
        );
        Stake memory stakeToWithdraw = _stakeholdersMapping[msg.sender];
        require(stakeToWithdraw._amount > 0, "Stake alreday withdrawn");
        //Reward proportional to amount withdrawn
        uint256 reward = (
            computeRewardForStake(block.timestamp, stakeToWithdraw, true).mul(
                amount
            )
        ).div(stakeToWithdraw._amount);
        //Check if there is enough reward tokens, this is to avoid paying rewards with other stakeholders stake
        uint256 currentRewardBalance = getRewardBalance();
        require(
            reward <= currentRewardBalance,
            "The contract does not have enough reward tokens"
        );
        uint256 totalAmoutToWithdraw = reward + amount;
        //Calculate nb STAKA to burn:
        uint256 nbStakaToBurn = (stakeToWithdraw._stakaAmount.mul(amount)).div(
            stakeToWithdraw._amount
        );

        _stakeholdersMapping[msg.sender]._amount -= amount;
        _stakeholdersMapping[msg.sender]._stakaAmount -= nbStakaToBurn;

        _totalKataStaked = _totalKataStaked - amount;
        _totalKataRewardsClaimed += reward;
        //Transfer amount to contract (this)
        if (
            !stakeToWithdraw._stakingToken.transfer(
                msg.sender,
                totalAmoutToWithdraw
            )
        ) {
            revert("couldn 't transfer tokens from sender to contract");
        }
        _burn(msg.sender, nbStakaToBurn);
        emit Withdrawn(
            msg.sender,
            stakeToWithdraw._amount,
            totalAmoutToWithdraw,
            stakeToWithdraw._stakingToken
        );
    }

    /***@notice withdraw all stakes of a given user without including rewards */
    function emergencyWithdraw(address stakeHolderAddress) external onlyOwner {
        require(
            _stakeholdersMapping[stakeHolderAddress]._exists,
            "Can not find stake for sender"
        );
        require(
            _stakeholdersMapping[stakeHolderAddress]._amount > 0,
            "Can not any stake for supplied address"
        );

        uint256 totalAmoutTowithdraw;
        uint256 totalSKataToBurn;
        totalAmoutTowithdraw = _stakeholdersMapping[stakeHolderAddress]._amount;
        totalSKataToBurn = _stakeholdersMapping[stakeHolderAddress]
            ._stakaAmount;
        if (
            !_stakeholdersMapping[stakeHolderAddress]._stakingToken.transfer(
                stakeHolderAddress,
                _stakeholdersMapping[stakeHolderAddress]._amount
            )
        ) {
            revert("couldn 't transfer tokens from sender to contract");
        }
        _stakeholdersMapping[stakeHolderAddress]._amount = 0;
        _stakeholdersMapping[stakeHolderAddress]._exists = false;
        _stakeholdersMapping[stakeHolderAddress]._stakaAmount = 0;

        _totalKataStaked = _totalKataStaked - totalAmoutTowithdraw;
        _burn(stakeHolderAddress, totalSKataToBurn);
        emit EmergencyWithdraw(
            stakeHolderAddress,
            totalSKataToBurn,
            totalAmoutTowithdraw
        );
    }

    /***@notice Get an estimate of the reward  */
    function getStakeReward(uint256 targetTime)
        external
        view
        onlyUser
        returns (uint256)
    {
        require(
            _stakeholdersMapping[msg.sender]._exists,
            "Can not find stake for sender"
        );
        Stake memory targetStake = _stakeholdersMapping[msg.sender];
        return computeRewardForStake(targetTime, targetStake, true);
    }

    /***@notice Get an estimate of the reward  */
    function getEstimationOfReward(uint256 targetTime, uint256 amountToStake)
        external
        view
        returns (uint256)
    {
        Stake memory targetStake = createStake(amountToStake);
        return computeRewardForStake(targetTime, targetStake, false);
    }

    function getAPY() external view returns (APY memory) {
        if (
            !_stakingStarted ||
            _stakingParameters._endDate == _stakingParameters._startDate ||
            _totalKataStaked == 0
        ) return APY(0, 1);

        uint256 targetTime = 365 days;
        if (
            _stakingParameters._immediateRewardPercentage._percentage == 0 &&
            _stakingParameters._cliffRewardPercentage._percentage == 0 &&
            _stakingParameters._cliffDuration == 0 &&
            _stakingParameters._linearDuration == 0
        ) {
            uint256 reward = _stakingParameters
                ._totalReward
                .mul(targetTime)
                .div(
                    _stakingParameters._endDate.sub(
                        _stakingParameters._startDate
                    )
                );
            return APY(reward.mul(100000).div(_totalKataStaked), 100000);
        }
        return getAPYWithVesting();
    }

    function getAPYWithVesting() private view returns (APY memory) {
        uint256 targetTime = 365 days;
        Stake memory syntheticStake = Stake(
            _totalKataStaked,
            block.timestamp,
            _stakingParameters._stakingToken,
            totalSupply(),
            0,
            APY(0, 1),
            block.timestamp,
            true
        );
        uint256 reward = computeRewardForStakeWithVesting(
            block.timestamp + targetTime,
            syntheticStake,
            true
        );
        return APY(reward.mul(100000).div(_totalKataStaked), 100000);
    }

    /***@notice Create a new stake by taking into account accrued rewards when estimating the number of xKata tokens in exchange for Kata tokens */
    function createStake(uint256 amount) private view returns (Stake memory) {
        uint256 xKataAmountToMint;
        uint256 currentTimeStanp = block.timestamp;
        if (_totalKataStaked == 0 || totalSupply() == 0) {
            xKataAmountToMint = amount;
        } else {
            //Add multiplication by 1 + time to maturity ratio
            uint256 multiplier = amount
                .mul(
                    _stakingParameters._endDate.sub(
                        _stakingParameters._startDate
                    )
                )
                .div(
                    _stakingParameters._endDate.add(currentTimeStanp).sub(
                        2 * _stakingParameters._startDate
                    )
                );
            xKataAmountToMint = multiplier.mul(totalSupply()).div(
                _totalKataStaked
            );
        }
        return
            Stake(
                amount,
                currentTimeStanp,
                _stakingParameters._stakingToken,
                xKataAmountToMint,
                0,
                APY(0, 1),
                currentTimeStanp,
                true
            );
    }

    /*** Stats functions */

    /***@notice returns the amount of Kata tokens available for rewards */
    function getRewardBalance() public view returns (uint256) {
        uint256 stakingTokenBalance = _stakingParameters
            ._stakingToken
            .balanceOf(address(this));
        uint256 rewardBalance = stakingTokenBalance.sub(_totalKataStaked);
        return rewardBalance;
    }

    /***@notice returns the amount of Kata tokens withdrawn as rewards */
    function getTotalRewardsClaimed() public view returns (uint256) {
        return _totalKataRewardsClaimed;
    }

    function getRequiredRewardAmountForPerdiod(uint256 endPeriod)
        external
        view
        onlyOwner
        returns (uint256)
    {
        return caluclateRequiredRewardAmountForPerdiod(endPeriod);
    }

    function getRequiredRewardAmount() external view returns (uint256) {
        return caluclateRequiredRewardAmountForPerdiod(block.timestamp);
    }

    ///////////////////////////////////////////////////////////////

    function caluclateRequiredRewardAmountForPerdiod(uint256 endPeriod)
        private
        view
        returns (uint256)
    {
        if (
            !_stakingStarted ||
            _stakingParameters._endDate == _stakingParameters._startDate ||
            _totalKataStaked == 0
        ) return 0;
        uint256 requiredReward = _stakingParameters
            ._totalReward
            .mul(endPeriod.sub(_stakingParameters._startDate))
            .div(_stakingParameters._endDate.sub(_stakingParameters._startDate))
            .sub(_totalKataRewardsClaimed);
        return requiredReward;
    }

    /***@notice Calculate the reward for a give stake if withdrawn at 'targetTime' */
    function computeRewardForStake(
        uint256 targetTime,
        Stake memory targetStake,
        bool existingStake
    ) private view returns (uint256) {
        if (
            _stakingParameters._immediateRewardPercentage._percentage == 0 &&
            _stakingParameters._cliffRewardPercentage._percentage == 0 &&
            _stakingParameters._cliffDuration == 0 &&
            _stakingParameters._linearDuration == 0
        ) {
            return
                computeReward(
                    _stakingParameters._totalReward,
                    targetTime,
                    targetStake._stakaAmount,
                    targetStake._rewardStartDate,
                    existingStake
                );
        }
        return
            computeRewardForStakeWithVesting(
                targetTime,
                targetStake,
                existingStake
            );
    }

    function computeRewardForStakeWithVesting(
        uint256 targetTime,
        Stake memory targetStake,
        bool existingStake
    ) private view returns (uint256) {
        uint256 accumulatedReward;
        uint256 currentStartTime = targetStake._rewardStartDate;
        uint256 currentTotalRewardAmount = (
            _stakingParameters._totalReward.mul(
                _stakingParameters._immediateRewardPercentage._percentage
            )
        ).div(_stakingParameters._immediateRewardPercentage._percentageBase);

        if (
            (currentStartTime + _stakingParameters._cliffDuration) >= targetTime
        ) {
            return
                computeReward(
                    currentTotalRewardAmount,
                    targetTime,
                    targetStake._stakaAmount,
                    currentStartTime,
                    existingStake
                );
        }

        accumulatedReward += computeReward(
            currentTotalRewardAmount,
            currentStartTime + _stakingParameters._cliffDuration,
            targetStake._stakaAmount,
            currentStartTime,
            existingStake
        );

        currentStartTime = currentStartTime + _stakingParameters._cliffDuration;
        currentTotalRewardAmount += (
            _stakingParameters._totalReward.mul(
                _stakingParameters._cliffRewardPercentage._percentage
            )
        ).div(_stakingParameters._cliffRewardPercentage._percentageBase);

        if (
            _stakingParameters._linearDuration == 0 ||
            (currentStartTime + _stakingParameters._linearDuration) <=
            targetTime
        ) {
            // 100% percent of the reward vested
            currentTotalRewardAmount = _stakingParameters._totalReward;

            return (
                accumulatedReward.add(
                    computeReward(
                        currentTotalRewardAmount,
                        targetTime,
                        targetStake._stakaAmount,
                        currentStartTime,
                        existingStake
                    )
                )
            );
        }
        // immediate + cliff + linear proportion of the reward
        currentTotalRewardAmount += (
            _stakingParameters._totalReward.sub(currentTotalRewardAmount)
        ).mul(targetTime - currentStartTime).div(
                _stakingParameters._linearDuration
            );
        accumulatedReward += computeReward(
            currentTotalRewardAmount,
            targetTime,
            targetStake._stakaAmount,
            currentStartTime,
            existingStake
        );
        return accumulatedReward;
    }

    /***@notice Calculate the reward for a give stake if withdrawn at 'targetTime' */
    function computeReward(
        uint256 applicableReward,
        uint256 targetTime,
        uint256 stakaAmount,
        uint256 rewardStartDate,
        bool existingStake
    ) private view returns (uint256) {
        uint256 mulltiplier = stakaAmount
            .mul(applicableReward)
            .mul(targetTime.sub(rewardStartDate))
            .div(
                _stakingParameters._endDate.sub(_stakingParameters._startDate)
            );

        uint256 divider = existingStake
            ? totalSupply()
            : totalSupply().add(stakaAmount);
        return mulltiplier.div(divider);
    }

    /**
     * @notice
     * Update Staking Token
     */
    function setStakingToken(address stakingTokenAddress) external onlyOwner {
        _stakingParameters._stakingToken = IERC20(stakingTokenAddress);
    }

    /*** @notice Withdraw reward */
    function withdrawFromReward(uint256 amount) external onlyOwner {
        //Check if there is enough reward tokens, this is to avoid paying rewards with other stakeholders stake
        require(
            amount <= getRewardBalance(),
            "The contract does not have enough reward tokens"
        );
        //Transfer amount to contract (this)
        if (!_stakingParameters._stakingToken.transfer(msg.sender, amount)) {
            revert("couldn 't transfer tokens from sender to contract");
        }
    }

    /**
     * @notice
     * Return the total amount staked
     */
    function getTotalStaked() external view returns (uint256) {
        return _totalKataStaked;
    }

    /**
     * @notice
     * Return the value of the penalty for early exit
     */
    function getContractParameters()
        external
        view
        returns (StakingContractParameters memory)
    {
        return _stakingParameters;
    }

    /**
     * @notice
     * Return stakes for msg.sender
     */
    function getStake() external view returns (Stake memory) {
        Stake memory currentStake = _stakeholdersMapping[msg.sender];
        if (!currentStake._exists) {
            // Return empty stake
            return
                Stake(
                    0,
                    0,
                    _stakingParameters._stakingToken,
                    0,
                    0,
                    APY(0, 1),
                    0,
                    false
                );
        }
        if (_stakingStarted) {
            currentStake._estimatedReward = computeRewardForStake(
                block.timestamp,
                currentStake,
                true
            );
            currentStake._estimatedAPY = APY(
                computeRewardForStake(
                    currentStake._rewardStartDate + 365 days,
                    currentStake,
                    true
                ).mul(100000).div(currentStake._amount),
                100000
            );
        }
        return currentStake;
    }

    function shouldStartContract(
        uint256 newTotalKataStaked,
        uint256 newCurrentNumberOfStakeHolders
    ) private view returns (bool) {
        if (
            _stakingParameters._minimumTotalStakeBeforeStart > 0 &&
            newTotalKataStaked <
            _stakingParameters._minimumTotalStakeBeforeStart
        ) {
            return false;
        }
        if (
            _stakingParameters._minimumNumberStakeHoldersBeforeStart > 0 &&
            newCurrentNumberOfStakeHolders <
            _stakingParameters._minimumNumberStakeHoldersBeforeStart
        ) {
            return false;
        }
        return true;
    }

    function _afterTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal override {
        if (from == address(0))
            //Nothing to do when _mint is called
            return;
        if (to == address(0))
            //Nothing to do when _burn is called
            return;

        Stake memory fromStake = _stakeholdersMapping[from];
        uint256 amountOfKataToTransfer = (
            _stakeholdersMapping[from]._amount.mul(amount)
        ).div(_stakeholdersMapping[from]._stakaAmount);

        fromStake._exists = true;
        fromStake._stakaAmount = amount;
        fromStake._amount = amountOfKataToTransfer;
        if (!_stakeholdersMapping[to]._exists) {
            _stakeholdersMapping[to] = fromStake;
            _stakeholdersMapping[from]._stakaAmount -= amount;
            _stakeholdersMapping[from]._amount -= amountOfKataToTransfer;
        } else {
            _stakeholdersMapping[to]
                ._rewardStartDate = calculateNewRewardStartDate(
                _stakeholdersMapping[to],
                fromStake
            );
            _stakeholdersMapping[to]._stakaAmount += amount;
            _stakeholdersMapping[to]._amount += amountOfKataToTransfer;
            _stakeholdersMapping[from]._stakaAmount -= amount;
            _stakeholdersMapping[from]._amount -= amountOfKataToTransfer;
        }
    }

    function pause() external onlyOwner {
        _pause();
    }

    function unpause() external onlyOwner {
        _unpause();
    }

    /**
     * onlyUser
     * @dev guard contracts from calling method
     **/
    modifier onlyUser() {
        require(msg.sender == tx.origin);
        _;
    }
}

File 2 of 8 : Ownable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title Ownable
 * @dev Ownable has an owner address to simplify "user permissions".
 */
contract Ownable {
  address payable public owner;

  /**
   * Ownable
   * @dev Ownable constructor sets the `owner` of the contract to sender
   */
  constructor() {  owner = payable(msg.sender);  }

  /**
   * ownerOnly
   * @dev Throws an error if called by any account other than the owner.
   */
  modifier onlyOwner() {
    require(msg.sender == owner);
    _;
  }

  /**
   * transferOwnership
   * @dev Allows the current owner to transfer control of the contract to a newOwner.
   * @param newOwner The address to transfer ownership to.
   */
  function transferOwnership(address payable newOwner) public onlyOwner {
    require(newOwner != address(0));
    owner = newOwner;
  }
}

File 3 of 8 : SafeMath.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)

pragma solidity ^0.8.0;

// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.

/**
 * @dev Wrappers over Solidity's arithmetic operations.
 *
 * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
 * now has built in overflow checking.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

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

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

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

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

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

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

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

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator.
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return a / b;
    }

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

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

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

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

File 4 of 8 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

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

File 5 of 8 : 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 6 of 8 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @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 `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, 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 `sender` to `recipient` 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 sender,
        address recipient,
        uint256 amount
    ) external returns (bool);

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

File 7 of 8 : ERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/ERC20.sol)

pragma solidity ^0.8.0;

import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC20
 * applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20 is Context, IERC20, IERC20Metadata {
    mapping(address => uint256) private _balances;

    mapping(address => mapping(address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * The default value of {decimals} is 18. To select a different value for
     * {decimals} you should overload it.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the value {ERC20} uses, unless this function is
     * overridden;
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual override returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual override returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `recipient` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
        _transfer(_msgSender(), recipient, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        _approve(_msgSender(), spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * Requirements:
     *
     * - `sender` and `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     * - the caller must have allowance for ``sender``'s tokens of at least
     * `amount`.
     */
    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) public virtual override returns (bool) {
        _transfer(sender, recipient, amount);

        uint256 currentAllowance = _allowances[sender][_msgSender()];
        require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
        unchecked {
            _approve(sender, _msgSender(), currentAllowance - amount);
        }

        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        uint256 currentAllowance = _allowances[_msgSender()][spender];
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        unchecked {
            _approve(_msgSender(), spender, currentAllowance - subtractedValue);
        }

        return true;
    }

    /**
     * @dev Moves `amount` of tokens from `sender` to `recipient`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `sender` cannot be the zero address.
     * - `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     */
    function _transfer(
        address sender,
        address recipient,
        uint256 amount
    ) internal virtual {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(sender, recipient, amount);

        uint256 senderBalance = _balances[sender];
        require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
        unchecked {
            _balances[sender] = senderBalance - amount;
        }
        _balances[recipient] += amount;

        emit Transfer(sender, recipient, amount);

        _afterTokenTransfer(sender, recipient, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        _beforeTokenTransfer(address(0), account, amount);

        _totalSupply += amount;
        _balances[account] += amount;
        emit Transfer(address(0), account, amount);

        _afterTokenTransfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        _beforeTokenTransfer(account, address(0), amount);

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        unchecked {
            _balances[account] = accountBalance - amount;
        }
        _totalSupply -= amount;

        emit Transfer(account, address(0), amount);

        _afterTokenTransfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}

    /**
     * @dev Hook that is called after any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * has been transferred to `to`.
     * - when `from` is zero, `amount` tokens have been minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}
}

File 8 of 8 : Pausable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/Pausable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

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

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    constructor() {
        _paused = false;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        require(!paused(), "Pausable: paused");
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        require(paused(), "Pausable: not paused");
        _;
    }

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

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

Settings
{
  "remappings": [],
  "optimizer": {
    "enabled": false,
    "runs": 200
  },
  "evmVersion": "istanbul",
  "libraries": {},
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"stakingTokenAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stakeholder","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountSKataBurned","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountReceived","type":"uint256"}],"name":"EmergencyWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stakeholder","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountStaked","type":"uint256"},{"indexed":false,"internalType":"contract IERC20","name":"stakingToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"xKataAmount","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stakeholder","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountStaked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountReceived","type":"uint256"},{"indexed":false,"internalType":"contract IERC20","name":"stakingToken","type":"address"}],"name":"Withdrawn","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"_stakeholdersMapping","outputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_since","type":"uint256"},{"internalType":"contract IERC20","name":"_stakingToken","type":"address"},{"internalType":"uint256","name":"_stakaAmount","type":"uint256"},{"internalType":"uint256","name":"_estimatedReward","type":"uint256"},{"components":[{"internalType":"uint256","name":"_apy","type":"uint256"},{"internalType":"uint256","name":"_base","type":"uint256"}],"internalType":"struct APY","name":"_estimatedAPY","type":"tuple"},{"internalType":"uint256","name":"_rewardStartDate","type":"uint256"},{"internalType":"bool","name":"_exists","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"stakeHolderAddress","type":"address"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAPY","outputs":[{"components":[{"internalType":"uint256","name":"_apy","type":"uint256"},{"internalType":"uint256","name":"_base","type":"uint256"}],"internalType":"struct APY","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractParameters","outputs":[{"components":[{"internalType":"uint256","name":"_minimumStake","type":"uint256"},{"internalType":"uint256","name":"_maxSupply","type":"uint256"},{"internalType":"uint256","name":"_totalReward","type":"uint256"},{"internalType":"contract IERC20","name":"_stakingToken","type":"address"},{"internalType":"uint256","name":"_stakingDuration","type":"uint256"},{"internalType":"uint256","name":"_maximumStake","type":"uint256"},{"internalType":"uint256","name":"_minimumNumberStakeHoldersBeforeStart","type":"uint256"},{"internalType":"uint256","name":"_minimumTotalStakeBeforeStart","type":"uint256"},{"internalType":"uint256","name":"_startDate","type":"uint256"},{"internalType":"uint256","name":"_endDate","type":"uint256"},{"components":[{"internalType":"uint256","name":"_percentage","type":"uint256"},{"internalType":"uint256","name":"_percentageBase","type":"uint256"}],"internalType":"struct Percentage","name":"_immediateRewardPercentage","type":"tuple"},{"internalType":"uint256","name":"_cliffDuration","type":"uint256"},{"components":[{"internalType":"uint256","name":"_percentage","type":"uint256"},{"internalType":"uint256","name":"_percentageBase","type":"uint256"}],"internalType":"struct Percentage","name":"_cliffRewardPercentage","type":"tuple"},{"internalType":"uint256","name":"_linearDuration","type":"uint256"}],"internalType":"struct StakingContractParameters","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"targetTime","type":"uint256"},{"internalType":"uint256","name":"amountToStake","type":"uint256"}],"name":"getEstimationOfReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRequiredRewardAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"endPeriod","type":"uint256"}],"name":"getRequiredRewardAmountForPerdiod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewardBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStake","outputs":[{"components":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_since","type":"uint256"},{"internalType":"contract IERC20","name":"_stakingToken","type":"address"},{"internalType":"uint256","name":"_stakaAmount","type":"uint256"},{"internalType":"uint256","name":"_estimatedReward","type":"uint256"},{"components":[{"internalType":"uint256","name":"_apy","type":"uint256"},{"internalType":"uint256","name":"_base","type":"uint256"}],"internalType":"struct APY","name":"_estimatedAPY","type":"tuple"},{"internalType":"uint256","name":"_rewardStartDate","type":"uint256"},{"internalType":"bool","name":"_exists","type":"bool"}],"internalType":"struct Stake","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"targetTime","type":"uint256"}],"name":"getStakeReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalRewardsClaimed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalStaked","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"stakingTokenAddress","type":"address"}],"name":"setStakingToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"_minimumStake","type":"uint256"},{"internalType":"uint256","name":"_maxSupply","type":"uint256"},{"internalType":"uint256","name":"_totalReward","type":"uint256"},{"internalType":"contract IERC20","name":"_stakingToken","type":"address"},{"internalType":"uint256","name":"_stakingDuration","type":"uint256"},{"internalType":"uint256","name":"_maximumStake","type":"uint256"},{"internalType":"uint256","name":"_minimumNumberStakeHoldersBeforeStart","type":"uint256"},{"internalType":"uint256","name":"_minimumTotalStakeBeforeStart","type":"uint256"},{"components":[{"internalType":"uint256","name":"_percentage","type":"uint256"},{"internalType":"uint256","name":"_percentageBase","type":"uint256"}],"internalType":"struct Percentage","name":"_immediateRewardPercentage","type":"tuple"},{"internalType":"uint256","name":"_cliffDuration","type":"uint256"},{"components":[{"internalType":"uint256","name":"_percentage","type":"uint256"},{"internalType":"uint256","name":"_percentageBase","type":"uint256"}],"internalType":"struct Percentage","name":"_cliffRewardPercentage","type":"tuple"},{"internalType":"uint256","name":"_linearDuration","type":"uint256"}],"internalType":"struct StakingContractParametersUpdate","name":"stakingParameters","type":"tuple"}],"name":"updateStakingParameters","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawFromReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawStake","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60806040523480156200001157600080fd5b50604051620060fa380380620060fa833981810160405281019062000037919062000250565b6040518060400160405280600b81526020017f5354414b4120546f6b656e0000000000000000000000000000000000000000008152506040518060400160405280600581526020017f5354414b410000000000000000000000000000000000000000000000000000008152508160039080519060200190620000bb92919062000189565b508060049080519060200190620000d492919062000189565b50505033600560006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000600560146101000a81548160ff02191690831515021790555080600860030160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600860060181905550506200032f565b8280546200019790620002b0565b90600052602060002090601f016020900481019282620001bb576000855562000207565b82601f10620001d657805160ff191683800117855562000207565b8280016001018555821562000207579182015b8281111562000206578251825591602001919060010190620001e9565b5b5090506200021691906200021a565b5090565b5b80821115620002355760008160009055506001016200021b565b5090565b6000815190506200024a8162000315565b92915050565b6000602082840312156200026357600080fd5b6000620002738482850162000239565b91505092915050565b6000620002898262000290565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006002820490506001821680620002c957607f821691505b60208210811415620002e057620002df620002e6565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b62000320816200027c565b81146200032c57600080fd5b50565b615dbb806200033f6000396000f3fe608060405234801561001057600080fd5b50600436106101fb5760003560e01c80636ff1c9bc1161011a578063a694fc3a116100ad578063d2cbf7ad1161007c578063d2cbf7ad146105bd578063dd62ed3e146105db578063ea4405001461060b578063f2fde38b1461063b578063fc0e3d9014610657576101fb565b8063a694fc3a14610537578063a9059cbb14610553578063b0b5529e14610583578063bfacd9ed1461059f576101fb565b80638da5cb5b116100e95780638da5cb5b146104af57806395d89b41146104cd5780639d836bd2146104eb578063a457c2d714610507576101fb565b80636ff1c9bc1461042257806370a082311461043e578063758035661461046e5780638456cb59146104a5576101fb565b80632ff7cfc61161019257806348f9ead41161016157806348f9ead4146103865780635931b24e146103b65780635c975abb146103e65780635e42b45514610404576101fb565b80632ff7cfc614610310578063313ce5671461032e578063395093511461034c5780633f4ba83a1461037c576101fb565b80631e9b12ef116101ce5780631e9b12ef1461028a57806323b872dd146102a657806325d5971f146102d65780632f861449146102f2576101fb565b806306fdde03146102005780630917e7761461021e578063095ea7b31461023c57806318160ddd1461026c575b600080fd5b610208610675565b60405161021591906154b6565b60405180910390f35b610226610707565b604051610233919061580b565b60405180910390f35b610256600480360381019061025191906147b5565b610711565b604051610263919061549b565b60405180910390f35b61027461072f565b604051610281919061580b565b60405180910390f35b6102a4600480360381019061029f91906146d8565b610739565b005b6102c060048036038101906102bb9190614766565b6107da565b6040516102cd919061549b565b60405180910390f35b6102f060048036038101906102eb919061486d565b6108d2565b005b6102fa610eaa565b604051610307919061580b565b60405180910390f35b610318610eb4565b604051610325919061580b565b60405180910390f35b610336610ec4565b604051610343919061593c565b60405180910390f35b610366600480360381019061036191906147b5565b610ecd565b604051610373919061549b565b60405180910390f35b610384610f79565b005b6103a0600480360381019061039b919061486d565b610fdd565b6040516103ad919061580b565b60405180910390f35b6103d060048036038101906103cb91906148bf565b611049565b6040516103dd919061580b565b60405180910390f35b6103ee61106c565b6040516103fb919061549b565b60405180910390f35b61040c611083565b604051610419919061580b565b60405180910390f35b61043c600480360381019061043791906146d8565b611157565b005b610458600480360381019061045391906146d8565b611620565b604051610465919061580b565b60405180910390f35b610488600480360381019061048391906146d8565b611668565b60405161049c9897969594939291906158bd565b60405180910390f35b6104ad6116fb565b005b6104b761175f565b6040516104c49190615420565b60405180910390f35b6104d5611785565b6040516104e291906154b6565b60405180910390f35b61050560048036038101906105009190614843565b611817565b005b610521600480360381019061051c91906147b5565b611a4b565b60405161052e919061549b565b60405180910390f35b610551600480360381019061054c919061486d565b611b36565b005b61056d600480360381019061056891906147b5565b6123d6565b60405161057a919061549b565b60405180910390f35b61059d6004803603810190610598919061486d565b6123f4565b005b6105a761258c565b6040516105b491906157ef565b60405180910390f35b6105c56126bb565b6040516105d291906157b8565b60405180910390f35b6105f560048036038101906105f0919061472a565b612809565b604051610602919061580b565b60405180910390f35b6106256004803603810190610620919061486d565b612890565b604051610632919061580b565b60405180910390f35b61065560048036038101906106509190614701565b612a87565b005b61065f612b5f565b60405161066c91906157d3565b60405180910390f35b60606003805461068490615b6a565b80601f01602080910402602001604051908101604052809291908181526020018280546106b090615b6a565b80156106fd5780601f106106d2576101008083540402835291602001916106fd565b820191906000526020600020905b8154815290600101906020018083116106e057829003601f168201915b5050505050905090565b6000601854905090565b600061072561071e612dc1565b8484612dc9565b6001905092915050565b6000600254905090565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461079357600080fd5b80600860030160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60006107e7848484612f94565b6000600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000610832612dc1565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050828110156108b2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108a990615678565b60405180910390fd5b6108c6856108be612dc1565b858403612dc9565b60019150509392505050565b3273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461090a57600080fd5b61091261106c565b15610952576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610949906155f8565b60405180910390fd5b600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060080160009054906101000a900460ff166109e1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109d890615658565b60405180910390fd5b80600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001541015610a66576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a5d906155d8565b60405180910390fd5b6000600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518061010001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001600382015481526020016004820154815260200160058201604051806040016040529081600082015481526020016001820154815250508152602001600782015481526020016008820160009054906101000a900460ff16151515158152505090506000816000015111610bc7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bbe906156d8565b60405180910390fd5b6000610bfd8260000151610bef85610be142876001613215565b61329390919063ffffffff16565b6132a990919063ffffffff16565b90506000610c09611083565b905080821115610c4e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c4590615618565b60405180910390fd5b60008483610c5c9190615973565b90506000610c8d8560000151610c7f88886060015161329390919063ffffffff16565b6132a990919063ffffffff16565b905085600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000016000828254610ce19190615a54565b9250508190555080600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206003016000828254610d3a9190615a54565b9250508190555085601854610d4f9190615a54565b6018819055508360196000828254610d679190615973565b92505081905550846040015173ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33846040518363ffffffff1660e01b8152600401610dad929190615472565b602060405180830381600087803b158015610dc757600080fd5b505af1158015610ddb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dff91906147f1565b610e3e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e3590615718565b60405180910390fd5b610e4833826132bf565b3373ffffffffffffffffffffffffffffffffffffffff167fbc0fb706d03a6cb96fbe31862998338850cd01d239a360045dbe469d548e42188660000151848860400151604051610e9a93929190615886565b60405180910390a2505050505050565b6000601954905090565b6000610ebf42613496565b905090565b60006012905090565b6000610f6f610eda612dc1565b848460016000610ee8612dc1565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610f6a9190615973565b612dc9565b6001905092915050565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610fd357600080fd5b610fdb613554565b565b6000600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461103957600080fd5b61104282613496565b9050919050565b600080611055836135f6565b905061106384826000613215565b91505092915050565b6000600560149054906101000a900460ff16905090565b600080600860030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016110e49190615405565b60206040518083038186803b1580156110fc57600080fd5b505afa158015611110573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111349190614896565b9050600061114d6018548361377090919063ffffffff16565b9050809250505090565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146111b157600080fd5b600660008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060080160009054906101000a900460ff16611240576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161123790615658565b60405180910390fd5b6000600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000154116112c5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112bc90615558565b60405180910390fd5b600080600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001549150600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600301549050600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb84600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001546040518363ffffffff1660e01b8152600401611431929190615472565b602060405180830381600087803b15801561144b57600080fd5b505af115801561145f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061148391906147f1565b6114c2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114b990615718565b60405180910390fd5b6000600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001819055506000600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060080160006101000a81548160ff0219169083151502179055506000600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060030181905550816018546115bb9190615a54565b6018819055506115cb83826132bf565b8273ffffffffffffffffffffffffffffffffffffffff167fbb757047c2b5f3974fe26b7c10f732e7bce710b0952a71082702781e62ae0595828460405161161392919061585d565b60405180910390a2505050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60066020528060005260406000206000915090508060000154908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060030154908060040154908060050160405180604001604052908160008201548152602001600182015481525050908060070154908060080160009054906101000a900460ff16905088565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461175557600080fd5b61175d613786565b565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60606004805461179490615b6a565b80601f01602080910402602001604051908101604052809291908181526020018280546117c090615b6a565b801561180d5780601f106117e25761010080835404028352916020019161180d565b820191906000526020600020905b8154815290600101906020018083116117f057829003601f168201915b5050505050905090565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461187157600080fd5b8060000135600860000181905550806020013560086001018190555080604001356008600201819055508060600160208101906118ae919061481a565b600860030160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060800135600860040181905550601a60009054906101000a900460ff16156119335760086004015460088001546119299190615973565b6008600901819055505b601a60009054906101000a900460ff166119ea578060c001356008600601819055508060e001356008600701819055506000600860070154148061197e575060086007015460185410155b80156119a15750600060086006015414806119a0575060086006015460075410155b5b156119e9576001601a60006101000a81548160ff02191690831515021790555042600880018190555060086004015460088001546119df9190615973565b6008600901819055505b5b8060a0013560086005018190555080610100016008600a018181611a0e9190615ca9565b9050508061014001356008600c018190555080610160016008600d018181611a369190615ca9565b905050806101a001356008600f018190555050565b60008060016000611a5a612dc1565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905082811015611b17576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b0e90615778565b60405180910390fd5b611b2b611b22612dc1565b85858403612dc9565b600191505092915050565b3273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611b6e57600080fd5b611b7661106c565b15611bb6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bad906155f8565b60405180910390fd5b600860000154811015611bfe576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bf590615598565b60405180910390fd5b60006008600501541480611c1757506008600501548111155b611c56576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c4d906156f8565b60405180910390fd5b60086001015481601854611c6a9190615973565b1115611cab576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ca290615638565b60405180910390fd5b601a60009054906101000a900460ff161580611ccb575060086009015442105b611d0a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d0190615538565b60405180910390fd5b60086002015460195410611d53576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d4a90615758565b60405180910390fd5b6000611d5e826135f6565b90508160186000828254611d729190615973565b92505081905550600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060080160009054906101000a900460ff16611de857600160076000828254611de09190615973565b925050819055505b601a60009054906101000a900460ff16158015611e1c575060006008600701541480611e1b575060086007015460185410155b5b8015611e3f575060006008600601541480611e3e575060086006015460075410155b5b15611e87576001601a60006101000a81548160ff0219169083151502179055504260088001819055506008600401546008800154611e7d9190615973565b6008600901819055505b600860030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd3330856040518463ffffffff1660e01b8152600401611ee99392919061543b565b602060405180830381600087803b158015611f0357600080fd5b505af1158015611f17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f3b91906147f1565b611f7a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f7190615718565b60405180910390fd5b611f88338260600151613829565b600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060080160009054906101000a900460ff166121375780600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550606082015181600301556080820151816004015560a0820151816005016000820151816000015560208201518160010155505060c0820151816007015560e08201518160080160006101000a81548160ff0219169083151502179055509050506001600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060080160006101000a81548160ff021916908315150217905550612357565b612256600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518061010001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001600382015481526020016004820154815260200160058201604051806040016040529081600082015481526020016001820154815250508152602001600782015481526020016008820160009054906101000a900460ff16151515158152505082613989565b600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600701819055508060000151600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160008282546122f29190615973565b925050819055508060600151600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600301600082825461234f9190615973565b925050819055505b3373ffffffffffffffffffffffffffffffffffffffff167ff65271afc35201e83c229b7b581d7fde59bfe7b7dd943e8719fc8c5f5ada63f683600860030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1684606001516040516123ca93929190615826565b60405180910390a25050565b60006123ea6123e3612dc1565b8484612f94565b6001905092915050565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461244e57600080fd5b612456611083565b811115612498576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161248f90615618565b60405180910390fd5b600860030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33836040518363ffffffff1660e01b81526004016124f8929190615472565b602060405180830381600087803b15801561251257600080fd5b505af1158015612526573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061254a91906147f1565b612589576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161258090615718565b60405180910390fd5b50565b612594614516565b6008604051806101c00160405290816000820154815260200160018201548152602001600282015481526020016003820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001600482015481526020016005820154815260200160068201548152602001600782015481526020016008820154815260200160098201548152602001600a8201604051806040016040529081600082015481526020016001820154815250508152602001600c8201548152602001600d8201604051806040016040529081600082015481526020016001820154815250508152602001600f82015481525050905090565b6126c36145a7565b601a60009054906101000a900460ff1615806126e757506008800154600860090154145b806126f457506000601854145b156127175760405180604001604052806000815260200160018152509050612806565b60006301e13380905060006008600a0160000154148015612740575060006008600d0160000154145b8015612751575060006008600c0154145b8015612762575060006008600f0154145b156127fa5760006127ae612788600880015460086009015461377090919063ffffffff16565b6127a08460086002015461329390919063ffffffff16565b6132a990919063ffffffff16565b905060405180604001604052806127e56018546127d7620186a08661329390919063ffffffff16565b6132a990919063ffffffff16565b8152602001620186a081525092505050612806565b612802613a11565b9150505b90565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b60003273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146128ca57600080fd5b600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060080160009054906101000a900460ff16612959576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161295090615658565b60405180910390fd5b6000600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518061010001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001600382015481526020016004820154815260200160058201604051806040016040529081600082015481526020016001820154815250508152602001600782015481526020016008820160009054906101000a900460ff1615151515815250509050612a7f83826001613215565b915050919050565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612ae157600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415612b1b57600080fd5b80600560006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b612b676145c1565b6000600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518061010001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001600382015481526020016004820154815260200160058201604051806040016040529081600082015481526020016001820154815250508152602001600782015481526020016008820160009054906101000a900460ff16151515158152505090508060e00151612d25576040518061010001604052806000815260200160008152602001600860030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000815260200160008152602001604051806040016040528060008152602001600181525081526020016000815260200160001515815250915050612dbe565b601a60009054906101000a900460ff1615612db957612d4642826001613215565b8160800181815250506040518060400160405280612da48360000151612d96620186a0612d886301e133808860c00151612d809190615973565b886001613215565b61329390919063ffffffff16565b6132a990919063ffffffff16565b8152602001620186a08152508160a001819052505b809150505b90565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415612e39576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612e3090615738565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415612ea9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612ea090615578565b60405180910390fd5b80600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92583604051612f87919061580b565b60405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415613004576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612ffb906156b8565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415613074576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161306b906154d8565b60405180910390fd5b61307f838383613b22565b60008060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905081811015613105576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016130fc906155b8565b60405180910390fd5b8181036000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546131989190615973565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516131fc919061580b565b60405180910390a361320f848484613b27565b50505050565b6000806008600a0160000154148015613236575060006008600d0160000154145b8015613247575060006008600c0154145b8015613258575060006008600f0154145b1561327e576132776008600201548585606001518660c001518661425f565b905061328c565b613289848484614319565b90505b9392505050565b600081836132a191906159fa565b905092915050565b600081836132b791906159c9565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141561332f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161332690615698565b60405180910390fd5b61333b82600083613b22565b60008060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050818110156133c1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016133b890615518565b60405180910390fd5b8181036000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600260008282546134189190615a54565b92505081905550600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161347d919061580b565b60405180910390a361349183600084613b27565b505050565b6000601a60009054906101000a900460ff1615806134bc57506008800154600860090154145b806134c957506000601854145b156134d7576000905061354f565b600061354860195461353a6134fe600880015460086009015461377090919063ffffffff16565b61352c61351860088001548961377090919063ffffffff16565b60086002015461329390919063ffffffff16565b6132a990919063ffffffff16565b61377090919063ffffffff16565b9050809150505b919050565b61355c61106c565b61359b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613592906154f8565b60405180910390fd5b6000600560146101000a81548160ff0219169083151502179055507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6135df612dc1565b6040516135ec9190615405565b60405180910390a1565b6135fe6145c1565b6000804290506000601854148061361c5750600061361a61072f565b145b15613629578391506136d8565b60006136a46136686008800154600261364291906159fa565b61365a8560086009015461450090919063ffffffff16565b61377090919063ffffffff16565b613696613687600880015460086009015461377090919063ffffffff16565b8861329390919063ffffffff16565b6132a990919063ffffffff16565b90506136d46018546136c66136b761072f565b8461329390919063ffffffff16565b6132a990919063ffffffff16565b9250505b604051806101000160405280858152602001828152602001600860030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200183815260200160008152602001604051806040016040528060008152602001600181525081526020018281526020016001151581525092505050919050565b6000818361377e9190615a54565b905092915050565b61378e61106c565b156137ce576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016137c5906155f8565b60405180910390fd5b6001600560146101000a81548160ff0219169083151502179055507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258613812612dc1565b60405161381f9190615405565b60405180910390a1565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415613899576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161389090615798565b60405180910390fd5b6138a560008383613b22565b80600260008282546138b79190615973565b92505081905550806000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825461390c9190615973565b925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051613971919061580b565b60405180910390a361398560008383613b27565b5050565b6000806139d36139aa84606001518560c0015161329390919063ffffffff16565b6139c586606001518760c0015161329390919063ffffffff16565b61450090919063ffffffff16565b905060006139f28460600151866060015161450090919063ffffffff16565b9050613a0781836132a990919063ffffffff16565b9250505092915050565b613a196145a7565b60006301e13380905060006040518061010001604052806018548152602001428152602001600860030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001613a8761072f565b815260200160008152602001604051806040016040528060008152602001600181525081526020014281526020016001151581525090506000613ad78342613acf9190615973565b836001614319565b90506040518060400160405280613b0e601854613b00620186a08661329390919063ffffffff16565b6132a990919063ffffffff16565b8152602001620186a0815250935050505090565b505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415613b615761425a565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415613b9b5761425a565b6000600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518061010001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001600382015481526020016004820154815260200160058201604051806040016040529081600082015481526020016001820154815250508152602001600782015481526020016008820160009054906101000a900460ff16151515158152505090506000613d60600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060030154613d5285600660008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000015461329390919063ffffffff16565b6132a990919063ffffffff16565b905060018260e00190151590811515815250508282606001818152505080826000018181525050600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060080160009054906101000a900460ff16613f8d5781600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550606082015181600301556080820151816004015560a0820151816005016000820151816000015560208201518160010155505060c0820151816007015560e08201518160080160006101000a81548160ff02191690831515021790555090505082600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206003016000828254613f289190615a54565b9250508190555080600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000016000828254613f819190615a54565b92505081905550614257565b6140ac600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518061010001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001600382015481526020016004820154815260200160058201604051806040016040529081600082015481526020016001820154815250508152602001600782015481526020016008820160009054906101000a900460ff16151515158152505083613989565b600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206007018190555082600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060030160008282546141449190615973565b9250508190555080600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001600082825461419d9190615973565b9250508190555082600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060030160008282546141f69190615a54565b9250508190555080600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001600082825461424f9190615a54565b925050819055505b50505b505050565b6000806142c6614281600880015460086009015461377090919063ffffffff16565b6142b8614297878a61377090919063ffffffff16565b6142aa8b8a61329390919063ffffffff16565b61329390919063ffffffff16565b6132a990919063ffffffff16565b90506000836142ee576142e9866142db61072f565b61450090919063ffffffff16565b6142f7565b6142f661072f565b5b905061430c81836132a990919063ffffffff16565b9250505095945050505050565b60008060008460c00151905060006143616008600a01600101546143536008600a016000015460086002015461329390919063ffffffff16565b6132a990919063ffffffff16565b9050866008600c0154836143759190615973565b106143955761438b81888860600151858961425f565b93505050506144f9565b6143b6816008600c0154846143aa9190615973565b8860600151858961425f565b836143c19190615973565b92506008600c0154826143d49190615973565b91506144106008600d01600101546144026008600d016000015460086002015461329390919063ffffffff16565b6132a990919063ffffffff16565b8161441b9190615973565b905060006008600f015414806144415750866008600f01548361443e9190615973565b11155b1561447b57600860020154905061447161446282898960600151868a61425f565b8461450090919063ffffffff16565b93505050506144f9565b6144c76008600f01546144b9848a6144939190615a54565b6144ab8560086002015461377090919063ffffffff16565b61329390919063ffffffff16565b6132a990919063ffffffff16565b816144d29190615973565b90506144e581888860600151858961425f565b836144f09190615973565b92508293505050505b9392505050565b6000818361450e9190615973565b905092915050565b604051806101c00160405280600081526020016000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001614586614624565b81526020016000815260200161459a614624565b8152602001600081525090565b604051806040016040528060008152602001600081525090565b6040518061010001604052806000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600081526020016000815260200161460e6145a7565b8152602001600081526020016000151581525090565b604051806040016040528060008152602001600081525090565b60008135905061464d81615d12565b92915050565b60008135905061466281615d29565b92915050565b60008151905061467781615d40565b92915050565b60008135905061468c81615d57565b92915050565b60006101c082840312156146a557600080fd5b81905092915050565b6000813590506146bd81615d6e565b92915050565b6000815190506146d281615d6e565b92915050565b6000602082840312156146ea57600080fd5b60006146f88482850161463e565b91505092915050565b60006020828403121561471357600080fd5b600061472184828501614653565b91505092915050565b6000806040838503121561473d57600080fd5b600061474b8582860161463e565b925050602061475c8582860161463e565b9150509250929050565b60008060006060848603121561477b57600080fd5b60006147898682870161463e565b935050602061479a8682870161463e565b92505060406147ab868287016146ae565b9150509250925092565b600080604083850312156147c857600080fd5b60006147d68582860161463e565b92505060206147e7858286016146ae565b9150509250929050565b60006020828403121561480357600080fd5b600061481184828501614668565b91505092915050565b60006020828403121561482c57600080fd5b600061483a8482850161467d565b91505092915050565b60006101c0828403121561485657600080fd5b600061486484828501614692565b91505092915050565b60006020828403121561487f57600080fd5b600061488d848285016146ae565b91505092915050565b6000602082840312156148a857600080fd5b60006148b6848285016146c3565b91505092915050565b600080604083850312156148d257600080fd5b60006148e0858286016146ae565b92505060206148f1858286016146ae565b9150509250929050565b61490481615a9a565b82525050565b61491381615a88565b82525050565b61492281615aac565b82525050565b61493181615aac565b82525050565b61494081615b01565b82525050565b61494f81615b01565b82525050565b600061496082615957565b61496a8185615962565b935061497a818560208601615b37565b61498381615c49565b840191505092915050565b600061499b602383615962565b91507f45524332303a207472616e7366657220746f20746865207a65726f206164647260008301527f65737300000000000000000000000000000000000000000000000000000000006020830152604082019050919050565b6000614a01601483615962565b91507f5061757361626c653a206e6f74207061757365640000000000000000000000006000830152602082019050919050565b6000614a41602283615962565b91507f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60008301527f63650000000000000000000000000000000000000000000000000000000000006020830152604082019050919050565b6000614aa7601c83615962565b91507f546865207374616b696e6720706572696f642068617320656e646564000000006000830152602082019050919050565b6000614ae7602683615962565b91507f43616e206e6f7420616e79207374616b6520666f7220737570706c696564206160008301527f64647265737300000000000000000000000000000000000000000000000000006020830152604082019050919050565b6000614b4d602283615962565b91507f45524332303a20617070726f766520746f20746865207a65726f20616464726560008301527f73730000000000000000000000000000000000000000000000000000000000006020830152604082019050919050565b6000614bb3601e83615962565b91507f416d6f756e742062656c6f7720746865206d696e696d756d207374616b6500006000830152602082019050919050565b6000614bf3602683615962565b91507f45524332303a207472616e7366657220616d6f756e742065786365656473206260008301527f616c616e636500000000000000000000000000000000000000000000000000006020830152604082019050919050565b6000614c59602783615962565b91507f43616e206e6f74207769746864726177206d6f7265207468616e20616374756160008301527f6c207374616b65000000000000000000000000000000000000000000000000006020830152604082019050919050565b6000614cbf601083615962565b91507f5061757361626c653a20706175736564000000000000000000000000000000006000830152602082019050919050565b6000614cff602f83615962565b91507f54686520636f6e747261637420646f6573206e6f74206861766520656e6f756760008301527f682072657761726420746f6b656e7300000000000000000000000000000000006020830152604082019050919050565b6000614d65602e83615962565b91507f596f752063616e206e6f742065786365656564206d6178696d756d207375707060008301527f6c7920666f72207374616b696e670000000000000000000000000000000000006020830152604082019050919050565b6000614dcb601d83615962565b91507f43616e206e6f742066696e64207374616b6520666f722073656e6465720000006000830152602082019050919050565b6000614e0b602883615962565b91507f45524332303a207472616e7366657220616d6f756e742065786365656473206160008301527f6c6c6f77616e63650000000000000000000000000000000000000000000000006020830152604082019050919050565b6000614e71602183615962565b91507f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360008301527f73000000000000000000000000000000000000000000000000000000000000006020830152604082019050919050565b6000614ed7602583615962565b91507f45524332303a207472616e736665722066726f6d20746865207a65726f20616460008301527f64726573730000000000000000000000000000000000000000000000000000006020830152604082019050919050565b6000614f3d601783615962565b91507f5374616b6520616c72656461792077697468647261776e0000000000000000006000830152602082019050919050565b6000614f7d601c83615962565b91507f616d6f756e742065786365656473206d6178696d756d207374616b65000000006000830152602082019050919050565b6000614fbd603183615962565b91507f636f756c646e202774207472616e7366657220746f6b656e732066726f6d207360008301527f656e64657220746f20636f6e74726163740000000000000000000000000000006020830152604082019050919050565b6000615023602483615962565b91507f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460008301527f72657373000000000000000000000000000000000000000000000000000000006020830152604082019050919050565b6000615089602183615962565b91507f416c6c20726577617264732068617665206265656e206469737472696275746560008301527f64000000000000000000000000000000000000000000000000000000000000006020830152604082019050919050565b60006150ef602583615962565b91507f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760008301527f207a65726f0000000000000000000000000000000000000000000000000000006020830152604082019050919050565b6000615155601f83615962565b91507f45524332303a206d696e7420746f20746865207a65726f2061646472657373006000830152602082019050919050565b60408201600082015161519e60008501826153d8565b5060208201516151b160208501826153d8565b50505050565b6040820160008201516151cd60008501826153d8565b5060208201516151e060208501826153d8565b50505050565b6040820160008201516151fc60008501826153d8565b50602082015161520f60208501826153d8565b50505050565b6101208201600082015161522c60008501826153d8565b50602082015161523f60208501826153d8565b5060408201516152526040850182614937565b50606082015161526560608501826153d8565b50608082015161527860808501826153d8565b5060a082015161528b60a0850182615188565b5060c082015161529e60e08501826153d8565b5060e08201516152b2610100850182614919565b50505050565b610200820160008201516152cf60008501826153d8565b5060208201516152e260208501826153d8565b5060408201516152f560408501826153d8565b5060608201516153086060850182614937565b50608082015161531b60808501826153d8565b5060a082015161532e60a08501826153d8565b5060c082015161534160c08501826153d8565b5060e082015161535460e08501826153d8565b506101008201516153696101008501826153d8565b5061012082015161537e6101208501826153d8565b506101408201516153936101408501826151e6565b506101608201516153a86101808501826153d8565b506101808201516153bd6101a08501826151e6565b506101a08201516153d26101e08501826153d8565b50505050565b6153e181615aea565b82525050565b6153f081615aea565b82525050565b6153ff81615af4565b82525050565b600060208201905061541a600083018461490a565b92915050565b600060208201905061543560008301846148fb565b92915050565b6000606082019050615450600083018661490a565b61545d602083018561490a565b61546a60408301846153e7565b949350505050565b6000604082019050615487600083018561490a565b61549460208301846153e7565b9392505050565b60006020820190506154b06000830184614928565b92915050565b600060208201905081810360008301526154d08184614955565b905092915050565b600060208201905081810360008301526154f18161498e565b9050919050565b60006020820190508181036000830152615511816149f4565b9050919050565b6000602082019050818103600083015261553181614a34565b9050919050565b6000602082019050818103600083015261555181614a9a565b9050919050565b6000602082019050818103600083015261557181614ada565b9050919050565b6000602082019050818103600083015261559181614b40565b9050919050565b600060208201905081810360008301526155b181614ba6565b9050919050565b600060208201905081810360008301526155d181614be6565b9050919050565b600060208201905081810360008301526155f181614c4c565b9050919050565b6000602082019050818103600083015261561181614cb2565b9050919050565b6000602082019050818103600083015261563181614cf2565b9050919050565b6000602082019050818103600083015261565181614d58565b9050919050565b6000602082019050818103600083015261567181614dbe565b9050919050565b6000602082019050818103600083015261569181614dfe565b9050919050565b600060208201905081810360008301526156b181614e64565b9050919050565b600060208201905081810360008301526156d181614eca565b9050919050565b600060208201905081810360008301526156f181614f30565b9050919050565b6000602082019050818103600083015261571181614f70565b9050919050565b6000602082019050818103600083015261573181614fb0565b9050919050565b6000602082019050818103600083015261575181615016565b9050919050565b600060208201905081810360008301526157718161507c565b9050919050565b60006020820190508181036000830152615791816150e2565b9050919050565b600060208201905081810360008301526157b181615148565b9050919050565b60006040820190506157cd60008301846151b7565b92915050565b6000610120820190506157e96000830184615215565b92915050565b60006102008201905061580560008301846152b8565b92915050565b600060208201905061582060008301846153e7565b92915050565b600060608201905061583b60008301866153e7565b6158486020830185614946565b61585560408301846153e7565b949350505050565b600060408201905061587260008301856153e7565b61587f60208301846153e7565b9392505050565b600060608201905061589b60008301866153e7565b6158a860208301856153e7565b6158b56040830184614946565b949350505050565b6000610120820190506158d3600083018b6153e7565b6158e0602083018a6153e7565b6158ed6040830189614946565b6158fa60608301886153e7565b61590760808301876153e7565b61591460a08301866151b7565b61592160e08301856153e7565b61592f610100830184614928565b9998505050505050505050565b600060208201905061595160008301846153f6565b92915050565b600081519050919050565b600082825260208201905092915050565b600061597e82615aea565b915061598983615aea565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156159be576159bd615b9c565b5b828201905092915050565b60006159d482615aea565b91506159df83615aea565b9250826159ef576159ee615bcb565b5b828204905092915050565b6000615a0582615aea565b9150615a1083615aea565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615615a4957615a48615b9c565b5b828202905092915050565b6000615a5f82615aea565b9150615a6a83615aea565b925082821015615a7d57615a7c615b9c565b5b828203905092915050565b6000615a9382615aca565b9050919050565b6000615aa582615aca565b9050919050565b60008115159050919050565b6000615ac382615a88565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b6000615b0c82615b13565b9050919050565b6000615b1e82615aca565b9050919050565b6000615b3082615aea565b9050919050565b60005b83811015615b55578082015181840152602081019050615b3a565b83811115615b64576000848401525b50505050565b60006002820490506001821680615b8257607f821691505b60208210811415615b9657615b95615bfa565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000819050919050565b60008135615c4081615d6e565b80915050919050565b6000601f19601f8301169050919050565b60008160001b9050919050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff615c9384615c5a565b9350801983169250808416831791505092915050565b600081016000830180615cbb81615c33565b9050615cc78184615cef565b505050600181016020830180615cdc81615c33565b9050615ce88184615cef565b5050505050565b615cf882615b25565b615d0b615d0482615c29565b8354615c67565b8255505050565b615d1b81615a88565b8114615d2657600080fd5b50565b615d3281615a9a565b8114615d3d57600080fd5b50565b615d4981615aac565b8114615d5457600080fd5b50565b615d6081615ab8565b8114615d6b57600080fd5b50565b615d7781615aea565b8114615d8257600080fd5b5056fea2646970667358221220afecb0b0dd0e73ee4bd971c9bbd3ae530612cceed388cf838f1f5eb5cdbfdbb964736f6c634300080000330000000000000000000000002e85ae1c47602f7927bcabc2ff99c40aa222ae15

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101fb5760003560e01c80636ff1c9bc1161011a578063a694fc3a116100ad578063d2cbf7ad1161007c578063d2cbf7ad146105bd578063dd62ed3e146105db578063ea4405001461060b578063f2fde38b1461063b578063fc0e3d9014610657576101fb565b8063a694fc3a14610537578063a9059cbb14610553578063b0b5529e14610583578063bfacd9ed1461059f576101fb565b80638da5cb5b116100e95780638da5cb5b146104af57806395d89b41146104cd5780639d836bd2146104eb578063a457c2d714610507576101fb565b80636ff1c9bc1461042257806370a082311461043e578063758035661461046e5780638456cb59146104a5576101fb565b80632ff7cfc61161019257806348f9ead41161016157806348f9ead4146103865780635931b24e146103b65780635c975abb146103e65780635e42b45514610404576101fb565b80632ff7cfc614610310578063313ce5671461032e578063395093511461034c5780633f4ba83a1461037c576101fb565b80631e9b12ef116101ce5780631e9b12ef1461028a57806323b872dd146102a657806325d5971f146102d65780632f861449146102f2576101fb565b806306fdde03146102005780630917e7761461021e578063095ea7b31461023c57806318160ddd1461026c575b600080fd5b610208610675565b60405161021591906154b6565b60405180910390f35b610226610707565b604051610233919061580b565b60405180910390f35b610256600480360381019061025191906147b5565b610711565b604051610263919061549b565b60405180910390f35b61027461072f565b604051610281919061580b565b60405180910390f35b6102a4600480360381019061029f91906146d8565b610739565b005b6102c060048036038101906102bb9190614766565b6107da565b6040516102cd919061549b565b60405180910390f35b6102f060048036038101906102eb919061486d565b6108d2565b005b6102fa610eaa565b604051610307919061580b565b60405180910390f35b610318610eb4565b604051610325919061580b565b60405180910390f35b610336610ec4565b604051610343919061593c565b60405180910390f35b610366600480360381019061036191906147b5565b610ecd565b604051610373919061549b565b60405180910390f35b610384610f79565b005b6103a0600480360381019061039b919061486d565b610fdd565b6040516103ad919061580b565b60405180910390f35b6103d060048036038101906103cb91906148bf565b611049565b6040516103dd919061580b565b60405180910390f35b6103ee61106c565b6040516103fb919061549b565b60405180910390f35b61040c611083565b604051610419919061580b565b60405180910390f35b61043c600480360381019061043791906146d8565b611157565b005b610458600480360381019061045391906146d8565b611620565b604051610465919061580b565b60405180910390f35b610488600480360381019061048391906146d8565b611668565b60405161049c9897969594939291906158bd565b60405180910390f35b6104ad6116fb565b005b6104b761175f565b6040516104c49190615420565b60405180910390f35b6104d5611785565b6040516104e291906154b6565b60405180910390f35b61050560048036038101906105009190614843565b611817565b005b610521600480360381019061051c91906147b5565b611a4b565b60405161052e919061549b565b60405180910390f35b610551600480360381019061054c919061486d565b611b36565b005b61056d600480360381019061056891906147b5565b6123d6565b60405161057a919061549b565b60405180910390f35b61059d6004803603810190610598919061486d565b6123f4565b005b6105a761258c565b6040516105b491906157ef565b60405180910390f35b6105c56126bb565b6040516105d291906157b8565b60405180910390f35b6105f560048036038101906105f0919061472a565b612809565b604051610602919061580b565b60405180910390f35b6106256004803603810190610620919061486d565b612890565b604051610632919061580b565b60405180910390f35b61065560048036038101906106509190614701565b612a87565b005b61065f612b5f565b60405161066c91906157d3565b60405180910390f35b60606003805461068490615b6a565b80601f01602080910402602001604051908101604052809291908181526020018280546106b090615b6a565b80156106fd5780601f106106d2576101008083540402835291602001916106fd565b820191906000526020600020905b8154815290600101906020018083116106e057829003601f168201915b5050505050905090565b6000601854905090565b600061072561071e612dc1565b8484612dc9565b6001905092915050565b6000600254905090565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461079357600080fd5b80600860030160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60006107e7848484612f94565b6000600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000610832612dc1565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050828110156108b2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108a990615678565b60405180910390fd5b6108c6856108be612dc1565b858403612dc9565b60019150509392505050565b3273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461090a57600080fd5b61091261106c565b15610952576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610949906155f8565b60405180910390fd5b600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060080160009054906101000a900460ff166109e1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109d890615658565b60405180910390fd5b80600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001541015610a66576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a5d906155d8565b60405180910390fd5b6000600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518061010001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001600382015481526020016004820154815260200160058201604051806040016040529081600082015481526020016001820154815250508152602001600782015481526020016008820160009054906101000a900460ff16151515158152505090506000816000015111610bc7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bbe906156d8565b60405180910390fd5b6000610bfd8260000151610bef85610be142876001613215565b61329390919063ffffffff16565b6132a990919063ffffffff16565b90506000610c09611083565b905080821115610c4e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c4590615618565b60405180910390fd5b60008483610c5c9190615973565b90506000610c8d8560000151610c7f88886060015161329390919063ffffffff16565b6132a990919063ffffffff16565b905085600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000016000828254610ce19190615a54565b9250508190555080600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206003016000828254610d3a9190615a54565b9250508190555085601854610d4f9190615a54565b6018819055508360196000828254610d679190615973565b92505081905550846040015173ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33846040518363ffffffff1660e01b8152600401610dad929190615472565b602060405180830381600087803b158015610dc757600080fd5b505af1158015610ddb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dff91906147f1565b610e3e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e3590615718565b60405180910390fd5b610e4833826132bf565b3373ffffffffffffffffffffffffffffffffffffffff167fbc0fb706d03a6cb96fbe31862998338850cd01d239a360045dbe469d548e42188660000151848860400151604051610e9a93929190615886565b60405180910390a2505050505050565b6000601954905090565b6000610ebf42613496565b905090565b60006012905090565b6000610f6f610eda612dc1565b848460016000610ee8612dc1565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610f6a9190615973565b612dc9565b6001905092915050565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610fd357600080fd5b610fdb613554565b565b6000600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461103957600080fd5b61104282613496565b9050919050565b600080611055836135f6565b905061106384826000613215565b91505092915050565b6000600560149054906101000a900460ff16905090565b600080600860030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016110e49190615405565b60206040518083038186803b1580156110fc57600080fd5b505afa158015611110573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111349190614896565b9050600061114d6018548361377090919063ffffffff16565b9050809250505090565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146111b157600080fd5b600660008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060080160009054906101000a900460ff16611240576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161123790615658565b60405180910390fd5b6000600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000154116112c5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112bc90615558565b60405180910390fd5b600080600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001549150600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600301549050600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb84600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001546040518363ffffffff1660e01b8152600401611431929190615472565b602060405180830381600087803b15801561144b57600080fd5b505af115801561145f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061148391906147f1565b6114c2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114b990615718565b60405180910390fd5b6000600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001819055506000600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060080160006101000a81548160ff0219169083151502179055506000600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060030181905550816018546115bb9190615a54565b6018819055506115cb83826132bf565b8273ffffffffffffffffffffffffffffffffffffffff167fbb757047c2b5f3974fe26b7c10f732e7bce710b0952a71082702781e62ae0595828460405161161392919061585d565b60405180910390a2505050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60066020528060005260406000206000915090508060000154908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060030154908060040154908060050160405180604001604052908160008201548152602001600182015481525050908060070154908060080160009054906101000a900460ff16905088565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461175557600080fd5b61175d613786565b565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60606004805461179490615b6a565b80601f01602080910402602001604051908101604052809291908181526020018280546117c090615b6a565b801561180d5780601f106117e25761010080835404028352916020019161180d565b820191906000526020600020905b8154815290600101906020018083116117f057829003601f168201915b5050505050905090565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461187157600080fd5b8060000135600860000181905550806020013560086001018190555080604001356008600201819055508060600160208101906118ae919061481a565b600860030160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060800135600860040181905550601a60009054906101000a900460ff16156119335760086004015460088001546119299190615973565b6008600901819055505b601a60009054906101000a900460ff166119ea578060c001356008600601819055508060e001356008600701819055506000600860070154148061197e575060086007015460185410155b80156119a15750600060086006015414806119a0575060086006015460075410155b5b156119e9576001601a60006101000a81548160ff02191690831515021790555042600880018190555060086004015460088001546119df9190615973565b6008600901819055505b5b8060a0013560086005018190555080610100016008600a018181611a0e9190615ca9565b9050508061014001356008600c018190555080610160016008600d018181611a369190615ca9565b905050806101a001356008600f018190555050565b60008060016000611a5a612dc1565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905082811015611b17576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b0e90615778565b60405180910390fd5b611b2b611b22612dc1565b85858403612dc9565b600191505092915050565b3273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611b6e57600080fd5b611b7661106c565b15611bb6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bad906155f8565b60405180910390fd5b600860000154811015611bfe576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bf590615598565b60405180910390fd5b60006008600501541480611c1757506008600501548111155b611c56576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c4d906156f8565b60405180910390fd5b60086001015481601854611c6a9190615973565b1115611cab576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ca290615638565b60405180910390fd5b601a60009054906101000a900460ff161580611ccb575060086009015442105b611d0a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d0190615538565b60405180910390fd5b60086002015460195410611d53576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d4a90615758565b60405180910390fd5b6000611d5e826135f6565b90508160186000828254611d729190615973565b92505081905550600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060080160009054906101000a900460ff16611de857600160076000828254611de09190615973565b925050819055505b601a60009054906101000a900460ff16158015611e1c575060006008600701541480611e1b575060086007015460185410155b5b8015611e3f575060006008600601541480611e3e575060086006015460075410155b5b15611e87576001601a60006101000a81548160ff0219169083151502179055504260088001819055506008600401546008800154611e7d9190615973565b6008600901819055505b600860030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd3330856040518463ffffffff1660e01b8152600401611ee99392919061543b565b602060405180830381600087803b158015611f0357600080fd5b505af1158015611f17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f3b91906147f1565b611f7a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f7190615718565b60405180910390fd5b611f88338260600151613829565b600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060080160009054906101000a900460ff166121375780600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550606082015181600301556080820151816004015560a0820151816005016000820151816000015560208201518160010155505060c0820151816007015560e08201518160080160006101000a81548160ff0219169083151502179055509050506001600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060080160006101000a81548160ff021916908315150217905550612357565b612256600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518061010001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001600382015481526020016004820154815260200160058201604051806040016040529081600082015481526020016001820154815250508152602001600782015481526020016008820160009054906101000a900460ff16151515158152505082613989565b600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600701819055508060000151600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160008282546122f29190615973565b925050819055508060600151600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600301600082825461234f9190615973565b925050819055505b3373ffffffffffffffffffffffffffffffffffffffff167ff65271afc35201e83c229b7b581d7fde59bfe7b7dd943e8719fc8c5f5ada63f683600860030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1684606001516040516123ca93929190615826565b60405180910390a25050565b60006123ea6123e3612dc1565b8484612f94565b6001905092915050565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461244e57600080fd5b612456611083565b811115612498576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161248f90615618565b60405180910390fd5b600860030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33836040518363ffffffff1660e01b81526004016124f8929190615472565b602060405180830381600087803b15801561251257600080fd5b505af1158015612526573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061254a91906147f1565b612589576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161258090615718565b60405180910390fd5b50565b612594614516565b6008604051806101c00160405290816000820154815260200160018201548152602001600282015481526020016003820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001600482015481526020016005820154815260200160068201548152602001600782015481526020016008820154815260200160098201548152602001600a8201604051806040016040529081600082015481526020016001820154815250508152602001600c8201548152602001600d8201604051806040016040529081600082015481526020016001820154815250508152602001600f82015481525050905090565b6126c36145a7565b601a60009054906101000a900460ff1615806126e757506008800154600860090154145b806126f457506000601854145b156127175760405180604001604052806000815260200160018152509050612806565b60006301e13380905060006008600a0160000154148015612740575060006008600d0160000154145b8015612751575060006008600c0154145b8015612762575060006008600f0154145b156127fa5760006127ae612788600880015460086009015461377090919063ffffffff16565b6127a08460086002015461329390919063ffffffff16565b6132a990919063ffffffff16565b905060405180604001604052806127e56018546127d7620186a08661329390919063ffffffff16565b6132a990919063ffffffff16565b8152602001620186a081525092505050612806565b612802613a11565b9150505b90565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b60003273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146128ca57600080fd5b600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060080160009054906101000a900460ff16612959576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161295090615658565b60405180910390fd5b6000600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518061010001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001600382015481526020016004820154815260200160058201604051806040016040529081600082015481526020016001820154815250508152602001600782015481526020016008820160009054906101000a900460ff1615151515815250509050612a7f83826001613215565b915050919050565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612ae157600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415612b1b57600080fd5b80600560006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b612b676145c1565b6000600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518061010001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001600382015481526020016004820154815260200160058201604051806040016040529081600082015481526020016001820154815250508152602001600782015481526020016008820160009054906101000a900460ff16151515158152505090508060e00151612d25576040518061010001604052806000815260200160008152602001600860030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000815260200160008152602001604051806040016040528060008152602001600181525081526020016000815260200160001515815250915050612dbe565b601a60009054906101000a900460ff1615612db957612d4642826001613215565b8160800181815250506040518060400160405280612da48360000151612d96620186a0612d886301e133808860c00151612d809190615973565b886001613215565b61329390919063ffffffff16565b6132a990919063ffffffff16565b8152602001620186a08152508160a001819052505b809150505b90565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415612e39576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612e3090615738565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415612ea9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612ea090615578565b60405180910390fd5b80600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92583604051612f87919061580b565b60405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415613004576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612ffb906156b8565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415613074576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161306b906154d8565b60405180910390fd5b61307f838383613b22565b60008060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905081811015613105576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016130fc906155b8565b60405180910390fd5b8181036000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546131989190615973565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516131fc919061580b565b60405180910390a361320f848484613b27565b50505050565b6000806008600a0160000154148015613236575060006008600d0160000154145b8015613247575060006008600c0154145b8015613258575060006008600f0154145b1561327e576132776008600201548585606001518660c001518661425f565b905061328c565b613289848484614319565b90505b9392505050565b600081836132a191906159fa565b905092915050565b600081836132b791906159c9565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141561332f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161332690615698565b60405180910390fd5b61333b82600083613b22565b60008060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050818110156133c1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016133b890615518565b60405180910390fd5b8181036000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600260008282546134189190615a54565b92505081905550600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161347d919061580b565b60405180910390a361349183600084613b27565b505050565b6000601a60009054906101000a900460ff1615806134bc57506008800154600860090154145b806134c957506000601854145b156134d7576000905061354f565b600061354860195461353a6134fe600880015460086009015461377090919063ffffffff16565b61352c61351860088001548961377090919063ffffffff16565b60086002015461329390919063ffffffff16565b6132a990919063ffffffff16565b61377090919063ffffffff16565b9050809150505b919050565b61355c61106c565b61359b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613592906154f8565b60405180910390fd5b6000600560146101000a81548160ff0219169083151502179055507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6135df612dc1565b6040516135ec9190615405565b60405180910390a1565b6135fe6145c1565b6000804290506000601854148061361c5750600061361a61072f565b145b15613629578391506136d8565b60006136a46136686008800154600261364291906159fa565b61365a8560086009015461450090919063ffffffff16565b61377090919063ffffffff16565b613696613687600880015460086009015461377090919063ffffffff16565b8861329390919063ffffffff16565b6132a990919063ffffffff16565b90506136d46018546136c66136b761072f565b8461329390919063ffffffff16565b6132a990919063ffffffff16565b9250505b604051806101000160405280858152602001828152602001600860030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200183815260200160008152602001604051806040016040528060008152602001600181525081526020018281526020016001151581525092505050919050565b6000818361377e9190615a54565b905092915050565b61378e61106c565b156137ce576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016137c5906155f8565b60405180910390fd5b6001600560146101000a81548160ff0219169083151502179055507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258613812612dc1565b60405161381f9190615405565b60405180910390a1565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415613899576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161389090615798565b60405180910390fd5b6138a560008383613b22565b80600260008282546138b79190615973565b92505081905550806000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825461390c9190615973565b925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051613971919061580b565b60405180910390a361398560008383613b27565b5050565b6000806139d36139aa84606001518560c0015161329390919063ffffffff16565b6139c586606001518760c0015161329390919063ffffffff16565b61450090919063ffffffff16565b905060006139f28460600151866060015161450090919063ffffffff16565b9050613a0781836132a990919063ffffffff16565b9250505092915050565b613a196145a7565b60006301e13380905060006040518061010001604052806018548152602001428152602001600860030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001613a8761072f565b815260200160008152602001604051806040016040528060008152602001600181525081526020014281526020016001151581525090506000613ad78342613acf9190615973565b836001614319565b90506040518060400160405280613b0e601854613b00620186a08661329390919063ffffffff16565b6132a990919063ffffffff16565b8152602001620186a0815250935050505090565b505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415613b615761425a565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415613b9b5761425a565b6000600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518061010001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001600382015481526020016004820154815260200160058201604051806040016040529081600082015481526020016001820154815250508152602001600782015481526020016008820160009054906101000a900460ff16151515158152505090506000613d60600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060030154613d5285600660008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000015461329390919063ffffffff16565b6132a990919063ffffffff16565b905060018260e00190151590811515815250508282606001818152505080826000018181525050600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060080160009054906101000a900460ff16613f8d5781600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550606082015181600301556080820151816004015560a0820151816005016000820151816000015560208201518160010155505060c0820151816007015560e08201518160080160006101000a81548160ff02191690831515021790555090505082600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206003016000828254613f289190615a54565b9250508190555080600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000016000828254613f819190615a54565b92505081905550614257565b6140ac600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518061010001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001600382015481526020016004820154815260200160058201604051806040016040529081600082015481526020016001820154815250508152602001600782015481526020016008820160009054906101000a900460ff16151515158152505083613989565b600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206007018190555082600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060030160008282546141449190615973565b9250508190555080600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001600082825461419d9190615973565b9250508190555082600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060030160008282546141f69190615a54565b9250508190555080600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001600082825461424f9190615a54565b925050819055505b50505b505050565b6000806142c6614281600880015460086009015461377090919063ffffffff16565b6142b8614297878a61377090919063ffffffff16565b6142aa8b8a61329390919063ffffffff16565b61329390919063ffffffff16565b6132a990919063ffffffff16565b90506000836142ee576142e9866142db61072f565b61450090919063ffffffff16565b6142f7565b6142f661072f565b5b905061430c81836132a990919063ffffffff16565b9250505095945050505050565b60008060008460c00151905060006143616008600a01600101546143536008600a016000015460086002015461329390919063ffffffff16565b6132a990919063ffffffff16565b9050866008600c0154836143759190615973565b106143955761438b81888860600151858961425f565b93505050506144f9565b6143b6816008600c0154846143aa9190615973565b8860600151858961425f565b836143c19190615973565b92506008600c0154826143d49190615973565b91506144106008600d01600101546144026008600d016000015460086002015461329390919063ffffffff16565b6132a990919063ffffffff16565b8161441b9190615973565b905060006008600f015414806144415750866008600f01548361443e9190615973565b11155b1561447b57600860020154905061447161446282898960600151868a61425f565b8461450090919063ffffffff16565b93505050506144f9565b6144c76008600f01546144b9848a6144939190615a54565b6144ab8560086002015461377090919063ffffffff16565b61329390919063ffffffff16565b6132a990919063ffffffff16565b816144d29190615973565b90506144e581888860600151858961425f565b836144f09190615973565b92508293505050505b9392505050565b6000818361450e9190615973565b905092915050565b604051806101c00160405280600081526020016000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001614586614624565b81526020016000815260200161459a614624565b8152602001600081525090565b604051806040016040528060008152602001600081525090565b6040518061010001604052806000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600081526020016000815260200161460e6145a7565b8152602001600081526020016000151581525090565b604051806040016040528060008152602001600081525090565b60008135905061464d81615d12565b92915050565b60008135905061466281615d29565b92915050565b60008151905061467781615d40565b92915050565b60008135905061468c81615d57565b92915050565b60006101c082840312156146a557600080fd5b81905092915050565b6000813590506146bd81615d6e565b92915050565b6000815190506146d281615d6e565b92915050565b6000602082840312156146ea57600080fd5b60006146f88482850161463e565b91505092915050565b60006020828403121561471357600080fd5b600061472184828501614653565b91505092915050565b6000806040838503121561473d57600080fd5b600061474b8582860161463e565b925050602061475c8582860161463e565b9150509250929050565b60008060006060848603121561477b57600080fd5b60006147898682870161463e565b935050602061479a8682870161463e565b92505060406147ab868287016146ae565b9150509250925092565b600080604083850312156147c857600080fd5b60006147d68582860161463e565b92505060206147e7858286016146ae565b9150509250929050565b60006020828403121561480357600080fd5b600061481184828501614668565b91505092915050565b60006020828403121561482c57600080fd5b600061483a8482850161467d565b91505092915050565b60006101c0828403121561485657600080fd5b600061486484828501614692565b91505092915050565b60006020828403121561487f57600080fd5b600061488d848285016146ae565b91505092915050565b6000602082840312156148a857600080fd5b60006148b6848285016146c3565b91505092915050565b600080604083850312156148d257600080fd5b60006148e0858286016146ae565b92505060206148f1858286016146ae565b9150509250929050565b61490481615a9a565b82525050565b61491381615a88565b82525050565b61492281615aac565b82525050565b61493181615aac565b82525050565b61494081615b01565b82525050565b61494f81615b01565b82525050565b600061496082615957565b61496a8185615962565b935061497a818560208601615b37565b61498381615c49565b840191505092915050565b600061499b602383615962565b91507f45524332303a207472616e7366657220746f20746865207a65726f206164647260008301527f65737300000000000000000000000000000000000000000000000000000000006020830152604082019050919050565b6000614a01601483615962565b91507f5061757361626c653a206e6f74207061757365640000000000000000000000006000830152602082019050919050565b6000614a41602283615962565b91507f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60008301527f63650000000000000000000000000000000000000000000000000000000000006020830152604082019050919050565b6000614aa7601c83615962565b91507f546865207374616b696e6720706572696f642068617320656e646564000000006000830152602082019050919050565b6000614ae7602683615962565b91507f43616e206e6f7420616e79207374616b6520666f7220737570706c696564206160008301527f64647265737300000000000000000000000000000000000000000000000000006020830152604082019050919050565b6000614b4d602283615962565b91507f45524332303a20617070726f766520746f20746865207a65726f20616464726560008301527f73730000000000000000000000000000000000000000000000000000000000006020830152604082019050919050565b6000614bb3601e83615962565b91507f416d6f756e742062656c6f7720746865206d696e696d756d207374616b6500006000830152602082019050919050565b6000614bf3602683615962565b91507f45524332303a207472616e7366657220616d6f756e742065786365656473206260008301527f616c616e636500000000000000000000000000000000000000000000000000006020830152604082019050919050565b6000614c59602783615962565b91507f43616e206e6f74207769746864726177206d6f7265207468616e20616374756160008301527f6c207374616b65000000000000000000000000000000000000000000000000006020830152604082019050919050565b6000614cbf601083615962565b91507f5061757361626c653a20706175736564000000000000000000000000000000006000830152602082019050919050565b6000614cff602f83615962565b91507f54686520636f6e747261637420646f6573206e6f74206861766520656e6f756760008301527f682072657761726420746f6b656e7300000000000000000000000000000000006020830152604082019050919050565b6000614d65602e83615962565b91507f596f752063616e206e6f742065786365656564206d6178696d756d207375707060008301527f6c7920666f72207374616b696e670000000000000000000000000000000000006020830152604082019050919050565b6000614dcb601d83615962565b91507f43616e206e6f742066696e64207374616b6520666f722073656e6465720000006000830152602082019050919050565b6000614e0b602883615962565b91507f45524332303a207472616e7366657220616d6f756e742065786365656473206160008301527f6c6c6f77616e63650000000000000000000000000000000000000000000000006020830152604082019050919050565b6000614e71602183615962565b91507f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360008301527f73000000000000000000000000000000000000000000000000000000000000006020830152604082019050919050565b6000614ed7602583615962565b91507f45524332303a207472616e736665722066726f6d20746865207a65726f20616460008301527f64726573730000000000000000000000000000000000000000000000000000006020830152604082019050919050565b6000614f3d601783615962565b91507f5374616b6520616c72656461792077697468647261776e0000000000000000006000830152602082019050919050565b6000614f7d601c83615962565b91507f616d6f756e742065786365656473206d6178696d756d207374616b65000000006000830152602082019050919050565b6000614fbd603183615962565b91507f636f756c646e202774207472616e7366657220746f6b656e732066726f6d207360008301527f656e64657220746f20636f6e74726163740000000000000000000000000000006020830152604082019050919050565b6000615023602483615962565b91507f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460008301527f72657373000000000000000000000000000000000000000000000000000000006020830152604082019050919050565b6000615089602183615962565b91507f416c6c20726577617264732068617665206265656e206469737472696275746560008301527f64000000000000000000000000000000000000000000000000000000000000006020830152604082019050919050565b60006150ef602583615962565b91507f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760008301527f207a65726f0000000000000000000000000000000000000000000000000000006020830152604082019050919050565b6000615155601f83615962565b91507f45524332303a206d696e7420746f20746865207a65726f2061646472657373006000830152602082019050919050565b60408201600082015161519e60008501826153d8565b5060208201516151b160208501826153d8565b50505050565b6040820160008201516151cd60008501826153d8565b5060208201516151e060208501826153d8565b50505050565b6040820160008201516151fc60008501826153d8565b50602082015161520f60208501826153d8565b50505050565b6101208201600082015161522c60008501826153d8565b50602082015161523f60208501826153d8565b5060408201516152526040850182614937565b50606082015161526560608501826153d8565b50608082015161527860808501826153d8565b5060a082015161528b60a0850182615188565b5060c082015161529e60e08501826153d8565b5060e08201516152b2610100850182614919565b50505050565b610200820160008201516152cf60008501826153d8565b5060208201516152e260208501826153d8565b5060408201516152f560408501826153d8565b5060608201516153086060850182614937565b50608082015161531b60808501826153d8565b5060a082015161532e60a08501826153d8565b5060c082015161534160c08501826153d8565b5060e082015161535460e08501826153d8565b506101008201516153696101008501826153d8565b5061012082015161537e6101208501826153d8565b506101408201516153936101408501826151e6565b506101608201516153a86101808501826153d8565b506101808201516153bd6101a08501826151e6565b506101a08201516153d26101e08501826153d8565b50505050565b6153e181615aea565b82525050565b6153f081615aea565b82525050565b6153ff81615af4565b82525050565b600060208201905061541a600083018461490a565b92915050565b600060208201905061543560008301846148fb565b92915050565b6000606082019050615450600083018661490a565b61545d602083018561490a565b61546a60408301846153e7565b949350505050565b6000604082019050615487600083018561490a565b61549460208301846153e7565b9392505050565b60006020820190506154b06000830184614928565b92915050565b600060208201905081810360008301526154d08184614955565b905092915050565b600060208201905081810360008301526154f18161498e565b9050919050565b60006020820190508181036000830152615511816149f4565b9050919050565b6000602082019050818103600083015261553181614a34565b9050919050565b6000602082019050818103600083015261555181614a9a565b9050919050565b6000602082019050818103600083015261557181614ada565b9050919050565b6000602082019050818103600083015261559181614b40565b9050919050565b600060208201905081810360008301526155b181614ba6565b9050919050565b600060208201905081810360008301526155d181614be6565b9050919050565b600060208201905081810360008301526155f181614c4c565b9050919050565b6000602082019050818103600083015261561181614cb2565b9050919050565b6000602082019050818103600083015261563181614cf2565b9050919050565b6000602082019050818103600083015261565181614d58565b9050919050565b6000602082019050818103600083015261567181614dbe565b9050919050565b6000602082019050818103600083015261569181614dfe565b9050919050565b600060208201905081810360008301526156b181614e64565b9050919050565b600060208201905081810360008301526156d181614eca565b9050919050565b600060208201905081810360008301526156f181614f30565b9050919050565b6000602082019050818103600083015261571181614f70565b9050919050565b6000602082019050818103600083015261573181614fb0565b9050919050565b6000602082019050818103600083015261575181615016565b9050919050565b600060208201905081810360008301526157718161507c565b9050919050565b60006020820190508181036000830152615791816150e2565b9050919050565b600060208201905081810360008301526157b181615148565b9050919050565b60006040820190506157cd60008301846151b7565b92915050565b6000610120820190506157e96000830184615215565b92915050565b60006102008201905061580560008301846152b8565b92915050565b600060208201905061582060008301846153e7565b92915050565b600060608201905061583b60008301866153e7565b6158486020830185614946565b61585560408301846153e7565b949350505050565b600060408201905061587260008301856153e7565b61587f60208301846153e7565b9392505050565b600060608201905061589b60008301866153e7565b6158a860208301856153e7565b6158b56040830184614946565b949350505050565b6000610120820190506158d3600083018b6153e7565b6158e0602083018a6153e7565b6158ed6040830189614946565b6158fa60608301886153e7565b61590760808301876153e7565b61591460a08301866151b7565b61592160e08301856153e7565b61592f610100830184614928565b9998505050505050505050565b600060208201905061595160008301846153f6565b92915050565b600081519050919050565b600082825260208201905092915050565b600061597e82615aea565b915061598983615aea565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156159be576159bd615b9c565b5b828201905092915050565b60006159d482615aea565b91506159df83615aea565b9250826159ef576159ee615bcb565b5b828204905092915050565b6000615a0582615aea565b9150615a1083615aea565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615615a4957615a48615b9c565b5b828202905092915050565b6000615a5f82615aea565b9150615a6a83615aea565b925082821015615a7d57615a7c615b9c565b5b828203905092915050565b6000615a9382615aca565b9050919050565b6000615aa582615aca565b9050919050565b60008115159050919050565b6000615ac382615a88565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b6000615b0c82615b13565b9050919050565b6000615b1e82615aca565b9050919050565b6000615b3082615aea565b9050919050565b60005b83811015615b55578082015181840152602081019050615b3a565b83811115615b64576000848401525b50505050565b60006002820490506001821680615b8257607f821691505b60208210811415615b9657615b95615bfa565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000819050919050565b60008135615c4081615d6e565b80915050919050565b6000601f19601f8301169050919050565b60008160001b9050919050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff615c9384615c5a565b9350801983169250808416831791505092915050565b600081016000830180615cbb81615c33565b9050615cc78184615cef565b505050600181016020830180615cdc81615c33565b9050615ce88184615cef565b5050505050565b615cf882615b25565b615d0b615d0482615c29565b8354615c67565b8255505050565b615d1b81615a88565b8114615d2657600080fd5b50565b615d3281615a9a565b8114615d3d57600080fd5b50565b615d4981615aac565b8114615d5457600080fd5b50565b615d6081615ab8565b8114615d6b57600080fd5b50565b615d7781615aea565b8114615d8257600080fd5b5056fea2646970667358221220afecb0b0dd0e73ee4bd971c9bbd3ae530612cceed388cf838f1f5eb5cdbfdbb964736f6c63430008000033

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

0000000000000000000000002e85ae1c47602f7927bcabc2ff99c40aa222ae15

-----Decoded View---------------
Arg [0] : stakingTokenAddress (address): 0x2e85ae1C47602f7927bCabc2Ff99C40aA222aE15

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000002e85ae1c47602f7927bcabc2ff99c40aa222ae15


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.