ETH Price: $3,411.00 (+2.99%)

Contract

0x078Ef23F8e56951AF537BE272484711Ab61e5632
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Claim Tokens212520482024-11-23 17:51:235 hrs ago1732384283IN
0x078Ef23F...Ab61e5632
0 ETH0.0181353517.95942377
Claim Tokens212503832024-11-23 12:16:3510 hrs ago1732364195IN
0x078Ef23F...Ab61e5632
0 ETH0.0106797510.5252937
Claim Tokens212499242024-11-23 10:44:3512 hrs ago1732358675IN
0x078Ef23F...Ab61e5632
0 ETH0.0110205511.24001221
Claim Tokens212497502024-11-23 10:09:3512 hrs ago1732356575IN
0x078Ef23F...Ab61e5632
0 ETH0.00989669.92066194
Claim Tokens212485752024-11-23 6:14:1116 hrs ago1732342451IN
0x078Ef23F...Ab61e5632
0 ETH0.0102963310.37134321
Claim Tokens212450602024-11-22 18:28:5928 hrs ago1732300139IN
0x078Ef23F...Ab61e5632
0 ETH0.0057594411.8854646
Claim Tokens212450472024-11-22 18:26:2328 hrs ago1732299983IN
0x078Ef23F...Ab61e5632
0 ETH0.0030600312.51145543
Claim All Tokens212390662024-11-21 22:22:472 days ago1732227767IN
0x078Ef23F...Ab61e5632
0 ETH0.0289697813.2470423
Claim Tokens212359882024-11-21 12:05:112 days ago1732190711IN
0x078Ef23F...Ab61e5632
0 ETH0.0150329715.20928539
Claim Tokens212341672024-11-21 5:58:232 days ago1732168703IN
0x078Ef23F...Ab61e5632
0 ETH0.0108156111.27701363
Claim Tokens212340142024-11-21 5:27:232 days ago1732166843IN
0x078Ef23F...Ab61e5632
0 ETH0.0105653110.82306284
Claim Tokens212309112024-11-20 19:03:353 days ago1732129415IN
0x078Ef23F...Ab61e5632
0 ETH0.0186421418.86078127
Claim Tokens212293872024-11-20 13:55:593 days ago1732110959IN
0x078Ef23F...Ab61e5632
0 ETH0.0139349114.2748715
Claim All Tokens212285002024-11-20 10:57:473 days ago1732100267IN
0x078Ef23F...Ab61e5632
0 ETH0.019979989.88017096
Claim Tokens212268072024-11-20 5:17:233 days ago1732079843IN
0x078Ef23F...Ab61e5632
0 ETH0.0097593610.04777522
Claim Tokens212229662024-11-19 16:26:474 days ago1732033607IN
0x078Ef23F...Ab61e5632
0 ETH0.0215874622.11112731
Claim Tokens212193022024-11-19 4:11:234 days ago1731989483IN
0x078Ef23F...Ab61e5632
0 ETH0.008964599.22952014
Claim Tokens212185142024-11-19 1:33:234 days ago1731980003IN
0x078Ef23F...Ab61e5632
0 ETH0.008434768.84021663
Claim Tokens212168432024-11-18 19:58:115 days ago1731959891IN
0x078Ef23F...Ab61e5632
0 ETH0.0155220515.70333126
Claim Tokens212145782024-11-18 12:23:115 days ago1731932591IN
0x078Ef23F...Ab61e5632
0 ETH0.0104175710.67172325
Claim Tokens212145252024-11-18 12:12:355 days ago1731931955IN
0x078Ef23F...Ab61e5632
0 ETH0.0129254913.0761325
Claim All Tokens212144732024-11-18 12:02:115 days ago1731931331IN
0x078Ef23F...Ab61e5632
0 ETH0.0276626612.49120167
Claim Tokens212144472024-11-18 11:56:595 days ago1731931019IN
0x078Ef23F...Ab61e5632
0 ETH0.0122453512.54409734
Claim Tokens212136562024-11-18 9:18:235 days ago1731921503IN
0x078Ef23F...Ab61e5632
0 ETH0.0107667911.28434363
Claim Tokens212134322024-11-18 8:33:235 days ago1731918803IN
0x078Ef23F...Ab61e5632
0 ETH0.0114316211.71051137
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:
TokenVesting

Compiler Version
v0.8.9+commit.e5eed63a

Optimization Enabled:
Yes with 9999 runs

Other Settings:
default evmVersion, MIT license
File 1 of 8 : TokenVesting.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import './access/Ownable2Step.sol';

error TokenVesting_AddressIsZero();
error TokenVesting_AmountExcessive(uint256 amount, uint256 limit);
error TokenVesting_AmountZero();
error TokenVesting_BeneficiaryNoneActiveVestings();
error TokenVesting_ContractIsPaused(bool isPaused);
error TokenVesting_Error(string msg);

/**
 * @title Token Vesting Contract
 */
contract TokenVesting is Ownable2Step {
    using SafeERC20 for IERC20;
    /**
     * @dev Event is triggered when vesting schedule is changed
     * @param _name string vesting schedule name
     * @param _amount uint256 vesting schedule amount
     */
    event VestingScheduleCreated(string _name, uint256 _amount);

    /**
     * @dev Event is triggered when vesting schedule is revoked
     * @param _name string vesting schedule name
     */
    event VestingScheduleRevoked(string _name);

    /**
     * @dev Event is triggered when allocation added
     * @param _beneficiary address of beneficiary
     * @param _vestingScheduleName string vesting schedule name
     * @param _amount uint256 amount of tokens
     * @param _currentAllocation uint256 current allocation for vesting schedule
     */
    event AllocationAdded(
        address _beneficiary,
        string _vestingScheduleName,
        uint256 _amount,
        uint256 _currentAllocation
    );

    /**
     * @dev Event is triggered when allocation removed
     * @param _beneficiary address of beneficiary
     * @param _vestingScheduleName string vesting schedule name
     * @param _amount uint256 amount of tokens
     * @param _currentAllocation uint256 current allocation for vesting schedule
     */
    event AllocationRemoved(
        address _beneficiary,
        string _vestingScheduleName,
        uint256 _amount,
        uint256 _currentAllocation
    );

    /**
     * @dev Event is triggered when contract paused or unpaused
     * @param _paused bool is paused
     */
    event ContractPaused(bool _paused);

    /**
     * @dev Event is triggered when beneficiary deleted
     * @param _beneficiary address of beneficiary
     */
    event BeneficiaryDeleted(address _beneficiary);

    /**
     * @dev Event is triggered when tokens claimed
     * @param _beneficiary address of beneficiary
     * @param _vestingScheduleName string vesting schedule name
     * @param _amount uint256 amount of tokens
     * @param _releasedAmount uint256 released amount of beneficiary tokens for current vesting schedule
     */
    event TokensClaimed(address _beneficiary, string _vestingScheduleName, uint256 _amount, uint256 _releasedAmount);

    struct VestingSchedule {
        string name;
        uint256 terms;
        uint256 cliff;
        uint256 duration;
        uint256 totalAmount;
        uint256 allocatedAmount;
        uint256 releasedAmount;
        bool initialized;
        bool revoked;
    }

    struct Vesting {
        string name;
        uint256 amount;
        uint256 timestamp;
    }

    struct VestingExpectation {
        Vesting vesting;
        uint256 beneficiaryAmount;
    }

    struct BeneficiaryOverview {
        string name;
        uint256 terms;
        uint256 cliff;
        uint256 duration;
        uint256 allocatedAmount;
        uint256 withdrawnAmount;
    }

    struct Beneficiary {
        uint256 allocatedAmount;
        uint256 withdrawnAmount;
    }

    IERC20 private immutable token;
    string[] private vestingSchedulesNames;
    uint256 private vestingSchedulesTotalReservedAmount;
    uint256 private validVestingSchedulesCount;
    uint256 public tgeTimestamp;
    address public treasuryAddress;
    bool public paused;
    mapping(string => VestingSchedule) private vestingSchedules;
    mapping(address => mapping(string => Beneficiary)) private beneficiaries;

    constructor(
        address _tokenContractAddress,
        uint256 _tgeTimestamp,
        address _treasuryAddress
    ) {
        if (_tokenContractAddress == address(0x0)) {
            revert TokenVesting_AddressIsZero();
        }
        if (_tgeTimestamp == 0) {
            revert TokenVesting_Error('The TGE Timestamp is zero!');
        }
        if (_treasuryAddress == address(0x0)) {
            revert TokenVesting_AddressIsZero();
        }
        token = IERC20(_tokenContractAddress);
        tgeTimestamp = _tgeTimestamp;
        treasuryAddress = _treasuryAddress;
    }

    /**
     * @dev Revokes all schedules and sends tokens to a set address
     */
    function emergencyWithdrawal() external onlyOwner {
        if (token.balanceOf(address(this)) == 0) {
            revert TokenVesting_Error('Nothing to withdraw!');
        }
        string[] memory vestingScheduleNames = getValidVestingScheduleNames();
        uint256 scheduleNamesLength = vestingScheduleNames.length;
        for (uint256 i = 0; i < scheduleNamesLength; i++) {
            _revokeVestingSchedule(vestingScheduleNames[i]);
        }
        token.safeTransfer(treasuryAddress, token.balanceOf(address(this)));
    }

    /**
     * @dev Pauses contract
     */
    function pauseContract() external onlyOwner {
        if (paused) {
            revert TokenVesting_ContractIsPaused(paused);
        }
        paused = true;
        emit ContractPaused(paused);
    }

    /**
     * @dev Unpauses contract
     */
    function unpauseContract() external onlyOwner {
        if (!paused) {
            revert TokenVesting_ContractIsPaused(paused);
        }
        paused = false;
        emit ContractPaused(paused);
    }

    /**
     * @dev Gets ERC20 token address
     * @return address of token
     */
    function getToken() external view returns (address) {
        return address(token);
    }

    /**
     * @dev Creates a new vesting schedule
     * @param _name string vesting schedule name
     * @param _terms vesting schedule terms in seconds
     * @param _cliff cliff in seconds after which tokens will begin to vest
     * @param _duration the number of terms during which the tokens will be vested
     * @param _amount total amount of tokens to be released at the end of the vesting
     */
    function createVestingSchedule(
        string calldata _name,
        uint256 _terms,
        uint256 _cliff,
        uint256 _duration,
        uint256 _amount
    ) external onlyOwner {
        uint256 unusedAmount = getUnusedAmount();

        if (paused) {
            revert TokenVesting_ContractIsPaused(paused);
        }
        if (bytes(_name).length == 0) {
            revert TokenVesting_Error('The name is empty!');
        }
        if (!isNameUnique(_name)) {
            revert TokenVesting_Error('The name is duplicated!');
        }
        if (unusedAmount < _amount) {
            revert TokenVesting_AmountExcessive(_amount, unusedAmount);
        }
        if (_duration == 0) {
            revert TokenVesting_Error('The duration is zero!');
        }
        if (_amount == 0) {
            revert TokenVesting_AmountZero();
        }
        if (_terms == 0) {
            revert TokenVesting_Error('The terms are zero!');
        }
        vestingSchedules[_name] = VestingSchedule({
            name: _name,
            terms: _terms,
            cliff: _cliff,
            duration: _duration,
            totalAmount: _amount,
            allocatedAmount: 0,
            releasedAmount: 0,
            initialized: true,
            revoked: false
        });
        vestingSchedulesTotalReservedAmount += _amount;
        vestingSchedulesNames.push(_name);
        validVestingSchedulesCount++;
        emit VestingScheduleCreated(_name, _amount);
    }

    /**
     * @dev Revokes vesting schedule
     * @param _name string schedule name
     */
    function revokeVestingSchedule(string memory _name) external onlyOwner {
        if (paused) {
            revert TokenVesting_ContractIsPaused(paused);
        }
        _revokeVestingSchedule(_name);
    }

    /**
     * @dev Gets the vesting schedule information
     * @param _name string vesting schedule name
     * @return VestingSchedule structure information
     */
    function getVestingSchedule(string calldata _name) external view returns (VestingSchedule memory) {
        return vestingSchedules[_name];
    }

    /**
     * @dev Gets all vesting schedules
     * @return VestingSchedule structure list of all vesting schedules
     */
    function getAllVestingSchedules() external view returns (VestingSchedule[] memory) {
        uint256 scheduleNamesLength = vestingSchedulesNames.length;
        if (scheduleNamesLength == 0) {
            revert TokenVesting_Error('No vesting schedules!');
        }
        VestingSchedule[] memory allVestingSchedules = new VestingSchedule[](scheduleNamesLength);
        for (uint32 i = 0; i < scheduleNamesLength; i++) {
            allVestingSchedules[i] = vestingSchedules[vestingSchedulesNames[i]];
        }
        return allVestingSchedules;
    }

    /**
     * @dev Gets all valid vesting schedules
     * @return VestingSchedule structure list of all active vesting schedules
     */
    function getValidVestingSchedules() external view returns (VestingSchedule[] memory) {
        if (validVestingSchedulesCount == 0) {
            revert TokenVesting_Error('No valid vesting schedules!');
        }
        VestingSchedule[] memory validVestingSchedules = new VestingSchedule[](validVestingSchedulesCount);
        uint32 j;
        for (uint32 i = 0; i < validVestingSchedulesCount; i++) {
            if (isVestingScheduleValid(vestingSchedulesNames[i])) {
                validVestingSchedules[j] = vestingSchedules[vestingSchedulesNames[i]];
                j++;
            }
        }
        return validVestingSchedules;
    }

    /**
     * INDECISIVE do we need it?
     * @dev Gets vesting schedules count
     * @return uint256 number of vesting schedules
     */
    function getVestingSchedulesCount() external view returns (uint256) {
        return vestingSchedulesNames.length;
    }

    /**
     * INDECISIVE do we need it?
     * @dev Gets valid vesting schedules count
     * @return uint256 number of vesting schedules
     */
    function getValidVestingSchedulesCount() external view returns (uint256) {
        return validVestingSchedulesCount;
    }

    /**
     * @dev Increases vesting schedule total amount
     * @param _name string vesting schedule name
     * @param _amount uint256 amount of tokens
     */
    function increaseVestingScheduleTotalAmount(uint256 _amount, string calldata _name) external onlyOwner {
        if (paused) {
            revert TokenVesting_ContractIsPaused(paused);
        }
        if (isNameUnique(_name)) {
            revert TokenVesting_Error('The name doesnt exist!');
        }
        if (_amount == 0) {
            revert TokenVesting_AmountZero();
        }
        if (getUnusedAmount() < _amount) {
            revert TokenVesting_AmountExcessive(_amount, getUnusedAmount());
        }
        vestingSchedules[_name].totalAmount += _amount;
        vestingSchedulesTotalReservedAmount += _amount;
    }

    /**
     * @dev Decreases vesting schedule total amount
     * @param _name string vesting schedule name
     * @param _amount uint256 amount of tokens
     */
    function decreaseVestingScheduleTotalAmount(uint256 _amount, string calldata _name) external onlyOwner {
        if (paused) {
            revert TokenVesting_ContractIsPaused(paused);
        }
        if (isNameUnique(_name)) {
            revert TokenVesting_Error('The name doesnt exist!');
        }
        if (_amount == 0) {
            revert TokenVesting_AmountZero();
        }
        if (getScheduleUnallocatedAmount(_name) < _amount) {
            revert TokenVesting_AmountExcessive(_amount, getScheduleUnallocatedAmount(_name));
        }
        vestingSchedules[_name].totalAmount -= _amount;
        vestingSchedulesTotalReservedAmount -= _amount;
    }

    /**
     * @dev Adds beneficiary allocation
     * @param _beneficiary address of user
     * @param _vestingScheduleName string
     * @param _amount uint256 amount of tokens
     */
    function addBeneficiaryAllocation(
        address _beneficiary,
        string memory _vestingScheduleName,
        uint256 _amount
    ) external onlyOwner {
        if (paused) {
            revert TokenVesting_ContractIsPaused(paused);
        }
        if (_beneficiary == address(0x0)) {
            revert TokenVesting_AddressIsZero();
        }
        if (bytes(_vestingScheduleName).length == 0) {
            revert TokenVesting_Error('The name is empty!');
        }
        if (_amount == 0) {
            revert TokenVesting_AmountZero();
        }
        if (!isVestingScheduleValid(_vestingScheduleName)) {
            revert TokenVesting_Error('The schedule is invalid!');
        }
        if (getScheduleUnallocatedAmount(_vestingScheduleName) < _amount) {
            revert TokenVesting_AmountExcessive(_amount, getScheduleUnallocatedAmount(_vestingScheduleName));
        }

        beneficiaries[_beneficiary][_vestingScheduleName].allocatedAmount += _amount;
        vestingSchedules[_vestingScheduleName].allocatedAmount += _amount;

        emit AllocationAdded(
            _beneficiary,
            _vestingScheduleName,
            _amount,
            beneficiaries[_beneficiary][_vestingScheduleName].allocatedAmount
        );
    }

    /**
     * @dev Removes beneficiary allocation
     * @param _beneficiary address of user
     * @param _vestingScheduleName string
     * @param _amount uint256 amount of tokens
     */
    function removeBeneficiaryAllocation(
        address _beneficiary,
        string calldata _vestingScheduleName,
        uint256 _amount
    ) external onlyOwner {
        if (paused) {
            revert TokenVesting_ContractIsPaused(paused);
        }
        if (_beneficiary == address(0x0)) {
            revert TokenVesting_AddressIsZero();
        }
        if (_amount == 0) {
            revert TokenVesting_AmountZero();
        }
        if (bytes(_vestingScheduleName).length == 0) {
            revert TokenVesting_Error('The name is empty!');
        }
        if (!isVestingScheduleValid(_vestingScheduleName)) {
            revert TokenVesting_Error('The name is invalid!');
        }
        if (getBeneficiaryUnreleasedAmount(_beneficiary, _vestingScheduleName) < _amount) {
            revert TokenVesting_AmountExcessive(
                _amount,
                getBeneficiaryUnreleasedAmount(_beneficiary, _vestingScheduleName)
            );
        }
        beneficiaries[_beneficiary][_vestingScheduleName].allocatedAmount -= _amount;
        vestingSchedules[_vestingScheduleName].allocatedAmount -= _amount;

        emit AllocationRemoved(
            _beneficiary,
            _vestingScheduleName,
            _amount,
            beneficiaries[_beneficiary][_vestingScheduleName].allocatedAmount
        );
    }

    /**
     * @dev Gets beneficiary
     * @param _beneficiary address of user
     * @param _vestingScheduleName string vesting schedule name
     * @return Beneficiary struct
     */
    function getBeneficiary(address _beneficiary, string calldata _vestingScheduleName)
        external
        view
        returns (Beneficiary memory)
    {
        return beneficiaries[_beneficiary][_vestingScheduleName];
    }

    /**
     * @dev Deletes beneficiary
     * @param _beneficiary address of user
     */
    function deleteBeneficiary(address _beneficiary) external onlyOwner {
        if (_beneficiary == address(0x0)) {
            revert TokenVesting_AddressIsZero();
        }
        if (paused) {
            revert TokenVesting_ContractIsPaused(paused);
        }
        string[] memory scheduleNames = getBeneficiaryActiveScheduleNames(_beneficiary);
        uint256 scheduleNamesLength = scheduleNames.length;
        if (scheduleNamesLength == 0) {
            revert TokenVesting_BeneficiaryNoneActiveVestings();
        }
        for (uint32 i = 0; i < scheduleNamesLength; i++) {
            uint256 unreleasedAmount = getBeneficiaryUnreleasedAmount(_beneficiary, scheduleNames[i]);
            beneficiaries[_beneficiary][scheduleNames[i]].allocatedAmount -= unreleasedAmount;
            vestingSchedules[scheduleNames[i]].allocatedAmount -= unreleasedAmount;
        }
        emit BeneficiaryDeleted(_beneficiary);
    }

    /**
     * @dev Gets the beneficiary's next vestings
     * @param _beneficiary address of user
     * @return VestingExpectations[] structure
     */
    function getBeneficiaryNextVestings(address _beneficiary) external view returns (VestingExpectation[] memory) {
        string[] memory scheduleNames = getBeneficiaryActiveScheduleNames(_beneficiary);
        uint256 scheduleNamesLength = scheduleNames.length;
        if (scheduleNamesLength == 0) {
            revert TokenVesting_BeneficiaryNoneActiveVestings();
        }
        VestingExpectation[] memory vestingExpectations = new VestingExpectation[](scheduleNamesLength);
        for (uint32 i = 0; i < scheduleNamesLength; i++) {
            VestingExpectation memory vestingExpectation = VestingExpectation({
                vesting: getNextVesting(scheduleNames[i]),
                beneficiaryAmount: getNextUnlockAmount(_beneficiary, scheduleNames[i])
            });
            vestingExpectations[i] = vestingExpectation;
        }
        return vestingExpectations;
    }

    /**
     * @dev Gets beneficiary overview
     * @param _beneficiary address of user
     * @return BeneficiaryOverview[] structure
     */
    function getBeneficiaryOverview(address _beneficiary) external view returns (BeneficiaryOverview[] memory) {
        string[] memory scheduleNames = getBeneficiaryScheduleNames(_beneficiary);
        uint256 scheduleNamesLength = scheduleNames.length;
        if (scheduleNamesLength == 0) {
            revert TokenVesting_BeneficiaryNoneActiveVestings();
        }
        BeneficiaryOverview[] memory beneficiaryOverview = new BeneficiaryOverview[](scheduleNamesLength);
        for (uint32 i = 0; i < scheduleNamesLength; i++) {
            BeneficiaryOverview memory overview = BeneficiaryOverview({
                name: scheduleNames[i],
                terms: vestingSchedules[scheduleNames[i]].terms,
                cliff: vestingSchedules[scheduleNames[i]].cliff,
                duration: vestingSchedules[scheduleNames[i]].duration,
                allocatedAmount: beneficiaries[_beneficiary][scheduleNames[i]].allocatedAmount,
                withdrawnAmount: beneficiaries[_beneficiary][scheduleNames[i]].withdrawnAmount
            });
            beneficiaryOverview[i] = overview;
        }
        return beneficiaryOverview;
    }

    /**
     * @dev Gets the next vesting
     * @param _vestingScheduleName string
     * @return Vesting structure
     */
    function getNextVesting(string memory _vestingScheduleName) public view returns (Vesting memory) {
        if (isVestingScheduleFinished(_vestingScheduleName)) {
            revert TokenVesting_Error('The schedule is finished!');
        }
        VestingSchedule memory vestingSchedule = vestingSchedules[_vestingScheduleName];
        uint256 passedVestings = getPassedVestings(_vestingScheduleName);
        Vesting memory vesting;
        vesting.name = _vestingScheduleName;
        vesting.timestamp = tgeTimestamp + vestingSchedule.cliff + vestingSchedule.terms * (passedVestings + 1);
        vesting.amount = vestingSchedule.totalAmount / vestingSchedule.duration;
        return vesting;
    }

    /**
     * INDECISIVE public/internal
     * @dev Gets the amount of tokens locked for all schedules
     * @return uint256 unreleased amount of tokens
     */
    function getTotalLockedAmount() public view returns (uint256) {
        uint256 lockedAmount;
        string[] memory vestingScheduleNames = getAllVestingScheduleNames();
        uint256 scheduleNamesLength = vestingScheduleNames.length;
        for (uint32 i = 0; i < scheduleNamesLength; i++) {
            lockedAmount += getScheduleLockedAmount(vestingScheduleNames[i]);
        }
        return lockedAmount;
    }

    /**
     * @dev Claims caller's tokens
     * @param _vestingScheduleName string vesting schedule name
     * @param _amount uint256 amount of tokens
     */
    function claimTokens(string memory _vestingScheduleName, uint256 _amount) public {
        if (paused) {
            revert TokenVesting_ContractIsPaused(paused);
        }
        if (bytes(_vestingScheduleName).length == 0) {
            revert TokenVesting_Error('The name is empty!');
        }
        if (!isVestingScheduleValid(_vestingScheduleName)) {
            revert TokenVesting_Error('The name is invalid!');
        }
        if (_amount == 0) {
            revert TokenVesting_AmountZero();
        }
        if (getScheduleLockedAmount(_vestingScheduleName) < _amount) {
            revert TokenVesting_AmountExcessive(_amount, getScheduleLockedAmount(_vestingScheduleName));
        }
        if (getBeneficiaryUnclaimedAmount(_msgSender(), _vestingScheduleName) < _amount) {
            revert TokenVesting_AmountExcessive(
                _amount,
                getBeneficiaryUnclaimedAmount(_msgSender(), _vestingScheduleName)
            );
        }
        sendTokens(_msgSender(), _amount);
        vestingSchedulesTotalReservedAmount -= _amount;
        vestingSchedules[_vestingScheduleName].releasedAmount += _amount;
        beneficiaries[_msgSender()][_vestingScheduleName].withdrawnAmount += _amount;
        emit TokensClaimed(
            _msgSender(),
            _vestingScheduleName,
            _amount,
            beneficiaries[_msgSender()][_vestingScheduleName].withdrawnAmount
        );
    }

    /**
     * @dev Claims all caller's tokens for selected vesting schedule
     * @param _vestingScheduleName string vesting schedule name
     */
    function claimAllTokensForVestingSchedule(string memory _vestingScheduleName) public {
        if (paused) {
            revert TokenVesting_ContractIsPaused(paused);
        }
        uint256 amount = getBeneficiaryUnclaimedAmount(_msgSender(), _vestingScheduleName);
        claimTokens(_vestingScheduleName, amount);
    }

    /**
     * @dev Claims all caller's tokens
     */
    function claimAllTokens() public {
        if (paused) {
            revert TokenVesting_ContractIsPaused(paused);
        }
        string[] memory unclaimedVestingScheduleNames = getBeneficiaryUnclaimedScheduleNames(_msgSender());
        uint256 scheduleNamesLength = unclaimedVestingScheduleNames.length;
        if (scheduleNamesLength == 0) {
            revert TokenVesting_Error('There are no unclaimed tokens!');
        }
        for (uint32 i = 0; i < scheduleNamesLength; i++) {
            claimAllTokensForVestingSchedule(unclaimedVestingScheduleNames[i]);
        }
    }

    /**
     * @dev Returns the amount of tokens not involved in vesting schedules
     * @return uint256 amount of tokens
     */
    function getUnusedAmount() public view returns (uint256) {
        return token.balanceOf(address(this)) - vestingSchedulesTotalReservedAmount;
    }

    /**
     * @dev Returns current timestamp
     * @return uint256 timestamp
     */
    function getCurrentTimestamp() internal view virtual returns (uint256) {
        return block.timestamp;
    }

    /**
     * @dev Checks is vesting schedule name unique
     * @param _name string vesting schedule name
     */
    function isNameUnique(string memory _name) internal view returns (bool) {
        uint256 scheduleNamesLength = vestingSchedulesNames.length;
        for (uint32 i = 0; i < scheduleNamesLength; i++) {
            if (keccak256(bytes(vestingSchedulesNames[i])) == keccak256(bytes(_name))) {
                return false;
            }
        }
        return true;
    }

    /**
     * @dev Checks is vesting schedule valid
     * @param _vestingScheduleName string vesting schedule name
     * @return bool true if active
     */
    function isVestingScheduleValid(string memory _vestingScheduleName) internal view returns (bool) {
        VestingSchedule memory vestingSchedule = vestingSchedules[_vestingScheduleName];
        return vestingSchedule.initialized && !vestingSchedule.revoked;
    }

    /**
     * @dev Gets all vesting schedule names
     * @return string list of schedule names
     */
    function getAllVestingScheduleNames() internal view virtual returns (string[] memory) {
        return vestingSchedulesNames;
    }

    /**
     * @dev Gets all valid vesting schedule names
     * @return string list of schedule names
     */
    function getValidVestingScheduleNames() internal view returns (string[] memory) {
        string[] memory validVestingSchedulesNames = new string[](validVestingSchedulesCount);
        uint256 scheduleNamesLength = vestingSchedulesNames.length;
        uint32 j;
        for (uint32 i = 0; i < scheduleNamesLength; i++) {
            if (isVestingScheduleValid(vestingSchedulesNames[i])) {
                validVestingSchedulesNames[j] = vestingSchedulesNames[i];
                j++;
            }
        }
        return validVestingSchedulesNames;
    }

    /**
     * @dev Revokes vesting schedule
     * @param _name string schedule name
     */
    function _revokeVestingSchedule(string memory _name) internal {
        if (isNameUnique(_name)) {
            revert TokenVesting_Error('The name doesnt exist!');
        }
        if (vestingSchedules[_name].revoked == true) {
            revert TokenVesting_Error('The schedule is revoked!');
        }
        vestingSchedules[_name].revoked = true;
        vestingSchedulesTotalReservedAmount -= getScheduleUnreleasedAmount(_name);
        validVestingSchedulesCount--;
        emit VestingScheduleRevoked(_name);
    }

    /**
     * @dev Checks is vesting schedule started
     * @param _vestingScheduleName string vesting schedule name
     * @return bool true if started
     */
    function isVestingScheduleStarted(string memory _vestingScheduleName) internal view returns (bool) {
        VestingSchedule memory vestingSchedule = vestingSchedules[_vestingScheduleName];
        return getCurrentTimestamp() >= tgeTimestamp + vestingSchedule.cliff;
    }

    /**
     * @dev Checks is vesting schedule finished
     * @param _vestingScheduleName string vesting schedule name
     * @return bool true if finished
     */
    function isVestingScheduleFinished(string memory _vestingScheduleName) internal view returns (bool) {
        VestingSchedule memory vestingSchedule = vestingSchedules[_vestingScheduleName];
        return
            getCurrentTimestamp() >
            tgeTimestamp + vestingSchedule.cliff + vestingSchedule.duration * vestingSchedule.terms;
    }

    /**
     * @dev Gets the vesting schedule passed duration
     * @param _vestingScheduleName string
     * @return uint256 number of passed vesting
     */
    function getPassedVestings(string memory _vestingScheduleName) internal view returns (uint256) {
        VestingSchedule memory vestingSchedule = vestingSchedules[_vestingScheduleName];
        if (isVestingScheduleStarted(_vestingScheduleName)) {
            return (getCurrentTimestamp() - tgeTimestamp - vestingSchedule.cliff) / vestingSchedule.terms;
        }
        if (isVestingScheduleFinished(_vestingScheduleName)) {
            return vestingSchedule.duration;
        }
        return 0;
    }

    /**
     * @dev Returns the amount of tokens that can be released from vesting schedule
     * @param _vestingScheduleName string vesting schedule name
     * @return uint256 unreleased amount of tokens
     */
    function getScheduleUnreleasedAmount(string memory _vestingScheduleName) internal view returns (uint256) {
        VestingSchedule memory vestingSchedule = vestingSchedules[_vestingScheduleName];
        return vestingSchedule.totalAmount - vestingSchedule.releasedAmount;
    }

    /**
     * @dev Returns the amount of locked tokens
     * @param _vestingScheduleName string vesting schedule name
     * @return uint256 locked amount of tokens
     */
    function getScheduleLockedAmount(string memory _vestingScheduleName) internal view returns (uint256) {
        VestingSchedule memory vestingSchedule = vestingSchedules[_vestingScheduleName];
        return vestingSchedule.allocatedAmount - vestingSchedule.releasedAmount;
    }

    /**
     * @dev Returns the amount of tokens that can be allocated from vesting schedule
     * @param _vestingScheduleName string vesting schedule name
     * @return uint256 unallocated amount of tokens
     */
    function getScheduleUnallocatedAmount(string memory _vestingScheduleName) internal view returns (uint256) {
        VestingSchedule memory vestingSchedule = vestingSchedules[_vestingScheduleName];
        return vestingSchedule.totalAmount - vestingSchedule.allocatedAmount;
    }

    /**
     * @dev Gets beneficiary schedule names
     * @param _beneficiary address of user
     * @return string[] array schedule names assigned to beneficiary
     */
    function getBeneficiaryScheduleNames(address _beneficiary) internal view returns (string[] memory) {
        uint256 beneficiaryScheduleNamesCount;
        string[] memory vestingScheduleNames = getValidVestingScheduleNames();
        for (uint32 i = 0; i < validVestingSchedulesCount; i++) {
            if (beneficiaries[_beneficiary][vestingScheduleNames[i]].allocatedAmount > 0) {
                beneficiaryScheduleNamesCount++;
            }
        }

        string[] memory beneficiaryScheduleNames = new string[](beneficiaryScheduleNamesCount);
        uint256 j;
        for (uint32 i = 0; i < validVestingSchedulesCount; i++) {
            if (beneficiaries[_beneficiary][vestingScheduleNames[i]].allocatedAmount > 0) {
                beneficiaryScheduleNames[j] = vestingScheduleNames[i];
                j++;
            }
        }
        return beneficiaryScheduleNames;
    }

    /**
     * @dev Gets beneficiary unclaimed schedule names
     * @param _beneficiary address of user
     * @return string[] array schedule names assigned to beneficiary
     */
    function getBeneficiaryUnclaimedScheduleNames(address _beneficiary) internal view returns (string[] memory) {
        uint256 beneficiaryScheduleNamesCount;
        string[] memory vestingScheduleNames = getValidVestingScheduleNames();
        for (uint32 i = 0; i < validVestingSchedulesCount; i++) {
            if (getBeneficiaryUnclaimedAmount(_beneficiary, vestingScheduleNames[i]) > 0) {
                beneficiaryScheduleNamesCount++;
            }
        }

        string[] memory beneficiaryScheduleNames = new string[](beneficiaryScheduleNamesCount);
        uint256 j;
        for (uint32 i = 0; i < validVestingSchedulesCount; i++) {
            if (getBeneficiaryUnclaimedAmount(_beneficiary, vestingScheduleNames[i]) > 0) {
                beneficiaryScheduleNames[j] = vestingScheduleNames[i];
                j++;
            }
        }
        return beneficiaryScheduleNames;
    }

    /**
     * @dev Gets beneficiary active schedule names
     * @param _beneficiary address of user
     * @return string[] array schedule names assigned to beneficiary
     */
    function getBeneficiaryActiveScheduleNames(address _beneficiary) internal view returns (string[] memory) {
        uint256 beneficiaryActiveScheduleNamesCount;
        string[] memory vestingScheduleNames = getValidVestingScheduleNames();
        for (uint32 i = 0; i < validVestingSchedulesCount; i++) {
            if (
                beneficiaries[_beneficiary][vestingScheduleNames[i]].allocatedAmount > 0 &&
                !isVestingScheduleFinished(vestingScheduleNames[i])
            ) {
                beneficiaryActiveScheduleNamesCount++;
            }
        }

        string[] memory beneficiaryActiveScheduleNames = new string[](beneficiaryActiveScheduleNamesCount);
        uint256 j;
        for (uint32 i = 0; i < validVestingSchedulesCount; i++) {
            if (
                beneficiaries[_beneficiary][vestingScheduleNames[i]].allocatedAmount > 0 &&
                !isVestingScheduleFinished(vestingScheduleNames[i])
            ) {
                beneficiaryActiveScheduleNames[j] = vestingScheduleNames[i];
                j++;
            }
        }
        return beneficiaryActiveScheduleNames;
    }

    /**
     * @dev Gets beneficiary next unlocked amount
     * @param _beneficiary address of user
     * @param _vestingScheduleName string
     * @return uint256 allocation
     */
    function getNextUnlockAmount(address _beneficiary, string memory _vestingScheduleName)
        internal
        view
        returns (uint256)
    {
        VestingSchedule memory vestingSchedule = vestingSchedules[_vestingScheduleName];
        return beneficiaries[_beneficiary][_vestingScheduleName].allocatedAmount / vestingSchedule.duration;
    }

    /**
     * @dev Returns the unlocked amount of tokens for selected beneficiary and vesting schedule
     * @param _beneficiary address of user
     * @param _vestingScheduleName string vesting schedule name
     * @return uint256 unlocked amount of tokens
     */
    function getBeneficiaryUnlockedAmount(address _beneficiary, string memory _vestingScheduleName)
        internal
        view
        returns (uint256)
    {
        VestingSchedule memory vestingSchedule = vestingSchedules[_vestingScheduleName];
        Beneficiary memory beneficiary = beneficiaries[_beneficiary][_vestingScheduleName];
        if (isVestingScheduleFinished(_vestingScheduleName)) {
            return beneficiary.allocatedAmount;
        }
        return (getPassedVestings(_vestingScheduleName) * beneficiary.allocatedAmount) / vestingSchedule.duration;
    }

    /**
     * @dev Returns the amount of tokens that can be claimed by beneficiary
     * @param _beneficiary address of user
     * @param _vestingScheduleName string vesting schedule name
     * @return uint256 unclaimed amount of tokens
     */
    function getBeneficiaryUnclaimedAmount(address _beneficiary, string memory _vestingScheduleName)
        internal
        view
        returns (uint256)
    {
        uint256 unlockedAmount = getBeneficiaryUnlockedAmount(_beneficiary, _vestingScheduleName);
        return unlockedAmount - beneficiaries[_beneficiary][_vestingScheduleName].withdrawnAmount;
    }

    /**
     * @dev Returns the amount of tokens that unreleased by beneficiary
     * @param _beneficiary address of user
     * @param _vestingScheduleName string vesting schedule name
     * @return uint256 unclaimed amount of tokens
     */
    function getBeneficiaryUnreleasedAmount(address _beneficiary, string memory _vestingScheduleName)
        internal
        view
        returns (uint256)
    {
        Beneficiary memory beneficiary = beneficiaries[_beneficiary][_vestingScheduleName];
        return beneficiary.allocatedAmount - beneficiary.withdrawnAmount;
    }

    /**
     * @dev Sends tokens to selected address
     * @param _to address of account
     * @param _amount uint256 amount of tokens
     */
    function sendTokens(address _to, uint256 _amount) internal {
        if (_to == address(0x0)) {
            revert TokenVesting_AddressIsZero();
        }
        if (_amount > getTotalLockedAmount()) {
            revert TokenVesting_AmountExcessive(_amount, getTotalLockedAmount());
        }
        token.safeTransfer(_to, _amount);
    }

    function transferOwnership(address newOwner) public virtual override onlyOwner {
        if (paused) {
            revert TokenVesting_ContractIsPaused(paused);
        }
        super.transferOwnership(newOwner);
    }
}

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

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

File 4 of 8 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";

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

    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) {
            // Return data is optional
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

File 5 of 8 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly
                /// @solidity memory-safe-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 6 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 7 of 8 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity 0.8.9;

import '@openzeppelin/contracts/utils/Context.sol';

error Ownable_Error(string msg);

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

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

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

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

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

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert Ownable_Error('Caller is not the owner!');
        }
    }

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

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

File 8 of 8 : Ownable2Step.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (access/Ownable2Step.sol)

pragma solidity 0.8.9;

import './Ownable.sol';

error Ownable2Step_Error(string msg);

/**
 * @dev Contract module which provides access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership} and {acceptOwnership}.
 *
 * This module is used through inheritance. It will make available all functions
 * from parent (Ownable).
 */
abstract contract Ownable2Step is Ownable {
    address private _pendingOwner;

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

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

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

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

    /**
     * @dev The new owner accepts the ownership transfer.
     */
    function acceptOwnership() external {
        address sender = _msgSender();
        if (pendingOwner() != sender) {
            revert Ownable2Step_Error('Caller is not the new owner!');
        }
        _transferOwnership(sender);
    }
}

Settings
{
  "evmVersion": "london",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs",
    "useLiteralContent": true
  },
  "optimizer": {
    "enabled": true,
    "runs": 9999
  },
  "remappings": [],
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_tokenContractAddress","type":"address"},{"internalType":"uint256","name":"_tgeTimestamp","type":"uint256"},{"internalType":"address","name":"_treasuryAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"string","name":"msg","type":"string"}],"name":"Ownable2Step_Error","type":"error"},{"inputs":[{"internalType":"string","name":"msg","type":"string"}],"name":"Ownable_Error","type":"error"},{"inputs":[],"name":"TokenVesting_AddressIsZero","type":"error"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"TokenVesting_AmountExcessive","type":"error"},{"inputs":[],"name":"TokenVesting_AmountZero","type":"error"},{"inputs":[],"name":"TokenVesting_BeneficiaryNoneActiveVestings","type":"error"},{"inputs":[{"internalType":"bool","name":"isPaused","type":"bool"}],"name":"TokenVesting_ContractIsPaused","type":"error"},{"inputs":[{"internalType":"string","name":"msg","type":"string"}],"name":"TokenVesting_Error","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_beneficiary","type":"address"},{"indexed":false,"internalType":"string","name":"_vestingScheduleName","type":"string"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_currentAllocation","type":"uint256"}],"name":"AllocationAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_beneficiary","type":"address"},{"indexed":false,"internalType":"string","name":"_vestingScheduleName","type":"string"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_currentAllocation","type":"uint256"}],"name":"AllocationRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_beneficiary","type":"address"}],"name":"BeneficiaryDeleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"_paused","type":"bool"}],"name":"ContractPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_beneficiary","type":"address"},{"indexed":false,"internalType":"string","name":"_vestingScheduleName","type":"string"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_releasedAmount","type":"uint256"}],"name":"TokensClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"_name","type":"string"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"VestingScheduleCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"_name","type":"string"}],"name":"VestingScheduleRevoked","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_beneficiary","type":"address"},{"internalType":"string","name":"_vestingScheduleName","type":"string"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"addBeneficiaryAllocation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimAllTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_vestingScheduleName","type":"string"}],"name":"claimAllTokensForVestingSchedule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_vestingScheduleName","type":"string"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"claimTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"uint256","name":"_terms","type":"uint256"},{"internalType":"uint256","name":"_cliff","type":"uint256"},{"internalType":"uint256","name":"_duration","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"createVestingSchedule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"string","name":"_name","type":"string"}],"name":"decreaseVestingScheduleTotalAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_beneficiary","type":"address"}],"name":"deleteBeneficiary","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emergencyWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAllVestingSchedules","outputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"terms","type":"uint256"},{"internalType":"uint256","name":"cliff","type":"uint256"},{"internalType":"uint256","name":"duration","type":"uint256"},{"internalType":"uint256","name":"totalAmount","type":"uint256"},{"internalType":"uint256","name":"allocatedAmount","type":"uint256"},{"internalType":"uint256","name":"releasedAmount","type":"uint256"},{"internalType":"bool","name":"initialized","type":"bool"},{"internalType":"bool","name":"revoked","type":"bool"}],"internalType":"struct TokenVesting.VestingSchedule[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_beneficiary","type":"address"},{"internalType":"string","name":"_vestingScheduleName","type":"string"}],"name":"getBeneficiary","outputs":[{"components":[{"internalType":"uint256","name":"allocatedAmount","type":"uint256"},{"internalType":"uint256","name":"withdrawnAmount","type":"uint256"}],"internalType":"struct TokenVesting.Beneficiary","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_beneficiary","type":"address"}],"name":"getBeneficiaryNextVestings","outputs":[{"components":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"internalType":"struct TokenVesting.Vesting","name":"vesting","type":"tuple"},{"internalType":"uint256","name":"beneficiaryAmount","type":"uint256"}],"internalType":"struct TokenVesting.VestingExpectation[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_beneficiary","type":"address"}],"name":"getBeneficiaryOverview","outputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"terms","type":"uint256"},{"internalType":"uint256","name":"cliff","type":"uint256"},{"internalType":"uint256","name":"duration","type":"uint256"},{"internalType":"uint256","name":"allocatedAmount","type":"uint256"},{"internalType":"uint256","name":"withdrawnAmount","type":"uint256"}],"internalType":"struct TokenVesting.BeneficiaryOverview[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_vestingScheduleName","type":"string"}],"name":"getNextVesting","outputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"internalType":"struct TokenVesting.Vesting","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalLockedAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUnusedAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getValidVestingSchedules","outputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"terms","type":"uint256"},{"internalType":"uint256","name":"cliff","type":"uint256"},{"internalType":"uint256","name":"duration","type":"uint256"},{"internalType":"uint256","name":"totalAmount","type":"uint256"},{"internalType":"uint256","name":"allocatedAmount","type":"uint256"},{"internalType":"uint256","name":"releasedAmount","type":"uint256"},{"internalType":"bool","name":"initialized","type":"bool"},{"internalType":"bool","name":"revoked","type":"bool"}],"internalType":"struct TokenVesting.VestingSchedule[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getValidVestingSchedulesCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"}],"name":"getVestingSchedule","outputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"terms","type":"uint256"},{"internalType":"uint256","name":"cliff","type":"uint256"},{"internalType":"uint256","name":"duration","type":"uint256"},{"internalType":"uint256","name":"totalAmount","type":"uint256"},{"internalType":"uint256","name":"allocatedAmount","type":"uint256"},{"internalType":"uint256","name":"releasedAmount","type":"uint256"},{"internalType":"bool","name":"initialized","type":"bool"},{"internalType":"bool","name":"revoked","type":"bool"}],"internalType":"struct TokenVesting.VestingSchedule","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVestingSchedulesCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"string","name":"_name","type":"string"}],"name":"increaseVestingScheduleTotalAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pauseContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_beneficiary","type":"address"},{"internalType":"string","name":"_vestingScheduleName","type":"string"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"removeBeneficiaryAllocation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"}],"name":"revokeVestingSchedule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tgeTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasuryAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpauseContract","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60a06040523480156200001157600080fd5b506040516200563b3803806200563b8339810160408190526200003491620001a7565b6200003f3362000110565b6001600160a01b038316620000675760405163f908131360e01b815260040160405180910390fd5b81620000b9576040516247efb760e81b815260206004820152601a60248201527f546865205447452054696d657374616d70206973207a65726f21000000000000604482015260640160405180910390fd5b6001600160a01b038116620000e15760405163f908131360e01b815260040160405180910390fd5b6001600160a01b03928316608052600591909155600680546001600160a01b03191691909216179055620001e8565b600180546001600160a01b031916905562000137816200013a602090811b62002bbf17901c565b50565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b0381168114620001a257600080fd5b919050565b600080600060608486031215620001bd57600080fd5b620001c8846200018a565b925060208401519150620001df604085016200018a565b90509250925092565b6080516154146200022760003960008181610238015281816117350152818161189301528181611919015281816119810152613dba01526154146000f3fe608060405234801561001057600080fd5b50600436106101f05760003560e01c806379ba50971161010f578063a4317ef4116100a2578063c5f956af11610071578063c5f956af14610429578063e30c39781461043c578063f2fde38b1461044d578063f4c6992b1461046057600080fd5b8063a4317ef4146103f0578063a4e41d29146103f9578063b195880b14610419578063b33712c51461042157600080fd5b806391cf9d09116100de57806391cf9d09146103af57806391d2b32e146103c2578063982d68ba146103ca578063a2aa6859146103dd57600080fd5b806379ba50971461037b5780637d3bca7614610383578063854e089e146103965780638da5cb5b1461039e57600080fd5b8063439766ce116101875780635c975abb116101565780635c975abb1461030f57806364bf72a914610333578063657a0cc81461033b5780636f5bea191461035b57600080fd5b8063439766ce146102d757806353936d3a146102df5780635414a0da146102f25780635b0a38431461030757600080fd5b8063293b26c6116101c3578063293b26c61461027057806329bbda1914610283578063328faf0514610296578063384695dc146102a957600080fd5b806313083617146101f55780631734ed471461020c5780631e4bd42c1461022c57806321df0da714610236575b600080fd5b6002545b6040519081526020015b60405180910390f35b61021f61021a3660046149d8565b610473565b6040516102039190614abc565b61023461069c565b005b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b039091168152602001610203565b61023461027e366004614b18565b610785565b610234610291366004614b7a565b610bd8565b6102346102a4366004614be2565b610df6565b6102bc6102b7366004614c3c565b611123565b60408051825181526020928301519281019290925201610203565b610234611190565b6102346102ed366004614b7a565b611248565b6102fa6113b3565b6040516102039190614cf5565b6102346116ff565b60065461032390600160a01b900460ff1681565b6040519015158152602001610203565b6101f9611944565b61034e610349366004614d75565b611a0a565b6040516102039190614d90565b61036e610369366004614e4d565b611d03565b6040516102039190614e8f565b610234611e77565b610234610391366004614d75565b611ef9565b6004546101f9565b6000546001600160a01b0316610258565b6102346103bd366004614ea2565b612120565b6101f961237c565b6102346103d83660046149d8565b6123ee565b6102346103eb366004614ee7565b61243b565b6101f960055481565b61040c610407366004614d75565b6126a5565b6040516102039190614f3e565b6102fa6127f6565b610234612a73565b600654610258906001600160a01b031681565b6001546001600160a01b0316610258565b61023461045b366004614d75565b612b1e565b61023461046e3660046149d8565b612b6b565b61049760405180606001604052806060815260200160008152602001600081525090565b6104a082612c27565b156104f2576040516247efb760e81b815260206004820152601960248201527f546865207363686564756c652069732066696e6973686564210000000000000060448201526064015b60405180910390fd5b60006007836040516105049190614fc4565b90815260200160405180910390206040518061012001604052908160008201805461052e90614fe0565b80601f016020809104026020016040519081016040528092919081815260200182805461055a90614fe0565b80156105a75780601f1061057c576101008083540402835291602001916105a7565b820191906000526020600020905b81548152906001019060200180831161058a57829003601f168201915b505050918352505060018201546020820152600282015460408201526003820154606082015260048201546080820152600582015460a0820152600682015460c082015260079091015460ff808216151560e0840152610100918290041615159101529050600061061784612d83565b905061063d60405180606001604052806060815260200160008152602001600081525090565b84815261064b826001615063565b836020015161065a919061507b565b836040015160055461066c9190615063565b6106769190615063565b60408201526060830151608084015161068f91906150b8565b6020820152949350505050565b600654600160a01b900460ff16156106d85760065460405163117beb8560e01b8152600160a01b90910460ff16151560048201526024016104e9565b60006106e333612ef8565b805190915080610735576040516247efb760e81b815260206004820152601e60248201527f546865726520617265206e6f20756e636c61696d656420746f6b656e7321000060448201526064016104e9565b60005b818163ffffffff1610156107805761076e838263ffffffff1681518110610761576107616150f3565b6020026020010151612b6b565b8061077881615122565b915050610738565b505050565b61078d61305e565b6000610797611944565b600654909150600160a01b900460ff16156107d65760065460405163117beb8560e01b8152600160a01b90910460ff16151560048201526024016104e9565b85610823576040516247efb760e81b815260206004820152601260248201527f546865206e616d6520697320656d70747921000000000000000000000000000060448201526064016104e9565b61086287878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506130d492505050565b6108ae576040516247efb760e81b815260206004820152601760248201527f546865206e616d65206973206475706c6963617465642100000000000000000060448201526064016104e9565b818110156108f2576040517f3b94d60600000000000000000000000000000000000000000000000000000000815260048101839052602481018290526044016104e9565b8261093f576040516247efb760e81b815260206004820152601560248201527f546865206475726174696f6e206973207a65726f21000000000000000000000060448201526064016104e9565b81610976576040517f135bf91600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b846109c3576040516247efb760e81b815260206004820152601360248201527f546865207465726d7320617265207a65726f210000000000000000000000000060448201526064016104e9565b60405180610120016040528088888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920182905250938552505050602082018890526040808301889052606083018790526080830186905260a0830182905260c08301829052600160e08401526101009092015251600790610a51908a908a90615146565b90815260200160405180910390206000820151816000019080519060200190610a7b929190614797565b50602082015160018201556040820151600282015560608201516003808301919091556080830151600483015560a0830151600583015560c0830151600683015560e083015160079092018054610100948501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00009091169315157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1693909317921515909302919091179091558054839190600090610b3c908490615063565b909155505060028054600181018255600091909152610b7e907f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace01888861481b565b5060048054906000610b8f83615156565b91905055507f37c575cf070e40f0e3e97de202fab4d5e34c8e88ed11783b252f0951b5c6d310878784604051610bc7939291906151d8565b60405180910390a150505050505050565b610be061305e565b600654600160a01b900460ff1615610c1c5760065460405163117beb8560e01b8152600160a01b90910460ff16151560048201526024016104e9565b610c5b82828080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506130d492505050565b15610ca8576040516247efb760e81b815260206004820152601660248201527f546865206e616d6520646f65736e74206578697374210000000000000000000060448201526064016104e9565b82610cdf576040517f135bf91600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82610d1f83838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061315692505050565b1015610da05782610d6583838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061315692505050565b6040517f3b94d606000000000000000000000000000000000000000000000000000000008152600481019290925260248201526044016104e9565b8260078383604051610db3929190615146565b90815260200160405180910390206004016000828254610dd391906151fc565b925050819055508260036000828254610dec91906151fc565b9091555050505050565b610dfe61305e565b600654600160a01b900460ff1615610e3a5760065460405163117beb8560e01b8152600160a01b90910460ff16151560048201526024016104e9565b6001600160a01b038416610e7a576040517ff908131300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80610eb1576040517f135bf91600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81610efe576040516247efb760e81b815260206004820152601260248201527f546865206e616d6520697320656d70747921000000000000000000000000000060448201526064016104e9565b610f3d83838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061328e92505050565b610f89576040516247efb760e81b815260206004820152601460248201527f546865206e616d6520697320696e76616c69642100000000000000000000000060448201526064016104e9565b80610fca8585858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506133c892505050565b10156110115780610d658585858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506133c892505050565b6001600160a01b03841660009081526008602052604090819020905182919061103d9086908690615146565b9081526020016040518091039020600001600082825461105d91906151fc565b925050819055508060078484604051611077929190615146565b9081526020016040518091039020600501600082825461109791906151fc565b925050819055507fcb6b75de6dac337ab06e18a20ee2bd260f10cbcecd1a495501b47b0aef412db584848484600860008a6001600160a01b03166001600160a01b0316815260200190815260200160002088886040516110f8929190615146565b908152604051908190036020018120546111159594939291615213565b60405180910390a150505050565b60408051808201909152600080825260208201526001600160a01b0384166000908152600860205260409081902090516111609085908590615146565b908152604080519182900360209081018320838301909252815483526001909101549082015290505b9392505050565b61119861305e565b600654600160a01b900460ff16156111d45760065460405163117beb8560e01b8152600160a01b90910460ff16151560048201526024016104e9565b600680547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16600160a01b908117918290556040517f752d7e161ff5146f80e3820893176eb40532811e5e20400dfdde57455213706a9261123e92900460ff161515815260200190565b60405180910390a1565b61125061305e565b600654600160a01b900460ff161561128c5760065460405163117beb8560e01b8152600160a01b90910460ff16151560048201526024016104e9565b6112cb82828080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506130d492505050565b15611318576040516247efb760e81b815260206004820152601660248201527f546865206e616d6520646f65736e74206578697374210000000000000000000060448201526064016104e9565b8261134f576040517f135bf91600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82611358611944565b10156113675782610d65611944565b826007838360405161137a929190615146565b9081526020016040518091039020600401600082825461139a9190615063565b925050819055508260036000828254610dec9190615063565b606060045460001415611408576040516247efb760e81b815260206004820152601b60248201527f4e6f2076616c69642076657374696e67207363686564756c657321000000000060448201526064016104e9565b600060045467ffffffffffffffff811115611425576114256148fe565b6040519080825280602002602001820160405280156114a957816020015b611496604051806101200160405280606081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000151581526020016000151581525090565b8152602001906001900390816114435790505b5090506000805b6004548163ffffffff1610156116f75761157460028263ffffffff16815481106114dc576114dc6150f3565b9060005260206000200180546114f190614fe0565b80601f016020809104026020016040519081016040528092919081815260200182805461151d90614fe0565b801561156a5780601f1061153f5761010080835404028352916020019161156a565b820191906000526020600020905b81548152906001019060200180831161154d57829003601f168201915b505050505061328e565b156116e557600760028263ffffffff1681548110611594576115946150f3565b906000526020600020016040516115ab919061531a565b9081526020016040518091039020604051806101200160405290816000820180546115d590614fe0565b80601f016020809104026020016040519081016040528092919081815260200182805461160190614fe0565b801561164e5780601f106116235761010080835404028352916020019161164e565b820191906000526020600020905b81548152906001019060200180831161163157829003601f168201915b505050918352505060018201546020820152600282015460408201526003820154606082015260048201546080820152600582015460a0820152600682015460c082015260079091015460ff808216151560e0840152610100918290041615159101528351849063ffffffff85169081106116cb576116cb6150f3565b602002602001018190525081806116e190615122565b9250505b806116ef81615122565b9150506114b0565b509092915050565b61170761305e565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561177f57600080fd5b505afa158015611793573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117b79190615326565b611803576040516247efb760e81b815260206004820152601460248201527f4e6f7468696e6720746f2077697468647261772100000000000000000000000060448201526064016104e9565b600061180d61342d565b805190915060005b818110156118515761183f838281518110611832576118326150f3565b60200260200101516135a9565b8061184981615156565b915050611815565b506006546040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152611940916001600160a01b03908116917f0000000000000000000000000000000000000000000000000000000000000000909116906370a082319060240160206040518083038186803b1580156118d757600080fd5b505afa1580156118eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061190f9190615326565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169190613742565b5050565b6003546040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152600091906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a082319060240160206040518083038186803b1580156119c357600080fd5b505afa1580156119d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119fb9190615326565b611a0591906151fc565b905090565b60606000611a17836137c2565b805190915080611a53576040517f1e79856100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008167ffffffffffffffff811115611a6e57611a6e6148fe565b604051908082528060200260200182016040528015611ad857816020015b611ac56040518060c001604052806060815260200160008152602001600081526020016000815260200160008152602001600081525090565b815260200190600190039081611a8c5790505b50905060005b828163ffffffff161015611cfa5760006040518060c00160405280868463ffffffff1681518110611b1157611b116150f3565b602002602001015181526020016007878563ffffffff1681518110611b3857611b386150f3565b6020026020010151604051611b4d9190614fc4565b90815260200160405180910390206001015481526020016007878563ffffffff1681518110611b7e57611b7e6150f3565b6020026020010151604051611b939190614fc4565b90815260200160405180910390206002015481526020016007878563ffffffff1681518110611bc457611bc46150f3565b6020026020010151604051611bd99190614fc4565b9081526020016040518091039020600301548152602001600860008a6001600160a01b03166001600160a01b03168152602001908152602001600020878563ffffffff1681518110611c2d57611c2d6150f3565b6020026020010151604051611c429190614fc4565b9081526020016040518091039020600001548152602001600860008a6001600160a01b03166001600160a01b03168152602001908152602001600020878563ffffffff1681518110611c9657611c966150f3565b6020026020010151604051611cab9190614fc4565b908152602001604051809103902060010154815250905080838363ffffffff1681518110611cdb57611cdb6150f3565b6020026020010181905250508080611cf290615122565b915050611ade565b50949350505050565b611d56604051806101200160405280606081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000151581526020016000151581525090565b60078383604051611d68929190615146565b908152602001604051809103902060405180610120016040529081600082018054611d9290614fe0565b80601f0160208091040260200160405190810160405280929190818152602001828054611dbe90614fe0565b8015611e0b5780601f10611de057610100808354040283529160200191611e0b565b820191906000526020600020905b815481529060010190602001808311611dee57829003601f168201915b505050918352505060018201546020820152600282015460408201526003820154606082015260048201546080820152600582015460a0820152600682015460c082015260079091015460ff808216151560e08401526101009182900416151591015290505b92915050565b60015433906001600160a01b03168114611eed576040517f252ec7cf00000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f43616c6c6572206973206e6f7420746865206e6577206f776e6572210000000060448201526064016104e9565b611ef681613982565b50565b611f0161305e565b6001600160a01b038116611f41576040517ff908131300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600654600160a01b900460ff1615611f7d5760065460405163117beb8560e01b8152600160a01b90910460ff16151560048201526024016104e9565b6000611f88826139b3565b805190915080611fc4576040517f1e79856100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b818163ffffffff1610156120dd57600061200085858463ffffffff1681518110611ff357611ff36150f3565b60200260200101516133c8565b6001600160a01b038616600090815260086020526040902085519192508291869063ffffffff8616908110612037576120376150f3565b602002602001015160405161204c9190614fc4565b9081526020016040518091039020600001600082825461206c91906151fc565b92505081905550806007858463ffffffff168151811061208e5761208e6150f3565b60200260200101516040516120a39190614fc4565b908152602001604051809103902060050160008282546120c391906151fc565b909155508291506120d5905081615122565b915050611fc7565b506040516001600160a01b03841681527ff5a46f0b640efde5acf94b5c5611e5ee1d1dabaf5c4e624911901e83623689f2906020015b60405180910390a1505050565b600654600160a01b900460ff161561215c5760065460405163117beb8560e01b8152600160a01b90910460ff16151560048201526024016104e9565b81516121aa576040516247efb760e81b815260206004820152601260248201527f546865206e616d6520697320656d70747921000000000000000000000000000060448201526064016104e9565b6121b38261328e565b6121ff576040516247efb760e81b815260206004820152601460248201527f546865206e616d6520697320696e76616c69642100000000000000000000000060448201526064016104e9565b80612236576040517f135bf91600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8061224083613bc8565b10156122505780610d6583613bc8565b8061225c335b84613d00565b101561226c5780610d6533612256565b6122763382613d55565b806003600082825461228891906151fc565b92505081905550806007836040516122a09190614fc4565b908152602001604051809103902060060160008282546122c09190615063565b9091555050336000908152600860205260409081902090518291906122e6908590614fc4565b908152602001604051809103902060010160008282546123069190615063565b9091555050336000818152600860205260409081902090517f404130b82350104f12b628380e26256559246fb39f9124791864b4b3062aadb692918591859190612351908490614fc4565b908152604051908190036020018120600101546123709493929161533f565b60405180910390a15050565b6000806000612389613de1565b805190915060005b818163ffffffff1610156123e5576123c7838263ffffffff16815181106123ba576123ba6150f3565b6020026020010151613bc8565b6123d19085615063565b9350806123dd81615122565b915050612391565b50919392505050565b6123f661305e565b600654600160a01b900460ff16156124325760065460405163117beb8560e01b8152600160a01b90910460ff16151560048201526024016104e9565b611ef6816135a9565b61244361305e565b600654600160a01b900460ff161561247f5760065460405163117beb8560e01b8152600160a01b90910460ff16151560048201526024016104e9565b6001600160a01b0383166124bf576040517ff908131300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815161250d576040516247efb760e81b815260206004820152601260248201527f546865206e616d6520697320656d70747921000000000000000000000000000060448201526064016104e9565b80612544576040517f135bf91600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61254d8261328e565b612599576040516247efb760e81b815260206004820152601860248201527f546865207363686564756c6520697320696e76616c696421000000000000000060448201526064016104e9565b806125a383613156565b10156125b35780610d6583613156565b6001600160a01b0383166000908152600860205260409081902090518291906125dd908590614fc4565b908152602001604051809103902060000160008282546125fd9190615063565b92505081905550806007836040516126159190614fc4565b908152602001604051809103902060050160008282546126359190615063565b90915550506001600160a01b0383166000908152600860205260409081902090517fd1eabf10ff5c5af40aada9f67d087cdb8964e16287ea3580e84defda96f10f9191859185918591612689908490614fc4565b908152604051908190036020018120546121139493929161533f565b606060006126b2836139b3565b8051909150806126ee576040517f1e79856100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008167ffffffffffffffff811115612709576127096148fe565b60405190808252806020026020018201604052801561274257816020015b61272f6148ad565b8152602001906001900390816127275790505b50905060005b828163ffffffff161015611cfa576000604051806040016040528061278b878563ffffffff168151811061277e5761277e6150f3565b6020026020010151610473565b81526020016127b989888663ffffffff16815181106127ac576127ac6150f3565b6020026020010151613eba565b815250905080838363ffffffff16815181106127d7576127d76150f3565b60200260200101819052505080806127ee90615122565b915050612748565b60025460609080612849576040516247efb760e81b815260206004820152601560248201527f4e6f2076657374696e67207363686564756c657321000000000000000000000060448201526064016104e9565b60008167ffffffffffffffff811115612864576128646148fe565b6040519080825280602002602001820160405280156128e857816020015b6128d5604051806101200160405280606081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000151581526020016000151581525090565b8152602001906001900390816128825790505b50905060005b828163ffffffff161015612a6c57600760028263ffffffff1681548110612917576129176150f3565b9060005260206000200160405161292e919061531a565b90815260200160405180910390206040518061012001604052908160008201805461295890614fe0565b80601f016020809104026020016040519081016040528092919081815260200182805461298490614fe0565b80156129d15780601f106129a6576101008083540402835291602001916129d1565b820191906000526020600020905b8154815290600101906020018083116129b457829003601f168201915b505050918352505060018201546020820152600282015460408201526003820154606082015260048201546080820152600582015460a0820152600682015460c082015260079091015460ff808216151560e0840152610100918290041615159101528251839063ffffffff8416908110612a4e57612a4e6150f3565b60200260200101819052508080612a6490615122565b9150506128ee565b5092915050565b612a7b61305e565b600654600160a01b900460ff16612ab65760065460405163117beb8560e01b8152600160a01b90910460ff16151560048201526024016104e9565b600680547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16908190556040517f752d7e161ff5146f80e3820893176eb40532811e5e20400dfdde57455213706a9161123e91600160a01b90910460ff161515815260200190565b612b2661305e565b600654600160a01b900460ff1615612b625760065460405163117beb8560e01b8152600160a01b90910460ff16151560048201526024016104e9565b611ef68161402a565b600654600160a01b900460ff1615612ba75760065460405163117beb8560e01b8152600160a01b90910460ff16151560048201526024016104e9565b6000612bb33383613d00565b90506119408282612120565b600080546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600080600783604051612c3a9190614fc4565b908152602001604051809103902060405180610120016040529081600082018054612c6490614fe0565b80601f0160208091040260200160405190810160405280929190818152602001828054612c9090614fe0565b8015612cdd5780601f10612cb257610100808354040283529160200191612cdd565b820191906000526020600020905b815481529060010190602001808311612cc057829003601f168201915b5050509183525050600182015460208083019190915260028301546040830152600383015460608084019190915260048401546080840152600584015460a0840152600684015460c084015260079093015460ff808216151560e08501526101009182900416151592019190915282015190820151919250612d5e9161507b565b8160400151600554612d709190615063565b612d7a9190615063565b42119392505050565b600080600783604051612d969190614fc4565b908152602001604051809103902060405180610120016040529081600082018054612dc090614fe0565b80601f0160208091040260200160405190810160405280929190818152602001828054612dec90614fe0565b8015612e395780601f10612e0e57610100808354040283529160200191612e39565b820191906000526020600020905b815481529060010190602001808311612e1c57829003601f168201915b505050918352505060018201546020820152600282015460408201526003820154606082015260048201546080820152600582015460a0820152600682015460c082015260079091015460ff808216151560e0840152610100918290041615159101529050612ea783614123565b15612ed75760208101516040820151600554612ec390426151fc565b612ecd91906151fc565b61118991906150b8565b612ee083612c27565b15612eef576060015192915050565b50600092915050565b6060600080612f0561342d565b905060005b6004548163ffffffff161015612f6b576000612f4586848463ffffffff1681518110612f3857612f386150f3565b6020026020010151613d00565b1115612f595782612f5581615156565b9350505b80612f6381615122565b915050612f0a565b5060008267ffffffffffffffff811115612f8757612f876148fe565b604051908082528060200260200182016040528015612fba57816020015b6060815260200190600190039081612fa55790505b5090506000805b6004548163ffffffff161015613053576000612fef88868463ffffffff1681518110612f3857612f386150f3565b111561304157838163ffffffff168151811061300d5761300d6150f3565b6020026020010151838381518110613027576130276150f3565b6020026020010181905250818061303d90615156565b9250505b8061304b81615122565b915050612fc1565b509095945050505050565b6000546001600160a01b031633146130d2576040517f43069fd000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f43616c6c6572206973206e6f7420746865206f776e657221000000000000000060448201526064016104e9565b565b600254600090815b818163ffffffff16101561314c57838051906020012060028263ffffffff168154811061310b5761310b6150f3565b90600052602060002001604051613122919061531a565b6040518091039020141561313a575060009392505050565b8061314481615122565b9150506130dc565b5060019392505050565b6000806007836040516131699190614fc4565b90815260200160405180910390206040518061012001604052908160008201805461319390614fe0565b80601f01602080910402602001604051908101604052809291908181526020018280546131bf90614fe0565b801561320c5780601f106131e15761010080835404028352916020019161320c565b820191906000526020600020905b8154815290600101906020018083116131ef57829003601f168201915b50505091835250506001820154602082015260028201546040820152600382015460608201526004820154608080830191909152600583015460a080840191909152600684015460c084015260079093015460ff808216151560e0850152610100918290041615159201919091529082015190820151919250611189916151fc565b6000806007836040516132a19190614fc4565b9081526020016040518091039020604051806101200160405290816000820180546132cb90614fe0565b80601f01602080910402602001604051908101604052809291908181526020018280546132f790614fe0565b80156133445780601f1061331957610100808354040283529160200191613344565b820191906000526020600020905b81548152906001019060200180831161332757829003601f168201915b505050918352505060018201546020820152600282015460408201526003820154606082015260048201546080820152600582015460a0820152600682015460c082015260079091015460ff808216151560e08085019190915261010092839004909116151591909201528101519091508015611189575061010001511592915050565b6001600160a01b03821660009081526008602052604080822090518291906133f1908590614fc4565b90815260408051602092819003830181208183019092528154808252600190920154928101839052925061342591906151fc565b949350505050565b6060600060045467ffffffffffffffff81111561344c5761344c6148fe565b60405190808252806020026020018201604052801561347f57816020015b606081526020019060019003908161346a5790505b506002549091506000805b828163ffffffff1610156123e5576134b460028263ffffffff16815481106114dc576114dc6150f3565b156135975760028163ffffffff16815481106134d2576134d26150f3565b9060005260206000200180546134e790614fe0565b80601f016020809104026020016040519081016040528092919081815260200182805461351390614fe0565b80156135605780601f1061353557610100808354040283529160200191613560565b820191906000526020600020905b81548152906001019060200180831161354357829003601f168201915b5050505050848363ffffffff168151811061357d5761357d6150f3565b6020026020010181905250818061359390615122565b9250505b806135a181615122565b91505061348a565b6135b2816130d4565b156135ff576040516247efb760e81b815260206004820152601660248201527f546865206e616d6520646f65736e74206578697374210000000000000000000060448201526064016104e9565b60078160405161360f9190614fc4565b9081526040519081900360200190206007015460ff6101009091041615156001141561367d576040516247efb760e81b815260206004820152601860248201527f546865207363686564756c65206973207265766f6b656421000000000000000060448201526064016104e9565b600160078260405161368f9190614fc4565b9081526040519081900360200190206007018054911515610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff9092169190911790556136dd8161425f565b600360008282546136ee91906151fc565b90915550506004805490600061370383615374565b91905055507fac25be9844d7d9cd932afc61fa44fe8e900d3caa5943f907c835703d89805acf8160405161373791906153a9565b60405180910390a150565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610780908490614397565b60606000806137cf61342d565b905060005b6004548163ffffffff161015613861576001600160a01b03851660009081526008602052604081208351849063ffffffff8516908110613816576138166150f3565b602002602001015160405161382b9190614fc4565b90815260405190819003602001902054111561384f578261384b81615156565b9350505b8061385981615122565b9150506137d4565b5060008267ffffffffffffffff81111561387d5761387d6148fe565b6040519080825280602002602001820160405280156138b057816020015b606081526020019060019003908161389b5790505b5090506000805b6004548163ffffffff161015613053576001600160a01b03871660009081526008602052604081208551869063ffffffff85169081106138f9576138f96150f3565b602002602001015160405161390e9190614fc4565b90815260405190819003602001902054111561397057838163ffffffff168151811061393c5761393c6150f3565b6020026020010151838381518110613956576139566150f3565b6020026020010181905250818061396c90615156565b9250505b8061397a81615122565b9150506138b7565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055611ef681612bbf565b60606000806139c061342d565b905060005b6004548163ffffffff161015613a83576001600160a01b03851660009081526008602052604081208351849063ffffffff8516908110613a0757613a076150f3565b6020026020010151604051613a1c9190614fc4565b90815260405190819003602001902054118015613a5e5750613a5c828263ffffffff1681518110613a4f57613a4f6150f3565b6020026020010151612c27565b155b15613a715782613a6d81615156565b9350505b80613a7b81615122565b9150506139c5565b5060008267ffffffffffffffff811115613a9f57613a9f6148fe565b604051908082528060200260200182016040528015613ad257816020015b6060815260200190600190039081613abd5790505b5090506000805b6004548163ffffffff161015613053576001600160a01b03871660009081526008602052604081208551869063ffffffff8516908110613b1b57613b1b6150f3565b6020026020010151604051613b309190614fc4565b90815260405190819003602001902054118015613b655750613b63848263ffffffff1681518110613a4f57613a4f6150f3565b155b15613bb657838163ffffffff1681518110613b8257613b826150f3565b6020026020010151838381518110613b9c57613b9c6150f3565b60200260200101819052508180613bb290615156565b9250505b80613bc081615122565b915050613ad9565b600080600783604051613bdb9190614fc4565b908152602001604051809103902060405180610120016040529081600082018054613c0590614fe0565b80601f0160208091040260200160405190810160405280929190818152602001828054613c3190614fe0565b8015613c7e5780601f10613c5357610100808354040283529160200191613c7e565b820191906000526020600020905b815481529060010190602001808311613c6157829003601f168201915b505050918352505060018201546020820152600282015460408201526003820154606082015260048201546080820152600582015460a080830191909152600683015460c08084019190915260079093015460ff808216151560e0850152610100918290041615159201919091529082015190820151919250611189916151fc565b600080613d0d8484614496565b6001600160a01b03851660009081526008602052604090819020905191925090613d38908590614fc4565b9081526020016040518091039020600101548161342591906151fc565b6001600160a01b038216613d95576040517ff908131300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613d9d61237c565b811115613dad5780610d6561237c565b6119406001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168383613742565b60606002805480602002602001604051908101604052809291908181526020016000905b82821015613eb1578382906000526020600020018054613e2490614fe0565b80601f0160208091040260200160405190810160405280929190818152602001828054613e5090614fe0565b8015613e9d5780601f10613e7257610100808354040283529160200191613e9d565b820191906000526020600020905b815481529060010190602001808311613e8057829003601f168201915b505050505081526020019060010190613e05565b50505050905090565b600080600783604051613ecd9190614fc4565b908152602001604051809103902060405180610120016040529081600082018054613ef790614fe0565b80601f0160208091040260200160405190810160405280929190818152602001828054613f2390614fe0565b8015613f705780601f10613f4557610100808354040283529160200191613f70565b820191906000526020600020905b815481529060010190602001808311613f5357829003601f168201915b505050918352505060018201546020808301919091526002830154604080840191909152600384015460608085019190915260048501546080850152600585015460a0850152600685015460c085015260079094015460ff808216151560e086015261010091829004161515930192909252918301516001600160a01b038816600090815260089093529181902090519293509091614010908690614fc4565b9081526040519081900360200190205461342591906150b8565b61403261305e565b6001600160a01b0381166140a2576040517f252ec7cf00000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f4e6577206f776e65722069732061207a65726f2061646472657373210000000060448201526064016104e9565b600180546001600160a01b0383167fffffffffffffffffffffffff000000000000000000000000000000000000000090911681179091556140eb6000546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6000806007836040516141369190614fc4565b90815260200160405180910390206040518061012001604052908160008201805461416090614fe0565b80601f016020809104026020016040519081016040528092919081815260200182805461418c90614fe0565b80156141d95780601f106141ae576101008083540402835291602001916141d9565b820191906000526020600020905b8154815290600101906020018083116141bc57829003601f168201915b5050509183525050600182015460208201526002820154604080830191909152600383015460608301526004830154608083015260058084015460a0840152600684015460c084015260079093015460ff808216151560e085015261010091829004161515920191909152820151905491925061425591615063565b4210159392505050565b6000806007836040516142729190614fc4565b90815260200160405180910390206040518061012001604052908160008201805461429c90614fe0565b80601f01602080910402602001604051908101604052809291908181526020018280546142c890614fe0565b80156143155780601f106142ea57610100808354040283529160200191614315565b820191906000526020600020905b8154815290600101906020018083116142f857829003601f168201915b50505091835250506001820154602082015260028201546040820152600382015460608201526004820154608080830191909152600583015460a0830152600683015460c08084019190915260079093015460ff808216151560e0850152610100918290041615159201919091529082015190820151919250611189916151fc565b60006143ec826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661464f9092919063ffffffff16565b805190915015610780578080602001905181019061440a91906153bc565b610780576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016104e9565b6000806007836040516144a99190614fc4565b9081526020016040518091039020604051806101200160405290816000820180546144d390614fe0565b80601f01602080910402602001604051908101604052809291908181526020018280546144ff90614fe0565b801561454c5780601f106145215761010080835404028352916020019161454c565b820191906000526020600020905b81548152906001019060200180831161452f57829003601f168201915b5050509183525050600182015460208083019190915260028301546040808401919091526003840154606084015260048401546080840152600584015460a0840152600684015460c084015260079093015460ff808216151560e0850152610100918290041615159201919091526001600160a01b038716600090815260089091528181209151929350916145e2908690614fc4565b9081526040805191829003602090810183208383019092528154835260019091015490820152905061461384612c27565b1561462257519150611e719050565b6060820151815161463286612d83565b61463c919061507b565b61464691906150b8565b95945050505050565b60606134258484600085856001600160a01b0385163b6146cb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016104e9565b600080866001600160a01b031685876040516146e79190614fc4565b60006040518083038185875af1925050503d8060008114614724576040519150601f19603f3d011682016040523d82523d6000602084013e614729565b606091505b5091509150614739828286614744565b979650505050505050565b60608315614753575081611189565b8251156147635782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104e991906153a9565b8280546147a390614fe0565b90600052602060002090601f0160209004810192826147c5576000855561480b565b82601f106147de57805160ff191683800117855561480b565b8280016001018555821561480b579182015b8281111561480b5782518255916020019190600101906147f0565b506148179291506148e9565b5090565b82805461482790614fe0565b90600052602060002090601f016020900481019282614849576000855561480b565b82601f10614880578280017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082351617855561480b565b8280016001018555821561480b579182015b8281111561480b578235825591602001919060010190614892565b60405180604001604052806148dc60405180606001604052806060815260200160008152602001600081525090565b8152602001600081525090565b5b8082111561481757600081556001016148ea565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f83011261493e57600080fd5b813567ffffffffffffffff80821115614959576149596148fe565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171561499f5761499f6148fe565b816040528381528660208588010111156149b857600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000602082840312156149ea57600080fd5b813567ffffffffffffffff811115614a0157600080fd5b6134258482850161492d565b60005b83811015614a28578181015183820152602001614a10565b83811115614a37576000848401525b50505050565b60008151808452614a55816020860160208601614a0d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000815160608452614a9c6060850182614a3d565b905060208301516020850152604083015160408501528091505092915050565b6020815260006111896020830184614a87565b60008083601f840112614ae157600080fd5b50813567ffffffffffffffff811115614af957600080fd5b602083019150836020828501011115614b1157600080fd5b9250929050565b60008060008060008060a08789031215614b3157600080fd5b863567ffffffffffffffff811115614b4857600080fd5b614b5489828a01614acf565b909a90995060208901359860408101359850606081013597506080013595509350505050565b600080600060408486031215614b8f57600080fd5b83359250602084013567ffffffffffffffff811115614bad57600080fd5b614bb986828701614acf565b9497909650939450505050565b80356001600160a01b0381168114614bdd57600080fd5b919050565b60008060008060608587031215614bf857600080fd5b614c0185614bc6565b9350602085013567ffffffffffffffff811115614c1d57600080fd5b614c2987828801614acf565b9598909750949560400135949350505050565b600080600060408486031215614c5157600080fd5b614c5a84614bc6565b9250602084013567ffffffffffffffff811115614bad57600080fd5b60006101208251818552614c8c82860182614a3d565b9150506020830151602085015260408301516040850152606083015160608501526080830151608085015260a083015160a085015260c083015160c085015260e0830151151560e085015261010080840151614ceb8287018215159052565b5090949350505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015614d68577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452614d56858351614c76565b94509285019290850190600101614d1c565b5092979650505050505050565b600060208284031215614d8757600080fd5b61118982614bc6565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b83811015614e3f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0898403018552815160c08151818652614dfb82870182614a3d565b838b0151878c0152898401518a880152606080850151908801526080808501519088015260a093840151939096019290925250509386019390860190600101614db7565b509098975050505050505050565b60008060208385031215614e6057600080fd5b823567ffffffffffffffff811115614e7757600080fd5b614e8385828601614acf565b90969095509350505050565b6020815260006111896020830184614c76565b60008060408385031215614eb557600080fd5b823567ffffffffffffffff811115614ecc57600080fd5b614ed88582860161492d565b95602094909401359450505050565b600080600060608486031215614efc57600080fd5b614f0584614bc6565b9250602084013567ffffffffffffffff811115614f2157600080fd5b614f2d8682870161492d565b925050604084013590509250925092565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b83811015614e3f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc089840301855281518051878552614fa788860182614a87565b918901519489019490945294870194925090860190600101614f65565b60008251614fd6818460208701614a0d565b9190910192915050565b600181811c90821680614ff457607f821691505b6020821081141561502e577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000821982111561507657615076615034565b500190565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156150b3576150b3615034565b500290565b6000826150ee577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600063ffffffff8083168181141561513c5761513c615034565b6001019392505050565b8183823760009101908152919050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561518857615188615034565b5060010190565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b6040815260006151ec60408301858761518f565b9050826020830152949350505050565b60008282101561520e5761520e615034565b500390565b6001600160a01b038616815260806020820152600061523660808301868861518f565b604083019490945250606001529392505050565b8054600090600181811c908083168061526457607f831692505b602080841082141561529f577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b8180156152b357600181146152e25761530e565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0086168952848901965061530e565b876000528160002060005b868110156153065781548b8201529085019083016152ed565b505084890196505b50505050505092915050565b6000611189828461524a565b60006020828403121561533857600080fd5b5051919050565b6001600160a01b03851681526080602082015260006153616080830186614a3d565b6040830194909452506060015292915050565b60008161538357615383615034565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b6020815260006111896020830184614a3d565b6000602082840312156153ce57600080fd5b8151801515811461118957600080fdfea264697066735822122064f02498c1090ba6004d4789ccfbaadc63ab42504e4c505b80f1aa96f5b2220a64736f6c63430008090033000000000000000000000000f9ca9523e5b5a42c3018c62b084db8543478c40000000000000000000000000000000000000000000000000000000000638fd780000000000000000000000000d62ba193d0c0c556d4d37dbbc5e431330471a557

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101f05760003560e01c806379ba50971161010f578063a4317ef4116100a2578063c5f956af11610071578063c5f956af14610429578063e30c39781461043c578063f2fde38b1461044d578063f4c6992b1461046057600080fd5b8063a4317ef4146103f0578063a4e41d29146103f9578063b195880b14610419578063b33712c51461042157600080fd5b806391cf9d09116100de57806391cf9d09146103af57806391d2b32e146103c2578063982d68ba146103ca578063a2aa6859146103dd57600080fd5b806379ba50971461037b5780637d3bca7614610383578063854e089e146103965780638da5cb5b1461039e57600080fd5b8063439766ce116101875780635c975abb116101565780635c975abb1461030f57806364bf72a914610333578063657a0cc81461033b5780636f5bea191461035b57600080fd5b8063439766ce146102d757806353936d3a146102df5780635414a0da146102f25780635b0a38431461030757600080fd5b8063293b26c6116101c3578063293b26c61461027057806329bbda1914610283578063328faf0514610296578063384695dc146102a957600080fd5b806313083617146101f55780631734ed471461020c5780631e4bd42c1461022c57806321df0da714610236575b600080fd5b6002545b6040519081526020015b60405180910390f35b61021f61021a3660046149d8565b610473565b6040516102039190614abc565b61023461069c565b005b7f000000000000000000000000f9ca9523e5b5a42c3018c62b084db8543478c4005b6040516001600160a01b039091168152602001610203565b61023461027e366004614b18565b610785565b610234610291366004614b7a565b610bd8565b6102346102a4366004614be2565b610df6565b6102bc6102b7366004614c3c565b611123565b60408051825181526020928301519281019290925201610203565b610234611190565b6102346102ed366004614b7a565b611248565b6102fa6113b3565b6040516102039190614cf5565b6102346116ff565b60065461032390600160a01b900460ff1681565b6040519015158152602001610203565b6101f9611944565b61034e610349366004614d75565b611a0a565b6040516102039190614d90565b61036e610369366004614e4d565b611d03565b6040516102039190614e8f565b610234611e77565b610234610391366004614d75565b611ef9565b6004546101f9565b6000546001600160a01b0316610258565b6102346103bd366004614ea2565b612120565b6101f961237c565b6102346103d83660046149d8565b6123ee565b6102346103eb366004614ee7565b61243b565b6101f960055481565b61040c610407366004614d75565b6126a5565b6040516102039190614f3e565b6102fa6127f6565b610234612a73565b600654610258906001600160a01b031681565b6001546001600160a01b0316610258565b61023461045b366004614d75565b612b1e565b61023461046e3660046149d8565b612b6b565b61049760405180606001604052806060815260200160008152602001600081525090565b6104a082612c27565b156104f2576040516247efb760e81b815260206004820152601960248201527f546865207363686564756c652069732066696e6973686564210000000000000060448201526064015b60405180910390fd5b60006007836040516105049190614fc4565b90815260200160405180910390206040518061012001604052908160008201805461052e90614fe0565b80601f016020809104026020016040519081016040528092919081815260200182805461055a90614fe0565b80156105a75780601f1061057c576101008083540402835291602001916105a7565b820191906000526020600020905b81548152906001019060200180831161058a57829003601f168201915b505050918352505060018201546020820152600282015460408201526003820154606082015260048201546080820152600582015460a0820152600682015460c082015260079091015460ff808216151560e0840152610100918290041615159101529050600061061784612d83565b905061063d60405180606001604052806060815260200160008152602001600081525090565b84815261064b826001615063565b836020015161065a919061507b565b836040015160055461066c9190615063565b6106769190615063565b60408201526060830151608084015161068f91906150b8565b6020820152949350505050565b600654600160a01b900460ff16156106d85760065460405163117beb8560e01b8152600160a01b90910460ff16151560048201526024016104e9565b60006106e333612ef8565b805190915080610735576040516247efb760e81b815260206004820152601e60248201527f546865726520617265206e6f20756e636c61696d656420746f6b656e7321000060448201526064016104e9565b60005b818163ffffffff1610156107805761076e838263ffffffff1681518110610761576107616150f3565b6020026020010151612b6b565b8061077881615122565b915050610738565b505050565b61078d61305e565b6000610797611944565b600654909150600160a01b900460ff16156107d65760065460405163117beb8560e01b8152600160a01b90910460ff16151560048201526024016104e9565b85610823576040516247efb760e81b815260206004820152601260248201527f546865206e616d6520697320656d70747921000000000000000000000000000060448201526064016104e9565b61086287878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506130d492505050565b6108ae576040516247efb760e81b815260206004820152601760248201527f546865206e616d65206973206475706c6963617465642100000000000000000060448201526064016104e9565b818110156108f2576040517f3b94d60600000000000000000000000000000000000000000000000000000000815260048101839052602481018290526044016104e9565b8261093f576040516247efb760e81b815260206004820152601560248201527f546865206475726174696f6e206973207a65726f21000000000000000000000060448201526064016104e9565b81610976576040517f135bf91600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b846109c3576040516247efb760e81b815260206004820152601360248201527f546865207465726d7320617265207a65726f210000000000000000000000000060448201526064016104e9565b60405180610120016040528088888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920182905250938552505050602082018890526040808301889052606083018790526080830186905260a0830182905260c08301829052600160e08401526101009092015251600790610a51908a908a90615146565b90815260200160405180910390206000820151816000019080519060200190610a7b929190614797565b50602082015160018201556040820151600282015560608201516003808301919091556080830151600483015560a0830151600583015560c0830151600683015560e083015160079092018054610100948501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00009091169315157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1693909317921515909302919091179091558054839190600090610b3c908490615063565b909155505060028054600181018255600091909152610b7e907f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace01888861481b565b5060048054906000610b8f83615156565b91905055507f37c575cf070e40f0e3e97de202fab4d5e34c8e88ed11783b252f0951b5c6d310878784604051610bc7939291906151d8565b60405180910390a150505050505050565b610be061305e565b600654600160a01b900460ff1615610c1c5760065460405163117beb8560e01b8152600160a01b90910460ff16151560048201526024016104e9565b610c5b82828080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506130d492505050565b15610ca8576040516247efb760e81b815260206004820152601660248201527f546865206e616d6520646f65736e74206578697374210000000000000000000060448201526064016104e9565b82610cdf576040517f135bf91600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82610d1f83838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061315692505050565b1015610da05782610d6583838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061315692505050565b6040517f3b94d606000000000000000000000000000000000000000000000000000000008152600481019290925260248201526044016104e9565b8260078383604051610db3929190615146565b90815260200160405180910390206004016000828254610dd391906151fc565b925050819055508260036000828254610dec91906151fc565b9091555050505050565b610dfe61305e565b600654600160a01b900460ff1615610e3a5760065460405163117beb8560e01b8152600160a01b90910460ff16151560048201526024016104e9565b6001600160a01b038416610e7a576040517ff908131300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80610eb1576040517f135bf91600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81610efe576040516247efb760e81b815260206004820152601260248201527f546865206e616d6520697320656d70747921000000000000000000000000000060448201526064016104e9565b610f3d83838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061328e92505050565b610f89576040516247efb760e81b815260206004820152601460248201527f546865206e616d6520697320696e76616c69642100000000000000000000000060448201526064016104e9565b80610fca8585858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506133c892505050565b10156110115780610d658585858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506133c892505050565b6001600160a01b03841660009081526008602052604090819020905182919061103d9086908690615146565b9081526020016040518091039020600001600082825461105d91906151fc565b925050819055508060078484604051611077929190615146565b9081526020016040518091039020600501600082825461109791906151fc565b925050819055507fcb6b75de6dac337ab06e18a20ee2bd260f10cbcecd1a495501b47b0aef412db584848484600860008a6001600160a01b03166001600160a01b0316815260200190815260200160002088886040516110f8929190615146565b908152604051908190036020018120546111159594939291615213565b60405180910390a150505050565b60408051808201909152600080825260208201526001600160a01b0384166000908152600860205260409081902090516111609085908590615146565b908152604080519182900360209081018320838301909252815483526001909101549082015290505b9392505050565b61119861305e565b600654600160a01b900460ff16156111d45760065460405163117beb8560e01b8152600160a01b90910460ff16151560048201526024016104e9565b600680547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16600160a01b908117918290556040517f752d7e161ff5146f80e3820893176eb40532811e5e20400dfdde57455213706a9261123e92900460ff161515815260200190565b60405180910390a1565b61125061305e565b600654600160a01b900460ff161561128c5760065460405163117beb8560e01b8152600160a01b90910460ff16151560048201526024016104e9565b6112cb82828080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506130d492505050565b15611318576040516247efb760e81b815260206004820152601660248201527f546865206e616d6520646f65736e74206578697374210000000000000000000060448201526064016104e9565b8261134f576040517f135bf91600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82611358611944565b10156113675782610d65611944565b826007838360405161137a929190615146565b9081526020016040518091039020600401600082825461139a9190615063565b925050819055508260036000828254610dec9190615063565b606060045460001415611408576040516247efb760e81b815260206004820152601b60248201527f4e6f2076616c69642076657374696e67207363686564756c657321000000000060448201526064016104e9565b600060045467ffffffffffffffff811115611425576114256148fe565b6040519080825280602002602001820160405280156114a957816020015b611496604051806101200160405280606081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000151581526020016000151581525090565b8152602001906001900390816114435790505b5090506000805b6004548163ffffffff1610156116f75761157460028263ffffffff16815481106114dc576114dc6150f3565b9060005260206000200180546114f190614fe0565b80601f016020809104026020016040519081016040528092919081815260200182805461151d90614fe0565b801561156a5780601f1061153f5761010080835404028352916020019161156a565b820191906000526020600020905b81548152906001019060200180831161154d57829003601f168201915b505050505061328e565b156116e557600760028263ffffffff1681548110611594576115946150f3565b906000526020600020016040516115ab919061531a565b9081526020016040518091039020604051806101200160405290816000820180546115d590614fe0565b80601f016020809104026020016040519081016040528092919081815260200182805461160190614fe0565b801561164e5780601f106116235761010080835404028352916020019161164e565b820191906000526020600020905b81548152906001019060200180831161163157829003601f168201915b505050918352505060018201546020820152600282015460408201526003820154606082015260048201546080820152600582015460a0820152600682015460c082015260079091015460ff808216151560e0840152610100918290041615159101528351849063ffffffff85169081106116cb576116cb6150f3565b602002602001018190525081806116e190615122565b9250505b806116ef81615122565b9150506114b0565b509092915050565b61170761305e565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000f9ca9523e5b5a42c3018c62b084db8543478c4006001600160a01b0316906370a082319060240160206040518083038186803b15801561177f57600080fd5b505afa158015611793573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117b79190615326565b611803576040516247efb760e81b815260206004820152601460248201527f4e6f7468696e6720746f2077697468647261772100000000000000000000000060448201526064016104e9565b600061180d61342d565b805190915060005b818110156118515761183f838281518110611832576118326150f3565b60200260200101516135a9565b8061184981615156565b915050611815565b506006546040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152611940916001600160a01b03908116917f000000000000000000000000f9ca9523e5b5a42c3018c62b084db8543478c400909116906370a082319060240160206040518083038186803b1580156118d757600080fd5b505afa1580156118eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061190f9190615326565b6001600160a01b037f000000000000000000000000f9ca9523e5b5a42c3018c62b084db8543478c400169190613742565b5050565b6003546040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152600091906001600160a01b037f000000000000000000000000f9ca9523e5b5a42c3018c62b084db8543478c40016906370a082319060240160206040518083038186803b1580156119c357600080fd5b505afa1580156119d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119fb9190615326565b611a0591906151fc565b905090565b60606000611a17836137c2565b805190915080611a53576040517f1e79856100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008167ffffffffffffffff811115611a6e57611a6e6148fe565b604051908082528060200260200182016040528015611ad857816020015b611ac56040518060c001604052806060815260200160008152602001600081526020016000815260200160008152602001600081525090565b815260200190600190039081611a8c5790505b50905060005b828163ffffffff161015611cfa5760006040518060c00160405280868463ffffffff1681518110611b1157611b116150f3565b602002602001015181526020016007878563ffffffff1681518110611b3857611b386150f3565b6020026020010151604051611b4d9190614fc4565b90815260200160405180910390206001015481526020016007878563ffffffff1681518110611b7e57611b7e6150f3565b6020026020010151604051611b939190614fc4565b90815260200160405180910390206002015481526020016007878563ffffffff1681518110611bc457611bc46150f3565b6020026020010151604051611bd99190614fc4565b9081526020016040518091039020600301548152602001600860008a6001600160a01b03166001600160a01b03168152602001908152602001600020878563ffffffff1681518110611c2d57611c2d6150f3565b6020026020010151604051611c429190614fc4565b9081526020016040518091039020600001548152602001600860008a6001600160a01b03166001600160a01b03168152602001908152602001600020878563ffffffff1681518110611c9657611c966150f3565b6020026020010151604051611cab9190614fc4565b908152602001604051809103902060010154815250905080838363ffffffff1681518110611cdb57611cdb6150f3565b6020026020010181905250508080611cf290615122565b915050611ade565b50949350505050565b611d56604051806101200160405280606081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000151581526020016000151581525090565b60078383604051611d68929190615146565b908152602001604051809103902060405180610120016040529081600082018054611d9290614fe0565b80601f0160208091040260200160405190810160405280929190818152602001828054611dbe90614fe0565b8015611e0b5780601f10611de057610100808354040283529160200191611e0b565b820191906000526020600020905b815481529060010190602001808311611dee57829003601f168201915b505050918352505060018201546020820152600282015460408201526003820154606082015260048201546080820152600582015460a0820152600682015460c082015260079091015460ff808216151560e08401526101009182900416151591015290505b92915050565b60015433906001600160a01b03168114611eed576040517f252ec7cf00000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f43616c6c6572206973206e6f7420746865206e6577206f776e6572210000000060448201526064016104e9565b611ef681613982565b50565b611f0161305e565b6001600160a01b038116611f41576040517ff908131300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600654600160a01b900460ff1615611f7d5760065460405163117beb8560e01b8152600160a01b90910460ff16151560048201526024016104e9565b6000611f88826139b3565b805190915080611fc4576040517f1e79856100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b818163ffffffff1610156120dd57600061200085858463ffffffff1681518110611ff357611ff36150f3565b60200260200101516133c8565b6001600160a01b038616600090815260086020526040902085519192508291869063ffffffff8616908110612037576120376150f3565b602002602001015160405161204c9190614fc4565b9081526020016040518091039020600001600082825461206c91906151fc565b92505081905550806007858463ffffffff168151811061208e5761208e6150f3565b60200260200101516040516120a39190614fc4565b908152602001604051809103902060050160008282546120c391906151fc565b909155508291506120d5905081615122565b915050611fc7565b506040516001600160a01b03841681527ff5a46f0b640efde5acf94b5c5611e5ee1d1dabaf5c4e624911901e83623689f2906020015b60405180910390a1505050565b600654600160a01b900460ff161561215c5760065460405163117beb8560e01b8152600160a01b90910460ff16151560048201526024016104e9565b81516121aa576040516247efb760e81b815260206004820152601260248201527f546865206e616d6520697320656d70747921000000000000000000000000000060448201526064016104e9565b6121b38261328e565b6121ff576040516247efb760e81b815260206004820152601460248201527f546865206e616d6520697320696e76616c69642100000000000000000000000060448201526064016104e9565b80612236576040517f135bf91600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8061224083613bc8565b10156122505780610d6583613bc8565b8061225c335b84613d00565b101561226c5780610d6533612256565b6122763382613d55565b806003600082825461228891906151fc565b92505081905550806007836040516122a09190614fc4565b908152602001604051809103902060060160008282546122c09190615063565b9091555050336000908152600860205260409081902090518291906122e6908590614fc4565b908152602001604051809103902060010160008282546123069190615063565b9091555050336000818152600860205260409081902090517f404130b82350104f12b628380e26256559246fb39f9124791864b4b3062aadb692918591859190612351908490614fc4565b908152604051908190036020018120600101546123709493929161533f565b60405180910390a15050565b6000806000612389613de1565b805190915060005b818163ffffffff1610156123e5576123c7838263ffffffff16815181106123ba576123ba6150f3565b6020026020010151613bc8565b6123d19085615063565b9350806123dd81615122565b915050612391565b50919392505050565b6123f661305e565b600654600160a01b900460ff16156124325760065460405163117beb8560e01b8152600160a01b90910460ff16151560048201526024016104e9565b611ef6816135a9565b61244361305e565b600654600160a01b900460ff161561247f5760065460405163117beb8560e01b8152600160a01b90910460ff16151560048201526024016104e9565b6001600160a01b0383166124bf576040517ff908131300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815161250d576040516247efb760e81b815260206004820152601260248201527f546865206e616d6520697320656d70747921000000000000000000000000000060448201526064016104e9565b80612544576040517f135bf91600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61254d8261328e565b612599576040516247efb760e81b815260206004820152601860248201527f546865207363686564756c6520697320696e76616c696421000000000000000060448201526064016104e9565b806125a383613156565b10156125b35780610d6583613156565b6001600160a01b0383166000908152600860205260409081902090518291906125dd908590614fc4565b908152602001604051809103902060000160008282546125fd9190615063565b92505081905550806007836040516126159190614fc4565b908152602001604051809103902060050160008282546126359190615063565b90915550506001600160a01b0383166000908152600860205260409081902090517fd1eabf10ff5c5af40aada9f67d087cdb8964e16287ea3580e84defda96f10f9191859185918591612689908490614fc4565b908152604051908190036020018120546121139493929161533f565b606060006126b2836139b3565b8051909150806126ee576040517f1e79856100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008167ffffffffffffffff811115612709576127096148fe565b60405190808252806020026020018201604052801561274257816020015b61272f6148ad565b8152602001906001900390816127275790505b50905060005b828163ffffffff161015611cfa576000604051806040016040528061278b878563ffffffff168151811061277e5761277e6150f3565b6020026020010151610473565b81526020016127b989888663ffffffff16815181106127ac576127ac6150f3565b6020026020010151613eba565b815250905080838363ffffffff16815181106127d7576127d76150f3565b60200260200101819052505080806127ee90615122565b915050612748565b60025460609080612849576040516247efb760e81b815260206004820152601560248201527f4e6f2076657374696e67207363686564756c657321000000000000000000000060448201526064016104e9565b60008167ffffffffffffffff811115612864576128646148fe565b6040519080825280602002602001820160405280156128e857816020015b6128d5604051806101200160405280606081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000151581526020016000151581525090565b8152602001906001900390816128825790505b50905060005b828163ffffffff161015612a6c57600760028263ffffffff1681548110612917576129176150f3565b9060005260206000200160405161292e919061531a565b90815260200160405180910390206040518061012001604052908160008201805461295890614fe0565b80601f016020809104026020016040519081016040528092919081815260200182805461298490614fe0565b80156129d15780601f106129a6576101008083540402835291602001916129d1565b820191906000526020600020905b8154815290600101906020018083116129b457829003601f168201915b505050918352505060018201546020820152600282015460408201526003820154606082015260048201546080820152600582015460a0820152600682015460c082015260079091015460ff808216151560e0840152610100918290041615159101528251839063ffffffff8416908110612a4e57612a4e6150f3565b60200260200101819052508080612a6490615122565b9150506128ee565b5092915050565b612a7b61305e565b600654600160a01b900460ff16612ab65760065460405163117beb8560e01b8152600160a01b90910460ff16151560048201526024016104e9565b600680547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16908190556040517f752d7e161ff5146f80e3820893176eb40532811e5e20400dfdde57455213706a9161123e91600160a01b90910460ff161515815260200190565b612b2661305e565b600654600160a01b900460ff1615612b625760065460405163117beb8560e01b8152600160a01b90910460ff16151560048201526024016104e9565b611ef68161402a565b600654600160a01b900460ff1615612ba75760065460405163117beb8560e01b8152600160a01b90910460ff16151560048201526024016104e9565b6000612bb33383613d00565b90506119408282612120565b600080546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600080600783604051612c3a9190614fc4565b908152602001604051809103902060405180610120016040529081600082018054612c6490614fe0565b80601f0160208091040260200160405190810160405280929190818152602001828054612c9090614fe0565b8015612cdd5780601f10612cb257610100808354040283529160200191612cdd565b820191906000526020600020905b815481529060010190602001808311612cc057829003601f168201915b5050509183525050600182015460208083019190915260028301546040830152600383015460608084019190915260048401546080840152600584015460a0840152600684015460c084015260079093015460ff808216151560e08501526101009182900416151592019190915282015190820151919250612d5e9161507b565b8160400151600554612d709190615063565b612d7a9190615063565b42119392505050565b600080600783604051612d969190614fc4565b908152602001604051809103902060405180610120016040529081600082018054612dc090614fe0565b80601f0160208091040260200160405190810160405280929190818152602001828054612dec90614fe0565b8015612e395780601f10612e0e57610100808354040283529160200191612e39565b820191906000526020600020905b815481529060010190602001808311612e1c57829003601f168201915b505050918352505060018201546020820152600282015460408201526003820154606082015260048201546080820152600582015460a0820152600682015460c082015260079091015460ff808216151560e0840152610100918290041615159101529050612ea783614123565b15612ed75760208101516040820151600554612ec390426151fc565b612ecd91906151fc565b61118991906150b8565b612ee083612c27565b15612eef576060015192915050565b50600092915050565b6060600080612f0561342d565b905060005b6004548163ffffffff161015612f6b576000612f4586848463ffffffff1681518110612f3857612f386150f3565b6020026020010151613d00565b1115612f595782612f5581615156565b9350505b80612f6381615122565b915050612f0a565b5060008267ffffffffffffffff811115612f8757612f876148fe565b604051908082528060200260200182016040528015612fba57816020015b6060815260200190600190039081612fa55790505b5090506000805b6004548163ffffffff161015613053576000612fef88868463ffffffff1681518110612f3857612f386150f3565b111561304157838163ffffffff168151811061300d5761300d6150f3565b6020026020010151838381518110613027576130276150f3565b6020026020010181905250818061303d90615156565b9250505b8061304b81615122565b915050612fc1565b509095945050505050565b6000546001600160a01b031633146130d2576040517f43069fd000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f43616c6c6572206973206e6f7420746865206f776e657221000000000000000060448201526064016104e9565b565b600254600090815b818163ffffffff16101561314c57838051906020012060028263ffffffff168154811061310b5761310b6150f3565b90600052602060002001604051613122919061531a565b6040518091039020141561313a575060009392505050565b8061314481615122565b9150506130dc565b5060019392505050565b6000806007836040516131699190614fc4565b90815260200160405180910390206040518061012001604052908160008201805461319390614fe0565b80601f01602080910402602001604051908101604052809291908181526020018280546131bf90614fe0565b801561320c5780601f106131e15761010080835404028352916020019161320c565b820191906000526020600020905b8154815290600101906020018083116131ef57829003601f168201915b50505091835250506001820154602082015260028201546040820152600382015460608201526004820154608080830191909152600583015460a080840191909152600684015460c084015260079093015460ff808216151560e0850152610100918290041615159201919091529082015190820151919250611189916151fc565b6000806007836040516132a19190614fc4565b9081526020016040518091039020604051806101200160405290816000820180546132cb90614fe0565b80601f01602080910402602001604051908101604052809291908181526020018280546132f790614fe0565b80156133445780601f1061331957610100808354040283529160200191613344565b820191906000526020600020905b81548152906001019060200180831161332757829003601f168201915b505050918352505060018201546020820152600282015460408201526003820154606082015260048201546080820152600582015460a0820152600682015460c082015260079091015460ff808216151560e08085019190915261010092839004909116151591909201528101519091508015611189575061010001511592915050565b6001600160a01b03821660009081526008602052604080822090518291906133f1908590614fc4565b90815260408051602092819003830181208183019092528154808252600190920154928101839052925061342591906151fc565b949350505050565b6060600060045467ffffffffffffffff81111561344c5761344c6148fe565b60405190808252806020026020018201604052801561347f57816020015b606081526020019060019003908161346a5790505b506002549091506000805b828163ffffffff1610156123e5576134b460028263ffffffff16815481106114dc576114dc6150f3565b156135975760028163ffffffff16815481106134d2576134d26150f3565b9060005260206000200180546134e790614fe0565b80601f016020809104026020016040519081016040528092919081815260200182805461351390614fe0565b80156135605780601f1061353557610100808354040283529160200191613560565b820191906000526020600020905b81548152906001019060200180831161354357829003601f168201915b5050505050848363ffffffff168151811061357d5761357d6150f3565b6020026020010181905250818061359390615122565b9250505b806135a181615122565b91505061348a565b6135b2816130d4565b156135ff576040516247efb760e81b815260206004820152601660248201527f546865206e616d6520646f65736e74206578697374210000000000000000000060448201526064016104e9565b60078160405161360f9190614fc4565b9081526040519081900360200190206007015460ff6101009091041615156001141561367d576040516247efb760e81b815260206004820152601860248201527f546865207363686564756c65206973207265766f6b656421000000000000000060448201526064016104e9565b600160078260405161368f9190614fc4565b9081526040519081900360200190206007018054911515610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff9092169190911790556136dd8161425f565b600360008282546136ee91906151fc565b90915550506004805490600061370383615374565b91905055507fac25be9844d7d9cd932afc61fa44fe8e900d3caa5943f907c835703d89805acf8160405161373791906153a9565b60405180910390a150565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610780908490614397565b60606000806137cf61342d565b905060005b6004548163ffffffff161015613861576001600160a01b03851660009081526008602052604081208351849063ffffffff8516908110613816576138166150f3565b602002602001015160405161382b9190614fc4565b90815260405190819003602001902054111561384f578261384b81615156565b9350505b8061385981615122565b9150506137d4565b5060008267ffffffffffffffff81111561387d5761387d6148fe565b6040519080825280602002602001820160405280156138b057816020015b606081526020019060019003908161389b5790505b5090506000805b6004548163ffffffff161015613053576001600160a01b03871660009081526008602052604081208551869063ffffffff85169081106138f9576138f96150f3565b602002602001015160405161390e9190614fc4565b90815260405190819003602001902054111561397057838163ffffffff168151811061393c5761393c6150f3565b6020026020010151838381518110613956576139566150f3565b6020026020010181905250818061396c90615156565b9250505b8061397a81615122565b9150506138b7565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055611ef681612bbf565b60606000806139c061342d565b905060005b6004548163ffffffff161015613a83576001600160a01b03851660009081526008602052604081208351849063ffffffff8516908110613a0757613a076150f3565b6020026020010151604051613a1c9190614fc4565b90815260405190819003602001902054118015613a5e5750613a5c828263ffffffff1681518110613a4f57613a4f6150f3565b6020026020010151612c27565b155b15613a715782613a6d81615156565b9350505b80613a7b81615122565b9150506139c5565b5060008267ffffffffffffffff811115613a9f57613a9f6148fe565b604051908082528060200260200182016040528015613ad257816020015b6060815260200190600190039081613abd5790505b5090506000805b6004548163ffffffff161015613053576001600160a01b03871660009081526008602052604081208551869063ffffffff8516908110613b1b57613b1b6150f3565b6020026020010151604051613b309190614fc4565b90815260405190819003602001902054118015613b655750613b63848263ffffffff1681518110613a4f57613a4f6150f3565b155b15613bb657838163ffffffff1681518110613b8257613b826150f3565b6020026020010151838381518110613b9c57613b9c6150f3565b60200260200101819052508180613bb290615156565b9250505b80613bc081615122565b915050613ad9565b600080600783604051613bdb9190614fc4565b908152602001604051809103902060405180610120016040529081600082018054613c0590614fe0565b80601f0160208091040260200160405190810160405280929190818152602001828054613c3190614fe0565b8015613c7e5780601f10613c5357610100808354040283529160200191613c7e565b820191906000526020600020905b815481529060010190602001808311613c6157829003601f168201915b505050918352505060018201546020820152600282015460408201526003820154606082015260048201546080820152600582015460a080830191909152600683015460c08084019190915260079093015460ff808216151560e0850152610100918290041615159201919091529082015190820151919250611189916151fc565b600080613d0d8484614496565b6001600160a01b03851660009081526008602052604090819020905191925090613d38908590614fc4565b9081526020016040518091039020600101548161342591906151fc565b6001600160a01b038216613d95576040517ff908131300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613d9d61237c565b811115613dad5780610d6561237c565b6119406001600160a01b037f000000000000000000000000f9ca9523e5b5a42c3018c62b084db8543478c400168383613742565b60606002805480602002602001604051908101604052809291908181526020016000905b82821015613eb1578382906000526020600020018054613e2490614fe0565b80601f0160208091040260200160405190810160405280929190818152602001828054613e5090614fe0565b8015613e9d5780601f10613e7257610100808354040283529160200191613e9d565b820191906000526020600020905b815481529060010190602001808311613e8057829003601f168201915b505050505081526020019060010190613e05565b50505050905090565b600080600783604051613ecd9190614fc4565b908152602001604051809103902060405180610120016040529081600082018054613ef790614fe0565b80601f0160208091040260200160405190810160405280929190818152602001828054613f2390614fe0565b8015613f705780601f10613f4557610100808354040283529160200191613f70565b820191906000526020600020905b815481529060010190602001808311613f5357829003601f168201915b505050918352505060018201546020808301919091526002830154604080840191909152600384015460608085019190915260048501546080850152600585015460a0850152600685015460c085015260079094015460ff808216151560e086015261010091829004161515930192909252918301516001600160a01b038816600090815260089093529181902090519293509091614010908690614fc4565b9081526040519081900360200190205461342591906150b8565b61403261305e565b6001600160a01b0381166140a2576040517f252ec7cf00000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f4e6577206f776e65722069732061207a65726f2061646472657373210000000060448201526064016104e9565b600180546001600160a01b0383167fffffffffffffffffffffffff000000000000000000000000000000000000000090911681179091556140eb6000546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6000806007836040516141369190614fc4565b90815260200160405180910390206040518061012001604052908160008201805461416090614fe0565b80601f016020809104026020016040519081016040528092919081815260200182805461418c90614fe0565b80156141d95780601f106141ae576101008083540402835291602001916141d9565b820191906000526020600020905b8154815290600101906020018083116141bc57829003601f168201915b5050509183525050600182015460208201526002820154604080830191909152600383015460608301526004830154608083015260058084015460a0840152600684015460c084015260079093015460ff808216151560e085015261010091829004161515920191909152820151905491925061425591615063565b4210159392505050565b6000806007836040516142729190614fc4565b90815260200160405180910390206040518061012001604052908160008201805461429c90614fe0565b80601f01602080910402602001604051908101604052809291908181526020018280546142c890614fe0565b80156143155780601f106142ea57610100808354040283529160200191614315565b820191906000526020600020905b8154815290600101906020018083116142f857829003601f168201915b50505091835250506001820154602082015260028201546040820152600382015460608201526004820154608080830191909152600583015460a0830152600683015460c08084019190915260079093015460ff808216151560e0850152610100918290041615159201919091529082015190820151919250611189916151fc565b60006143ec826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661464f9092919063ffffffff16565b805190915015610780578080602001905181019061440a91906153bc565b610780576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016104e9565b6000806007836040516144a99190614fc4565b9081526020016040518091039020604051806101200160405290816000820180546144d390614fe0565b80601f01602080910402602001604051908101604052809291908181526020018280546144ff90614fe0565b801561454c5780601f106145215761010080835404028352916020019161454c565b820191906000526020600020905b81548152906001019060200180831161452f57829003601f168201915b5050509183525050600182015460208083019190915260028301546040808401919091526003840154606084015260048401546080840152600584015460a0840152600684015460c084015260079093015460ff808216151560e0850152610100918290041615159201919091526001600160a01b038716600090815260089091528181209151929350916145e2908690614fc4565b9081526040805191829003602090810183208383019092528154835260019091015490820152905061461384612c27565b1561462257519150611e719050565b6060820151815161463286612d83565b61463c919061507b565b61464691906150b8565b95945050505050565b60606134258484600085856001600160a01b0385163b6146cb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016104e9565b600080866001600160a01b031685876040516146e79190614fc4565b60006040518083038185875af1925050503d8060008114614724576040519150601f19603f3d011682016040523d82523d6000602084013e614729565b606091505b5091509150614739828286614744565b979650505050505050565b60608315614753575081611189565b8251156147635782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104e991906153a9565b8280546147a390614fe0565b90600052602060002090601f0160209004810192826147c5576000855561480b565b82601f106147de57805160ff191683800117855561480b565b8280016001018555821561480b579182015b8281111561480b5782518255916020019190600101906147f0565b506148179291506148e9565b5090565b82805461482790614fe0565b90600052602060002090601f016020900481019282614849576000855561480b565b82601f10614880578280017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082351617855561480b565b8280016001018555821561480b579182015b8281111561480b578235825591602001919060010190614892565b60405180604001604052806148dc60405180606001604052806060815260200160008152602001600081525090565b8152602001600081525090565b5b8082111561481757600081556001016148ea565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f83011261493e57600080fd5b813567ffffffffffffffff80821115614959576149596148fe565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171561499f5761499f6148fe565b816040528381528660208588010111156149b857600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000602082840312156149ea57600080fd5b813567ffffffffffffffff811115614a0157600080fd5b6134258482850161492d565b60005b83811015614a28578181015183820152602001614a10565b83811115614a37576000848401525b50505050565b60008151808452614a55816020860160208601614a0d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000815160608452614a9c6060850182614a3d565b905060208301516020850152604083015160408501528091505092915050565b6020815260006111896020830184614a87565b60008083601f840112614ae157600080fd5b50813567ffffffffffffffff811115614af957600080fd5b602083019150836020828501011115614b1157600080fd5b9250929050565b60008060008060008060a08789031215614b3157600080fd5b863567ffffffffffffffff811115614b4857600080fd5b614b5489828a01614acf565b909a90995060208901359860408101359850606081013597506080013595509350505050565b600080600060408486031215614b8f57600080fd5b83359250602084013567ffffffffffffffff811115614bad57600080fd5b614bb986828701614acf565b9497909650939450505050565b80356001600160a01b0381168114614bdd57600080fd5b919050565b60008060008060608587031215614bf857600080fd5b614c0185614bc6565b9350602085013567ffffffffffffffff811115614c1d57600080fd5b614c2987828801614acf565b9598909750949560400135949350505050565b600080600060408486031215614c5157600080fd5b614c5a84614bc6565b9250602084013567ffffffffffffffff811115614bad57600080fd5b60006101208251818552614c8c82860182614a3d565b9150506020830151602085015260408301516040850152606083015160608501526080830151608085015260a083015160a085015260c083015160c085015260e0830151151560e085015261010080840151614ceb8287018215159052565b5090949350505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015614d68577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452614d56858351614c76565b94509285019290850190600101614d1c565b5092979650505050505050565b600060208284031215614d8757600080fd5b61118982614bc6565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b83811015614e3f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0898403018552815160c08151818652614dfb82870182614a3d565b838b0151878c0152898401518a880152606080850151908801526080808501519088015260a093840151939096019290925250509386019390860190600101614db7565b509098975050505050505050565b60008060208385031215614e6057600080fd5b823567ffffffffffffffff811115614e7757600080fd5b614e8385828601614acf565b90969095509350505050565b6020815260006111896020830184614c76565b60008060408385031215614eb557600080fd5b823567ffffffffffffffff811115614ecc57600080fd5b614ed88582860161492d565b95602094909401359450505050565b600080600060608486031215614efc57600080fd5b614f0584614bc6565b9250602084013567ffffffffffffffff811115614f2157600080fd5b614f2d8682870161492d565b925050604084013590509250925092565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b83811015614e3f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc089840301855281518051878552614fa788860182614a87565b918901519489019490945294870194925090860190600101614f65565b60008251614fd6818460208701614a0d565b9190910192915050565b600181811c90821680614ff457607f821691505b6020821081141561502e577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000821982111561507657615076615034565b500190565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156150b3576150b3615034565b500290565b6000826150ee577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600063ffffffff8083168181141561513c5761513c615034565b6001019392505050565b8183823760009101908152919050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561518857615188615034565b5060010190565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b6040815260006151ec60408301858761518f565b9050826020830152949350505050565b60008282101561520e5761520e615034565b500390565b6001600160a01b038616815260806020820152600061523660808301868861518f565b604083019490945250606001529392505050565b8054600090600181811c908083168061526457607f831692505b602080841082141561529f577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b8180156152b357600181146152e25761530e565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0086168952848901965061530e565b876000528160002060005b868110156153065781548b8201529085019083016152ed565b505084890196505b50505050505092915050565b6000611189828461524a565b60006020828403121561533857600080fd5b5051919050565b6001600160a01b03851681526080602082015260006153616080830186614a3d565b6040830194909452506060015292915050565b60008161538357615383615034565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b6020815260006111896020830184614a3d565b6000602082840312156153ce57600080fd5b8151801515811461118957600080fdfea264697066735822122064f02498c1090ba6004d4789ccfbaadc63ab42504e4c505b80f1aa96f5b2220a64736f6c63430008090033

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

000000000000000000000000f9ca9523e5b5a42c3018c62b084db8543478c40000000000000000000000000000000000000000000000000000000000638fd780000000000000000000000000d62ba193d0c0c556d4d37dbbc5e431330471a557

-----Decoded View---------------
Arg [0] : _tokenContractAddress (address): 0xF9Ca9523E5b5A42C3018C62B084Db8543478C400
Arg [1] : _tgeTimestamp (uint256): 1670371200
Arg [2] : _treasuryAddress (address): 0xD62Ba193D0c0C556D4D37DbbC5e431330471a557

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000f9ca9523e5b5a42c3018c62b084db8543478c400
Arg [1] : 00000000000000000000000000000000000000000000000000000000638fd780
Arg [2] : 000000000000000000000000d62ba193d0c0c556d4d37dbbc5e431330471a557


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.