ETH Price: $3,458.39 (-0.71%)
Gas: 2 Gwei

Contract

0xcaf5b5D268032a41cAF34d9280A1857E3394Ba47
 

Overview

ETH Balance

0.011341414756521 ETH

Eth Value

$39.22 (@ $3,458.39/ETH)

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
Claim Tokens202147642024-07-01 22:49:595 hrs ago1719874199IN
0xcaf5b5D2...E3394Ba47
0 ETH0.000414862.98186246
Claim Tokens202122002024-07-01 14:15:2314 hrs ago1719843323IN
0xcaf5b5D2...E3394Ba47
0 ETH0.001447728.35239824
Claim Tokens202111232024-07-01 10:38:4717 hrs ago1719830327IN
0xcaf5b5D2...E3394Ba47
0 ETH0.000514693.626072
Claim Tokens202110822024-07-01 10:30:3518 hrs ago1719829835IN
0xcaf5b5D2...E3394Ba47
0 ETH0.00046723.82859753
Claim Tokens202110692024-07-01 10:27:5918 hrs ago1719829679IN
0xcaf5b5D2...E3394Ba47
0 ETH0.00044923.68110743
Claim Tokens202110672024-07-01 10:27:3518 hrs ago1719829655IN
0xcaf5b5D2...E3394Ba47
0 ETH0.00055413.90372351
Claim Tokens202110652024-07-01 10:27:1118 hrs ago1719829631IN
0xcaf5b5D2...E3394Ba47
0 ETH0.000490614.02043039
Claim Tokens202110502024-07-01 10:24:1118 hrs ago1719829451IN
0xcaf5b5D2...E3394Ba47
0 ETH0.000474323.40924404
Claim Tokens202101312024-07-01 7:19:1121 hrs ago1719818351IN
0xcaf5b5D2...E3394Ba47
0 ETH0.000361982.96636552
Claim Tokens202089322024-07-01 3:18:1125 hrs ago1719803891IN
0xcaf5b5D2...E3394Ba47
0 ETH0.000518182.98957824
Claim Tokens202084872024-07-01 1:48:4726 hrs ago1719798527IN
0xcaf5b5D2...E3394Ba47
0 ETH0.000652744.69163183
Claim Tokens202068932024-06-30 20:28:3532 hrs ago1719779315IN
0xcaf5b5D2...E3394Ba47
0 ETH0.000762195.47829958
Claim Tokens202052642024-06-30 15:01:3537 hrs ago1719759695IN
0xcaf5b5D2...E3394Ba47
0 ETH0.000694114.00457944
Claim Tokens202034272024-06-30 8:52:1143 hrs ago1719737531IN
0xcaf5b5D2...E3394Ba47
0 ETH0.000365712.9969488
Claim Tokens201965022024-06-29 9:39:112 days ago1719653951IN
0xcaf5b5D2...E3394Ba47
0 ETH0.000281882.02608285
Claim Tokens201950842024-06-29 4:53:472 days ago1719636827IN
0xcaf5b5D2...E3394Ba47
0 ETH0.000195351.37631229
Claim Tokens201917042024-06-28 17:33:473 days ago1719596027IN
0xcaf5b5D2...E3394Ba47
0 ETH0.000681044.35927715
Claim Tokens201907242024-06-28 14:16:233 days ago1719584183IN
0xcaf5b5D2...E3394Ba47
0 ETH0.001209397.60483848
Claim Tokens201906352024-06-28 13:58:353 days ago1719583115IN
0xcaf5b5D2...E3394Ba47
0 ETH0.000731295.99278334
Claim Tokens201896002024-06-28 10:30:473 days ago1719570647IN
0xcaf5b5D2...E3394Ba47
0 ETH0.000794426.51005947
Claim Tokens201892222024-06-28 9:14:593 days ago1719566099IN
0xcaf5b5D2...E3394Ba47
0 ETH0.000647474.65375534
Claim Tokens201883042024-06-28 6:10:353 days ago1719555035IN
0xcaf5b5D2...E3394Ba47
0 ETH0.000321482.26490901
Claim Tokens201845552024-06-27 17:35:594 days ago1719509759IN
0xcaf5b5D2...E3394Ba47
0 ETH0.003970432.53631358
Claim Tokens201783892024-06-26 20:57:235 days ago1719435443IN
0xcaf5b5D2...E3394Ba47
0 ETH0.00091876.60323169
Claim Tokens201688952024-06-25 13:08:356 days ago1719320915IN
0xcaf5b5D2...E3394Ba47
0 ETH0.001157736.67938301
View all transactions

Latest 2 internal transactions

Advanced mode:
Parent Transaction Hash Block From To Value
182230452023-09-26 22:51:47279 days ago1695768707
0xcaf5b5D2...E3394Ba47
 Contract Creation0 ETH
182230452023-09-26 22:51:47279 days ago1695768707
0xcaf5b5D2...E3394Ba47
 Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
VestingExecutor

Compiler Version
v0.8.9+commit.e5eed63a

Optimization Enabled:
Yes with 200 runs

Other Settings:
istanbul EvmVersion, GNU GPLv3 license
File 1 of 13 : VestingExecutor.sol
// SPDX-License-Identifier: GPL-3.0-only

pragma solidity 0.8.9;

/// @title: Vesting Executor
/// @author: davoice321

import "VestingManager.sol";
import "TokenLock.sol";

/**
 * Vesting Executor contract interacts with, and is the owner, of Vesting Manager. 
 Contract executes:
- Purchasing of vested tokens at varying prices. After purchase, asset is vested on behalf of user
- Swapping of asset for a vested asset (at a pre-defined ratio); after swap, asset is vested on behalf of swapper
- Standard vesting transaction: Assign a vesting schedule to an account 
- Cancellation of individual vesting schedules (limited to multisig)
- Withdrawal of unlocked tokens from Vesting Manager account (limited to multisig)
- Vesting and swapping are only possible when vesting/swapping is active 
- Asset claiming at end of cliff period on behalf of vestors 

Contract allows for multiple: 
- Assets to be vested simultaneously 
- Tokens to be used to purchase vested assets 
- Tokens to be used to swap for vested assets 
 */

contract VestingExecutor is Ownable, ReentrancyGuard {
    using SafeMath for uint256;
    using SafeERC20 for IERC20;

    /* ========== State Variables ========== */

    address payable immutable TREASURY =
        payable(0xf950a86013bAA227009771181a885E369e158da3);

    uint256 public purchaseAmountThreshold; // Amount of vesting token that must be purchased to trigger immediate release of coins
    uint256 public releasePercentage; // Percentage of total amount that will be released
    uint256 public swapRatio; // Ratio that will determine how many swap tokens can be exchanged for vesting tokens
    VestingManager public vestingManager; // Vesting Manager contract
    TokenLock public tokenLock; // Contract where swapped tokens are deposited; Contract has no owner or withdraw functions

    /* ========== Structs and Mappings ========== */

    /**
     * @notice Vesting parameters struct.
     * @dev This struct holds necessary parameters for vesting.
     * @param asset The asset that the users are being vested.
     * @param isFixed If true, the vesting schedule cannot be cancelled
     * @param cliffWeeks The number of weeks that the cliff will be present at.
     * @param vestingWeeks The number of weeks the tokens will vest over (linearly).
     * @param startTime The timestamp for when this vesting should have started.
     */
    struct VestingParams {
        address asset;
        bool isFixed;
        uint256 cliffWeeks;
        uint256 vestingWeeks;
        uint256 startTime;
    }

    VestingParams public vestingParams;

    /**
     * @notice Valid vesting params struct
     * @dev This struct holds valid parameters for vesting.
     * @param purchaseCliffWeeks The number of weeks that the cliff will be present at (purchases)
     * @param purchaseVestingWeeks The number of weeks the tokens will vest over (linearly - purchases).
     * @param swapCliffWeeks The number of weeks that the cliff will be present at (swaps)
     * @param swapVestingWeeks The number of weeks the tokens will vest over (linearly - swaps)
     */

    struct ValidVestingParams {
        uint256 purchaseCliffWeeks;
        uint256 purchaseVestingWeeks;
        uint256 swapCliffWeeks;
        uint256 swapVestingWeeks;
    }

    ValidVestingParams public validVestingParams;

    /**
     * @dev Struct to represent approved purchase tokens
     * @param token IERC20 token that has been approved for purchase
     * @param decimals Number of decimals the token uses
     */
    struct approvedPurchaseTokens {
        IERC20 token;
        uint256 decimals;
        uint256 numDecimals;
    }

    mapping(address => approvedPurchaseTokens) public purchaseTokens;

    /**
     * @dev Struct to represent tokens available for vesting
     * @param token IERC20 token that is available for vesting
     * @param decimals Number of decimals the token uses
     */
    struct VestingTokens {
        IERC20 token;
        uint256 decimals;
        uint256 numDecimals;
        uint256 price;
    }

    mapping(address => VestingTokens) public vestingTokens;

    /**
     * @dev Struct to represent authorized swap tokens
     * @param token IERC20 token that has been authorized for swap
     * @param decimals Number of decimals the token uses
     */
    struct AuthorizedSwapTokens {
        IERC20 token;
        uint256 decimals;
    }

    mapping(address => AuthorizedSwapTokens) public authorizedSwapTokens;

    /**
     * @dev Struct to represent authorized swap whitelist addresses
     * @param address address to be added to whitelist
     * @param string status of whitelisted address
     */
    struct AuthorizedSwapAddresses {
        address whitelistaddress;
        bool isSet;
    }

    mapping(address => AuthorizedSwapAddresses) public authorizedSwapAddresses;

    /* ========== Events ========== */

    event vestingTransactionComplete(address vester, uint256 vestedAssetAmount);
    event vestingPurchaseTransactionComplete(
        address indexed vester,
        uint256 vestedAssetAmount,
        address purchaseToken,
        uint256 amountTransferred
    );
    event vestingTokenWithdrawal(address token, uint256 withdrawalAmount);
    event tokenLockWithdrawal(
        IERC20 token,
        address to,
        uint256 withdrawalAmount
    );
    event addressesAddedToWhiteList(address[] addresses);
    event bonusVestingTokenTransfered(
        address recipient,
        uint256 transferAmount
    );
    event processLog(string description, uint256 number);
    event processLog2(string message);
    event processLog3(address address2);

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

    /**
     * @notice Deploys the Vesting Manager contract and sets the Vesting Executor as the owner of the VestingManager.
     Also deploys the Token Lock contract, which has no owner and no withdrawal functions; used to "burn" tokens swapped for vesting assets
     * @dev The VestingExecutor contract initializes the VestingManager contract during its own deployment.
     Constructor also sets the default purchase tokens: DAI, USDC and USDT.
     */
    constructor() {
        // Deploy a new instance of VestingManager, and TokenLock setting VestingExecutor (this contract) as the owner
        vestingManager = new VestingManager(address(this));
        tokenLock = new TokenLock(address(this));

        // Add initial valid purchase tokens to list (DAI, USDC, USDT)
        purchaseTokens[
            address(0x6B175474E89094C44Da98b954EedeAC495271d0F) //DAI
        ] = approvedPurchaseTokens({
            token: IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F),
            decimals: 10 ** 18,
            numDecimals: 18
        });

        purchaseTokens[
            address(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48) //USDC
        ] = approvedPurchaseTokens({
            token: IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48),
            decimals: 10 ** 6,
            numDecimals: 6
        });

        purchaseTokens[
            address(0xdAC17F958D2ee523a2206206994597C13D831ec7) //USDT
        ] = approvedPurchaseTokens({
            token: IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7),
            decimals: 10 ** 6,
            numDecimals: 6
        });
    }

    /* ========== Views ========== */

    /**
     * @notice Fetches locked amount of a specific asset (how many tokens locked overall for vesting)
     * @param assetAddress The address of the asset.
     * @return The amount of the asset currently locked.
     */
    function viewLockedAmount(
        address assetAddress
    ) public view returns (uint256) {
        return vestingManager.getLockedAmount(assetAddress);
    }

    /**
     * @notice Returns information about all vesting schedules for a given account
     * @param account The address of the account for which to return vesting schedule information
     * @return An array of ScheduleInfo structs, each containing the ID, cliff timestamp, and end timestamp for a vesting schedule (related to the account)
     */
    function retrieveScheduleInfo(
        address account
    ) public view returns (VestingManager.ScheduleInfo[] memory) {
        VestingManager.ScheduleInfo[] memory schedules = vestingManager
            .getScheduleInfo(account);
        return schedules;
    }

    /**
     * @notice Retrieves claimable token information for each vesting schedule of the given account
     * @param vestorAddress The account address to retrieve the claimable token information for
     * @return An array of structs containing the schedule ID and the corresponding number of claimable tokens
     */
    function retrieveClaimableTokens(
        address vestorAddress
    ) public view returns (VestingManager.ClaimableInfo[] memory) {
        VestingManager.ClaimableInfo[] memory claimInformation = vestingManager
            .retrieveClaimableTokens(vestorAddress);
        return claimInformation;
    }

    /**
     * @notice Fetches the data related to token claiming activity for a specific address
     * @param _vestorAddress The address of the vestor
     * @return Data related to asset claims by the vestor
     */
    function retrieveTokenClaimData(
        address _vestorAddress
    ) public view returns (VestingManager.TokenClaimInfo[] memory) {
        return vestingManager.getTokenClaimData(_vestorAddress);
    }

    /* ========== Modifiers ========== */

    /**
     * @notice Modifier to only allow certain function calls when vesting is active
     * @dev Reverts if the current vesting status is not active. Used to restrict function calling
     */
    modifier whenVestingActive() {
        require(
            current_vesting_status == vestingStatus.vestingActive,
            "Vesting not active"
        );
        _;
    }

    /**
     * @notice Modifier to enforce that swapping is active
     * @dev Reverts if the current swapping status is not active.
     */
    modifier whenSwappingActive() {
        require(
            current_swapping_status == swappingStatus.swappingActive,
            "Swapping not active"
        );
        _;
    }

    /**
     * @notice Modifier to only allow certain function calls when vesting is active
     * @dev Reverts if the current vesting status is not active. Used to restrict function calling
     */
    modifier whenStandardVestingActive() {
        require(
            current_standard_vesting_status ==
                standardVestingStatus.standardVestingActive,
            "Standard vesting not active"
        );
        _;
    }

    /**
     * @notice Modifier to restrict certain functions to multisig only calls
     * @dev Reverts if the caller is not the treasury.
     */
    modifier multiSigOnly() {
        require(msg.sender == TREASURY, "Multisig not caller");
        _;
    }

    /* ========== Transfer ERC20 Tokens ========== */

    /**
     * @notice Transfers a specific amount of ERC20 tokens to an address.
     * @dev The token transfer is executed using the input token's transfer function. It checks there are enough tokens on
     * the contract's balance before performing the transfer.
     * @param token The address of the ERC20 token contract that we want to make the transfer with.
     * @param to The recipient's address of the tokens.
     * @param amount The amount of tokens to be transferred.
     */

    function transferERC20(
        IERC20 token,
        address to,
        uint256 amount
    ) public onlyOwner {
        _transferERC20(token, to, amount);
    }

    function _transferERC20(IERC20 token, address to, uint256 amount) internal {
        uint256 erc20balance = token.balanceOf(address(this));
        require(amount <= erc20balance, "Balance too low to transfer token");
        token.transfer(to, amount);
    }

    /**
     * @notice Transfers a specific amount of ERC20 tokens from the TokenLock contract to an address.
     * @dev The token transfer is executed using the input token's transfer function. It checks there are enough tokens on
     * the contract's balance before performing the transfer.
     * @param token The address of the ERC20 token contract that we want to make the transfer with.
     * @param to The recipient's address of the tokens.
     * @param amount The amount of tokens to be transferred.
     */
    function transferLockedTokens(
        IERC20 token,
        address to,
        uint256 amount
    ) external onlyOwner {
        tokenLock.transferLockedTokens(token, to, amount);

        emit tokenLockWithdrawal(token, to, amount);
    }

    /* ========== Manage Vesting/Swap/Token Locking/Whitelist Status ========== */

    //Vesting status options
    enum vestingStatus {
        vestingActive, //0
        vestingInactive //1
    }

    //Default vesting status: Active
    vestingStatus public current_vesting_status = vestingStatus.vestingActive;

    /**
     * @notice Changes the vesting status of the contract
     * @dev Can only be called by the contract owner. Changes the status to the input value
     * @param value The new vesting status
     */
    function setVestingStatus(uint256 value) public onlyOwner {
        current_vesting_status = vestingStatus(value);
    }

    //Whitelist status options
    enum whiteListStatus {
        whiteListActive, //0
        whiteListInactive //1
    }

    //Default whitelist status: Inactive
    whiteListStatus public current_whitelist_status =
        whiteListStatus.whiteListInactive;

    /**
     * @notice Changes the whitelist status of the contract
     * @dev Can only be called by the contract owner. Changes the status to the input value
     * @param value The new whitelist status
     */
    function setWhiteListStatus(uint256 value) public onlyOwner {
        current_whitelist_status = whiteListStatus(value);
    }

    //Swapping status options
    enum swappingStatus {
        swappingActive, //0
        swappingInactive //1
    }

    //Default swapping status: Inactive
    swappingStatus public current_swapping_status =
        swappingStatus.swappingInactive;

    /**
     * @notice Changes the swapping status of the contract
     * @dev Can only be called by the contract owner. Changes the status to the input value
     * @param value The new swapping status
     */
    function setSwappingStatus(uint256 value) public onlyOwner {
        current_swapping_status = swappingStatus(value);
    }

    //Standard Vesting status options
    enum standardVestingStatus {
        standardVestingActive, //0
        standardVestingInactive //1
    }

    //Default standard vesting status: Active
    standardVestingStatus public current_standard_vesting_status =
        standardVestingStatus.standardVestingActive;

    /**
     * @notice Changes the vesting status (for standard vesting) of the contract
     * @dev Can only be called by the contract owner. Changes the status to the input value
     * @param value The new vesting status
     */
    function setStandardVestingStatus(uint256 value) public onlyOwner {
        current_standard_vesting_status = standardVestingStatus(value);
    }

    //Token lock options (whether swapped tokens are locked in the Token Lock contract)

    enum tokenLockStatus {
        tokenLockActive, //0
        tokenLockInactive //1
    }

    //Default token lock status: Active
    tokenLockStatus public current_token_lock_status =
        tokenLockStatus.tokenLockActive;

    /**
     * @notice Changes the token lock status of the contract
     * @dev Can only be called by the contract owner. Changes the status to the input value
     * @param value The new token locking status
     */
    function setTokenLockStatus(uint256 value) public onlyOwner {
        current_token_lock_status = tokenLockStatus(value);
    }

    /* ========== Set/Get Approved Purchase Tokens ========== */

    /**
     * @notice Adds a new token to the approved purchase tokens list
     * @dev Can only be called by the contract owner. Reverts if the token already exists on the list or if the address is invalid
     * @param tokenAddress The address of the new token to add
     * @param decimals The decimals of the new token
     * @param numDecimals Decimals of the token
     */
    function addPurchaseToken(
        address tokenAddress,
        uint256 decimals,
        uint256 numDecimals
    ) public onlyOwner {
        require(tokenAddress != address(0), "Invalid token address");
        require(
            address(purchaseTokens[tokenAddress].token) == address(0),
            "Purchase token on list"
        );

        purchaseTokens[tokenAddress] = approvedPurchaseTokens({
            token: IERC20(tokenAddress),
            decimals: decimals,
            numDecimals: numDecimals
        });
    }

    /**
     * @notice Removes a token from the approved purchase tokens list
     * @dev Can only be called by the contract owner. Reverts if the token is not currently on the list.
     * @param tokenAddress The address of the token to remove
     */
    function removePurchaseToken(address tokenAddress) public onlyOwner {
        require(
            address(purchaseTokens[tokenAddress].token) != address(0),
            "Purchase token not on list"
        );

        delete purchaseTokens[tokenAddress];
    }

    /* ========== Set/Get Approved Vesting Tokens ========== */

    /**
     * @notice Adds a new token to the approved vesting tokens list
     * @dev Can only be called by the contract owner. Reverts if the token already exists on the list or if the address is invalid
     * @param tokenAddress The address of the new token to add
     * @param decimals The decimals of the new token
     * @param price The USD price of the new token (multiply by 10^4 before sending to contract)
     * @param numDecimals Decimals of the token
     */
    function addVestingToken(
        address tokenAddress,
        uint256 decimals,
        uint256 price,
        uint256 numDecimals
    ) public onlyOwner {
        require(tokenAddress != address(0), "Invalid token address");
        require(
            address(vestingTokens[tokenAddress].token) == address(0),
            "Vesting token on list"
        );

        require(
            price >= 1 * 10 ** 4 && price <= 200 * 10 ** 4,
            "Price must be scaled to 10 ** 4"
        );

        vestingTokens[tokenAddress] = VestingTokens({
            token: IERC20(tokenAddress),
            decimals: decimals,
            price: price,
            numDecimals: numDecimals
        });
    }

    /**
     * @notice Removes a token from the approved vesting tokens list
     * @dev Can only be called by the contract owner. Reverts if the token is not currently on the list.
     * @param tokenAddress The address of the token to remove
     */
    function removeVestingToken(address tokenAddress) public onlyOwner {
        require(
            address(vestingTokens[tokenAddress].token) != address(0),
            "Vesting token on list"
        );

        delete vestingTokens[tokenAddress];
    }

    /* ========== Set/Get Approved Swap Tokens ========== */

    /**
     * @notice Adds a new token to the authorized swap tokens list
     * @dev Can only be called by the contract owner. Reverts if the token already exists on the list or if the address is invalid
     * @param tokenAddress The address of the new token to add
     * @param decimals The decimals of the new token
     */
    function addAuthorizedSwapToken(
        address tokenAddress,
        uint256 decimals
    ) public onlyOwner {
        require(tokenAddress != address(0), "Invalid token address");
        require(
            address(authorizedSwapTokens[tokenAddress].token) == address(0),
            "Swap token on list"
        );

        authorizedSwapTokens[tokenAddress] = AuthorizedSwapTokens({
            token: IERC20(tokenAddress),
            decimals: decimals
        });
    }

    /**
     * @notice Removes a token from the authorized swap tokens list
     * @dev Can only be called by the contract owner. Reverts if the token is not currently on the list.
     * @param tokenAddress The address of the token to remove
     */
    function removeAuthorizedSwapToken(address tokenAddress) public onlyOwner {
        require(
            address(authorizedSwapTokens[tokenAddress].token) != address(0),
            "Swap token not on list"
        );

        delete authorizedSwapTokens[tokenAddress];
    }

    /* ========== Set Vesting Parameters ========== */

    /**
     * @notice Sets the valid vesting parameters
     * @dev This function allows the owner to set the valid parameters for vesting.
     * @param _purchaseCliffWeeks The number of weeks that the cliff will be present at for purchases
     * @param _purchaseVestingWeeks The number of weeks the tokens will vest over linearly for purchases.
     * @param _swapCliffWeeks The number of weeks that the cliff will be present at for swaps
     * @param _swapVestingWeeks The number of weeks the tokens will vest over linearly for swaps.
     */

    function setValidVestingParams(
        uint256 _purchaseCliffWeeks,
        uint256 _purchaseVestingWeeks,
        uint256 _swapCliffWeeks,
        uint256 _swapVestingWeeks
    ) public onlyOwner {
        validVestingParams.purchaseCliffWeeks = _purchaseCliffWeeks;
        validVestingParams.purchaseVestingWeeks = _purchaseVestingWeeks;
        validVestingParams.swapCliffWeeks = _swapCliffWeeks;
        validVestingParams.swapVestingWeeks = _swapVestingWeeks;
    }

    /**
     * @notice Sets the release percentage for amount of vesting tokens that will immediately sent to users
     * @dev Allows the owner to set a threshold vesting token releases.
     * @param _releasePercentage The new percentage for the amount of vesting tokens immediately released to purchasers (should be scaled to 10^4)
     */
    function setReleasePercentage(uint256 _releasePercentage) public onlyOwner {
        require(
            _releasePercentage >= 1 * 10 ** 4 &&
                _releasePercentage <= 100 * 10 ** 4,
            "Release percentage must be scaled to 10 ** 4"
        );
        releasePercentage = _releasePercentage;
    }

    /**
     * @notice Sets the threshold for the amount of vesting tokens to be purchased.
     * @dev Allows the owner to set a threshold for vesting token purchase. If a user's purchase amount exceeds this threshold, a specified percentage of purchased tokens will be instantly transferred to the user.
     * @param threshold The new threshold for the amount of vesting tokens to be purchased.
     */
    function setPurchaseAmountThreshold(uint256 threshold) public onlyOwner {
        purchaseAmountThreshold = threshold;
    }

    /* ========== Set Vesting Swap Exchange Rate ========== */

    /**
     * @notice Sets the swap ratio for the vesting to swap token conversion
     * @dev Can only be executed by the owner of the contract
     * @param _ratio The ratio (multiply by 10^4 before sending to contract)
     */
    function setSwapRatio(uint256 _ratio) public onlyOwner {
        swapRatio = _ratio;
    }

    /* ========== Add/Remove Addresses to Swap Whitelist/Check Whether Address is on Whitelist ========== */

    /**
     * @notice Add provided addresses to the authorized swap addresses whitelist
     * @dev This function allows multiple addresses to be added to the whitelist status in a single transaction. 
     The provided addresses must be valid i.e. they cannot be the null address. It checks for this condition and reverts the transaction if the condition is not met
     * @param _addresses The array of addresses to be added to the authorized swap addresses whitelist
     * 
     */

    function addAuthorizedSwapAddresses(
        address[] memory _addresses
    ) public onlyOwner {
        for (uint i = 0; i < _addresses.length; i++) {
            require(_addresses[i] != address(0), "Null address not allowed");
            authorizedSwapAddresses[_addresses[i]] = AuthorizedSwapAddresses(
                _addresses[i],
                true
            );
        }

        emit addressesAddedToWhiteList(_addresses);
    }

    /**
     * @notice Removes an address from the authorized swap addresses whitelist
     * @dev Delete a specific address from the authorizedSwapAddresses mapping
     The provided address must exist in the whitelist and cannot be the null address
     * @param _address The address to be removed from the whitelist
     */

    function removeAuthorizedSwapAddress(address _address) public onlyOwner {
        require(
            authorizedSwapAddresses[_address].isSet,
            "Address does not exist in the whitelist"
        );
        delete authorizedSwapAddresses[_address];
    }

    /**
     * @notice Check if an address is on the authorized swap addresses whitelist
     * @dev Checks if the isSet field in the struct against the passed address in authorizedSwapAddresses is true
     * @param _address The address to check if it is on the whitelist
     * @return bool Returns true if the address is on the whitelist, false otherwise
     */
    function isWhitelisted(address _address) public view returns (bool) {
        return authorizedSwapAddresses[_address].isSet;
    }

    /* ========== Purchase and Vesting Functions ========== */

    /**
     * @notice Adjust the amount from the scale of the source decimal to the destination decimal
     * @dev This function handles the case where the decimal numbers vary between two tokens.
     * @param amount The source amount to be adjusted
     * @param fromDecimals The decimal number of the source token
     * @param toDecimals The decimal number of the destination token
     * @return The amount adjusted to the destination decimal scale
     */
    function adjustDecimals(
        uint256 amount,
        uint256 fromDecimals,
        uint256 toDecimals
    ) public pure returns (uint256) {
        if (fromDecimals == toDecimals) {
            return amount;
        } else if (fromDecimals > toDecimals) {
            return amount / (10 ** (fromDecimals - toDecimals));
        } else {
            return amount * (10 ** (toDecimals - fromDecimals));
        }
    }

    /**
     * @notice Allows user to purchase tokens with DAI or USDC, or another approved asset, which are then vested.
     * @dev Tokens being used for purchase must be approved. Transfers funds from purchaser to Treasury. Only available when vesting is active.
     * If the purchase amount meets the threshold, a portion of tokens is immediately released.
     * The rest of the tokens are vested; if not enough tokens are available to vest the transaction will revert.
     * @param _vestingTokenPurchaseAmount The amount of vesting tokens to be purchased
     * @param _exchangeToken The token used for the purchase, either DAI or USDC, or another approved token
     * @param _vestingAsset The asset to be vested
     */
    function purchaseVestingToken(
        uint256 _vestingTokenPurchaseAmount,
        address _exchangeToken,
        address _vestingAsset,
        VestingParams memory _vestingParams
    ) public payable whenVestingActive nonReentrant {
        // Ensure cliff is shorter than vesting (vesting includes the cliff duration) and cliff + vesting weeks; provided vesting parameters are valid; start time is valid

        require(
            _vestingParams.vestingWeeks > 0 &&
                _vestingParams.vestingWeeks >= _vestingParams.cliffWeeks &&
                _vestingParams.vestingWeeks >=
                validVestingParams.purchaseVestingWeeks &&
                _vestingParams.cliffWeeks >=
                validVestingParams.purchaseCliffWeeks,
            "Vesting: invalid vesting params set"
        );

        require(
            _vestingParams.startTime >= block.timestamp - 60 minutes,
            "Invalid start time set"
        );

        require(
            address(purchaseTokens[_exchangeToken].token) != address(0),
            "Exchange token must be a valid approved token"
        );

        uint256 scaledBuyPrice = _vestingTokenPurchaseAmount
            .mul(vestingTokens[_vestingAsset].price)
            .div(10 ** 4);

        //Calculate required amount of buy token

        uint256 requiredBuyAmount = adjustDecimals(
            scaledBuyPrice,
            vestingTokens[_vestingAsset].numDecimals,
            purchaseTokens[_exchangeToken].numDecimals
        );

        emit processLog(
            "Required Sell Token Payment Amount Calculated",
            requiredBuyAmount
        );

        require(
            IERC20(_exchangeToken).balanceOf(msg.sender) >= requiredBuyAmount,
            "Not enough tokens in wallet to exchange for vesting token"
        );

        //Logic to determine if purchase amount meets threshold for immediate release of portion of vested token asset

        uint256 vestingAmount;
        uint256 sellTokenAmountCalc;

        //Calculate sell token amount (to compare to purchase amount threshold)
        sellTokenAmountCalc = requiredBuyAmount.div(
            purchaseTokens[_exchangeToken].decimals
        );

        emit processLog(
            "Scaled Down Amount of Sell Token Calculated",
            sellTokenAmountCalc
        );

        //Transfer funds from purchaser to Treasury

        IERC20(_exchangeToken).safeTransferFrom(
            msg.sender,
            TREASURY,
            requiredBuyAmount
        );

        // Complete vesting operations //

        if (sellTokenAmountCalc >= purchaseAmountThreshold) {
            //Calculate amount to release
            uint256 percentToReleaseCalc = _vestingTokenPurchaseAmount
                .mul(releasePercentage)
                .div(vestingTokens[_vestingAsset].decimals);

            uint256 amountToRelease = percentToReleaseCalc
                .mul(vestingTokens[_vestingAsset].decimals)
                .div(10 ** 4)
                .div(100);

            emit processLog("Amount to Release Calculated", amountToRelease);

            // Withdraw amount from vesting contract and send to purchaser
            if (amountToRelease > 0) {
                _withdrawBonusTokens(
                    amountToRelease,
                    _vestingAsset,
                    msg.sender
                );
            }

            emit bonusVestingTokenTransfered(msg.sender, amountToRelease);

            // Calculate the remaining amount to vest
            vestingAmount = _vestingTokenPurchaseAmount.sub(amountToRelease);

            emit processLog("Vesting Amount Calculated", vestingAmount);

            // Vest the tokens for the user; if not enough tokens are available to vest the transaction will revert
            _vest(msg.sender, vestingAmount, _vestingParams);

            emit vestingPurchaseTransactionComplete(
                msg.sender,
                vestingAmount,
                _exchangeToken,
                sellTokenAmountCalc
            );
        } else {
            vestingAmount = _vestingTokenPurchaseAmount;

            _vest(msg.sender, vestingAmount, _vestingParams);

            emit vestingPurchaseTransactionComplete(
                msg.sender,
                vestingAmount,
                _exchangeToken,
                requiredBuyAmount
            );
        }
    }

    /**
     * @notice Sets up a token vesting schedule for the provided vestor
     * @dev Available only when vesting is active and only the owner can execute this function.
     *      If not enough tokens are available to vest, the transaction will be reverted.
     * @param vestor The address of the wallet to receive vesting tokens
     * @param amount The amount of tokens to be vested for the participant
     */
    function standardVesting(
        address vestor,
        uint256 amount,
        VestingParams memory _vestingParams
    ) public whenStandardVestingActive onlyOwner {
        //Ensure vesting start time is valid
        require(
            _vestingParams.startTime >= block.timestamp - 60 minutes,
            "Invalid start time set"
        );

        uint256 vestingAmount = amount;
        _vest(vestor, vestingAmount, _vestingParams);

        emit vestingTransactionComplete(msg.sender, vestingAmount);
    }

    /**
     * @notice Swaps a specified amount of tokens for a corresponding amount of vesting tokens, then vests those tokens for a specified address.
     * @dev Can only be called when swapping is active. Tokens to be swapped must be the authorized swap token.
     * Swapped tokens are sent to the Token Lock contract
     * If not enough tokens are available to vest, the transaction will revert.
     * @param swapTokenAmount The amount of swap tokens to be swapped and burned
     * @param tokenToSwap The token that is being swapped. Must be the authorized swap token.
     */
    function swapAndVest(
        uint256 swapTokenAmount,
        address tokenToSwap,
        VestingParams memory _vestingParams
    ) public whenSwappingActive nonReentrant {
        //Set vestor address to msg sender
        address vestor = msg.sender;

        // Ensure cliff is shorter than vesting (vesting includes the cliff duration) and cliff weeks, vesting weeks and start time are valid
        require(
            _vestingParams.vestingWeeks > 0 &&
                _vestingParams.vestingWeeks >= _vestingParams.cliffWeeks &&
                _vestingParams.cliffWeeks >=
                validVestingParams.swapCliffWeeks &&
                _vestingParams.vestingWeeks >=
                validVestingParams.swapVestingWeeks,
            "Vesting: not valid parameters"
        );

        require(
            _vestingParams.startTime >= block.timestamp - 60 minutes,
            "Invalid start time set"
        );

        // Check that swap token is authorized
        require(
            authorizedSwapTokens[tokenToSwap].token != IERC20(address(0)),
            "Token must be authorized swap token"
        );

        // If whitelist is active, check that sender is on the whitelist.
        if (current_whitelist_status == whiteListStatus.whiteListActive) {
            require(isWhitelisted(msg.sender), "Sender is not on whitelist");
        }

        // Calculate amount to vest
        uint256 vestingAmount = swapTokenAmount.mul(swapRatio).div(10 ** 4);
        emit processLog("Vesting Amount Calculated", vestingAmount);

        // Transfer tokens to TokenLock contract or Treasury
        authorizedSwapTokens[tokenToSwap].token.safeTransferFrom(
            msg.sender,
            address(this),
            swapTokenAmount
        );

        if (current_token_lock_status == tokenLockStatus.tokenLockActive) {
            // Transfer token to Token Lock contract (default behavior)
            _transferERC20(
                IERC20(tokenToSwap),
                address(tokenLock),
                swapTokenAmount
            );
        } else {
            // Transfer token to TREASURY
            _transferERC20(IERC20(tokenToSwap), TREASURY, swapTokenAmount);
        }

        emit processLog("Swap Token Transfered", swapTokenAmount);

        // Vest tokens on behalf of user
        _vest(vestor, vestingAmount, _vestingParams);

        emit vestingTransactionComplete(vestor, vestingAmount);
    }

    /**
     * @notice Sets up a vesting schedule for a user using the Vesting contract. Arguments are vesting parameters.
     * @param account The account that a vesting schedule is being set up for.
     * @param amount The amount of tokens being vested for the user.
     * @param params A struct containing the vesting parameters. The struct has
     *        the following parameters:
     *        ```
     *        {
     *          "asset": "<ADDRESS>", // The address of the token being vested
     *          "isFixed": <BOOLEAN>, // A flag indicating if the vesting schedule is fixed (can be adjusted)
     *          "cliffWeeks": <NUMBER>, // The number of weeks for the cliff period
     *          "vestingWeeks": <NUMBER>, // The number of weeks over which the tokens will vest
     *          "startTime": <UNIX_TIMESTAMP> // The start timestamp for the vesting
     *        }
     *        ```
     */
    function _vest(
        address account,
        uint256 amount,
        VestingParams memory params
    ) internal {
        vestingManager.vest(
            account,
            amount,
            params.asset,
            params.isFixed,
            params.cliffWeeks,
            params.vestingWeeks,
            params.startTime
        );
    }

    /**
     * @notice Allows claim of vested tokens; 
     * @dev Uses vestingManager to process the claim; 
     Vesting Executor claims on behalf of vestor and tokens are sent to vestor's account
     * @param scheduleId The ID of the vesting schedule
     * @param vestor The address of the vestor
     */
    function claimTokens(
        uint256 scheduleId,
        address vestor,
        address vestingAsset
    ) external {
        require(vestor == msg.sender, "Claimer is not vestor");

        vestingManager.claim(scheduleId, vestor, vestingAsset);
    }

    /**
     * @notice Cancel an individual vesting schedule.
     * @dev If the indiviudal vesting schedule is cancellable, it transfers the outstanding tokens to the VestingExecutor. Can only be called by the DAO multisig.
     * @param account The account to cancel vesting for.
     * @param scheduleId The id of the vesting schedule being canceled.
     */
    function cancelVesting(
        address account,
        uint256 scheduleId
    ) external multiSigOnly {
        vestingManager.cancelVesting(account, scheduleId);
    }

    /**
     * @notice Withdraws vesting tokens from the VestingManager contract.
     * @dev It only allows withdrawing tokens that are not locked in vesting. Can only be called by DAO multisig.
     * @param amount The amount to withdraw.
     * @param asset The token to withdraw.
     */
    function withdrawVestingTokens(
        uint256 amount,
        address asset
    ) external multiSigOnly {
        vestingManager.withdrawVestingTokens(amount, asset);

        _transferERC20(IERC20(asset), owner(), amount);

        emit vestingTokenWithdrawal(asset, amount);
    }

    /**
     * @notice Withdraws vesting tokens from the VestingManager contract (during token purchase transactions)
     * @dev It only allows withdrawing tokens that are not locked in vesting.
     * @param amount The amount to withdraw.
     * @param asset The token to withdraw.
     */
    function _withdrawBonusTokens(
        uint256 amount,
        address asset,
        address receipent
    ) internal {
        vestingManager.withdrawVestingTokens(amount, asset);

        _transferERC20(IERC20(asset), receipent, amount);
    }

    //End of contract
}

File 2 of 13 : VestingManager.sol
// SPDX-License-Identifier: GPL-3.0-only

pragma solidity 0.8.9;

import "Ownable.sol";
import "ERC20.sol";
import "IERC20.sol";
import "SafeERC20.sol";
import "SafeMath.sol";
import "ReentrancyGuard.sol";

/**
 * Vesting Manager core functionality based on standard Myceleium 
 (formerly Tracer DAO) vesting contract. Source code 
 available at: https://github.com/tracer-protocol/vesting/blob/master/contracts/Vesting.sol.

 Vesting Manager can vest multiple tokens.
 An address can have multiple vesting schedules for multiple assets. 
 */

contract VestingManager is Ownable {
    /* ========== State Variables ========== */

    address payable immutable TREASURY =
        payable(0xf950a86013bAA227009771181a885E369e158da3);

    /* ========== Structs ========== */

    /**
     * @dev Represents a vesting schedule for an account.
     *
     * @param totalAmount Total amount of tokens that will be vested.
     * @param claimedAmount Amount of tokens that have already been claimed.
     * @param startTime Unix timestamp for the start of the vesting schedule.
     * @param cliffTime The timestamp at which the cliff period ends. No tokens can be claimed before the cliff.
     * @param endTime The timestamp at which the vesting schedule ends. All tokens can be claimed after endTime.
     * @param isFixed Flag indicating if the vesting schedule is fixed or can be modified.
     * @param asset The address of the token being vested.
     */
    struct Schedule {
        uint256 totalAmount;
        uint256 claimedAmount;
        uint256 startTime;
        uint256 cliffTime;
        uint256 endTime;
        bool isFixed;
        address asset;
    }

    /**
     * @dev Represents a summary of a vesting schedule.
     *
     * @param id Unique identifier for the vesting schedule.
     * @param cliffTime The timestamp at which the cliff period ends. No tokens can be claimed before the cliff.
     * @param endTime The timestamp at which the vesting schedule ends. All tokens can be claimed after endTime.
     
     */
    struct ScheduleInfo {
        uint256 id;
        uint256 startTime;
        uint256 cliffTime;
        uint256 endTime;
        uint256 claimedAmount;
        uint256 totalAmount;
        address asset;
    }

    /**
     * @dev Struct to represent amount of vested tokens claimable for a vesting schedule
     * @param scheduleID ID of vesting schedule
     * @param claimableTokens number of vesting tokens claimable as of the current time
     */
    struct ClaimableInfo {
        uint256 scheduleID;
        uint256 claimableTokens;
    }

    /**
     * @dev Struct to represent amount of vested tokens claimable for a vesting schedule
     * @param scheduleID ID of vesting schedule
     * @param claimableTokens number of vesting tokens claimable as of the current time
     */
    struct TokenClaimInfo {
        address asset;
        uint256 scheduleID;
        uint256 claimedAmount;
    }

    /* ========== Mappings ========== */

    // Maps a user address to a schedule ID, which can be used to identify a vesting schedule
    mapping(address => mapping(uint256 => Schedule)) public schedules;

    // Maps a user address to number of schedules created for the account
    mapping(address => uint256) public numberOfSchedules;

    //Provides number of total tokens locked for a specific asset
    mapping(address => uint256) public locked;

    //Maps an address to token claim information associated with a specific address
    mapping(address => TokenClaimInfo[]) public tokenClaimInfo;

    /* ========== Events ========== */

    event vestingClaim(
        uint256 scheduleID,
        address indexed claimer,
        uint256 tokenAmountClaimed,
        uint256 tokensClaimedToDate
    );
    event vestingCancelled(uint256 scheduleID, address account);

    event VestingScheduleCreated(
        address indexed account,
        uint256 indexed currentNumSchedules,
        uint256 amount,
        uint256 startTime,
        uint256 cliffTime,
        uint256 vestingTime,
        bool isFixed,
        address indexed asset
    );

    event processLog(string description, uint256 number);

    /* ========== Constructor ========== */
    // Owner will be set to VestingExecutor contract
    constructor(address initialOwner) {
        transferOwnership(initialOwner);
    }

    /* ========== Views ========== */

    /**
     * @notice Fetches locked amount of a specific asset.
     * @param _assetAddress The address of the asset.
     * @return The amount of the asset currently locked.
     */
    function getLockedAmount(
        address _assetAddress
    ) public view returns (uint256) {
        return locked[_assetAddress];
    }

    /**
     * @notice Returns information about all vesting schedules for a given account
     * @param account The address of the account for which to return vesting schedule information
     * @return An array of ScheduleInfo structs, each containing the ID, cliff timestamp, and end timestamp for a vesting schedule (related to the account)
     */
    function getScheduleInfo(
        address account
    ) public view returns (ScheduleInfo[] memory) {
        uint256 count = numberOfSchedules[account];
        ScheduleInfo[] memory scheduleInfoList = new ScheduleInfo[](count);
        for (uint256 i = 0; i < count; i++) {
            scheduleInfoList[i] = ScheduleInfo(
                i,
                schedules[account][i].startTime,
                schedules[account][i].cliffTime,
                schedules[account][i].endTime,
                schedules[account][i].claimedAmount,
                schedules[account][i].totalAmount,
                schedules[account][i].asset
            );
        }
        return scheduleInfoList;
    }

    /**
     * @notice Retrieves the number of claimable tokens per vesting schedule for a given account
     * @dev This function utilizes the calcVestingDistribution function to determine claimable tokens based on the current block timestamp
     * @param account The address of the account to retrieve claimable tokens for
     * @return An array of structs, each containing the scheduleID and the corresponding number of claimable tokens
     */
    function retrieveClaimableTokens(
        address account
    ) public view returns (ClaimableInfo[] memory) {
        ScheduleInfo[] memory scheduleInfoList = getScheduleInfo(account);

        ClaimableInfo[] memory claimableInfoList = new ClaimableInfo[](
            scheduleInfoList.length
        );

        for (uint256 i = 0; i < scheduleInfoList.length; i++) {
            uint256 claimableTokens = calcVestingDistribution(
                scheduleInfoList[i].totalAmount,
                block.timestamp,
                scheduleInfoList[i].startTime,
                scheduleInfoList[i].endTime
            );

            // Cap the claimable tokens to the total amount allocated for vesting
            claimableTokens = claimableTokens > scheduleInfoList[i].totalAmount
                ? scheduleInfoList[i].totalAmount
                : claimableTokens;

            // Adjust the amount based on the amount the user has claimed
            uint256 claimableAmount = claimableTokens >
                scheduleInfoList[i].claimedAmount
                ? claimableTokens - scheduleInfoList[i].claimedAmount
                : 0;

            claimableInfoList[i] = ClaimableInfo(i, claimableAmount);
        }

        return claimableInfoList;
    }

    /**
     * @notice Internal function to record vestor's claiming activity.
     * @param _vestor The address of the vestor.
     * @param _asset The address of the vesting asset.
     * @param _scheduleID The ID of the vesting schedule.
     * @param _claimedAmount The total amount claimed.
     */
    function _setTotalClaimedData(
        address _vestor,
        address _asset,
        uint256 _scheduleID,
        uint256 _claimedAmount
    ) internal {
        tokenClaimInfo[_vestor].push(
            TokenClaimInfo(_asset, _scheduleID, _claimedAmount)
        );
    }

    /**
     * @notice Retrieves token claim data for a vestor address.
     * @param _address The vestor address for which to retrieve the token claim data.
     * @return An array of TokenClaimInfo containing token claim data for the.
     */
    function getTokenClaimData(
        address _address
    ) public view returns (TokenClaimInfo[] memory) {
        return tokenClaimInfo[_address];
    }

    /* ========== Vesting Functions ========== */

    /**
     * @notice Sets up a vesting schedule for a set user.
     * @dev Adds a new Schedule to the schedules mapping.
     * @param account The account that a vesting schedule is being set up for. Account will be able to claim tokens post-cliff period
     * @param amount The amount of ERC20 tokens being vested for the user.
     * @param asset The ERC20 asset being vested
     * @param isFixed If true, the vesting schedule cannot be cancelled
     * @param cliffWeeks Important parameter that determines how long the vesting cliff will be. During a cliff, no tokens can be claimed and vesting is paused
     * @param vestingWeeks The number of weeks a token will be vested over (linear in this immplementation)
     * @param startTime The start time for the vesting period ( in UNIX)
     */
    function vest(
        address account,
        uint256 amount,
        address asset,
        bool isFixed,
        uint256 cliffWeeks,
        uint256 vestingWeeks,
        uint256 startTime
    ) public onlyOwner {
        // ensure cliff is shorter than vesting (vesting includes the cliff duration)
        require(
            vestingWeeks > 0 && vestingWeeks >= cliffWeeks && amount > 0,
            "Vesting: invalid vesting params set"
        );

        uint256 currentLocked = locked[asset];

        // require enough unlocked token is present to vest the desired amount
        require(
            IERC20(asset).balanceOf(address(this)) >= currentLocked + amount,
            "Vesting: Not enough unlocked supply available to to vest"
        );

        // create the schedule
        uint256 currentNumSchedules = numberOfSchedules[account];
        schedules[account][currentNumSchedules] = Schedule(
            amount,
            0,
            startTime,
            startTime + (cliffWeeks * 1 weeks),
            startTime + (vestingWeeks * 1 weeks),
            isFixed,
            asset
        );

        numberOfSchedules[account] = currentNumSchedules + 1; //Update number of schedules
        locked[asset] = currentLocked + amount; //Update amount of asset locked in vesting schedule

        emit VestingScheduleCreated(
            account,
            currentNumSchedules,
            amount,
            startTime,
            startTime + (cliffWeeks * 1 weeks),
            startTime + (vestingWeeks * 1 weeks),
            isFixed,
            asset
        );
    }

    /**
     * @notice Post-cliff period, users can claim their tokens
     * @param scheduleNumber which schedule the user is claiming against
     */
    function claim(
        uint256 scheduleNumber,
        address vestor,
        address asset
    ) external onlyOwner {
        Schedule storage schedule = schedules[vestor][scheduleNumber];
        require(
            schedule.cliffTime <= block.timestamp,
            "Vesting: cliff not reached"
        );
        require(schedule.totalAmount > 0, "Vesting: Token not claimable");

        // Get the amount to be distributed
        uint256 amount = calcVestingDistribution(
            schedule.totalAmount,
            block.timestamp,
            schedule.startTime,
            schedule.endTime
        );

        // Caps the claim amount to the total amount allocated to be vested to the address
        amount = amount > schedule.totalAmount ? schedule.totalAmount : amount;
        uint256 amountToTransfer = amount - schedule.claimedAmount;
        schedule.claimedAmount = amount; // set new claimed amount based off the curve
        locked[schedule.asset] = locked[schedule.asset] - amountToTransfer;

        _setTotalClaimedData(vestor, asset, scheduleNumber, amount);

        require(
            IERC20(schedule.asset).transfer(vestor, amountToTransfer),
            "Vesting: transfer failed"
        );

        emit vestingClaim(scheduleNumber, vestor, amountToTransfer, amount);
    }

    /**
     * @notice Allows an individual vesting schedule to be cancelled.
     * @dev Any outstanding tokens are returned to the system.
     * @param account the account of the user whos vesting schedule is being cancelled.
     * @param scheduleId the schedule ID of the vesting schedule being cancelled
     */
    function cancelVesting(
        address account,
        uint256 scheduleId
    ) external onlyOwner {
        Schedule storage schedule = schedules[account][scheduleId];
        require(!schedule.isFixed, "Vesting: Account is fixed");
        uint256 outstandingAmount = schedule.totalAmount -
            schedule.claimedAmount;
        require(outstandingAmount != 0, "Vesting: no outstanding tokens");
        schedule.totalAmount = 0;
        locked[schedule.asset] = locked[schedule.asset] - outstandingAmount;
        require(
            IERC20(schedule.asset).transfer(TREASURY, outstandingAmount),
            "Vesting: transfer failed"
        );
        emit vestingCancelled(scheduleId, account);
    }

    /**
     * @return calculates the amount of tokens to distribute to an account at any instance in time, based off some
     *         total claimable amount.
     * @param amount the total outstanding amount to be claimed for this vesting schedule.
     * @param currentTime the current timestamp.
     * @param startTime the timestamp this vesting schedule started.
     * @param endTime the timestamp this vesting schedule ends.
     */
    function calcVestingDistribution(
        uint256 amount,
        uint256 currentTime,
        uint256 startTime,
        uint256 endTime
    ) public pure returns (uint256) {
        // avoid uint underflow
        if (currentTime < startTime) {
            return 0;
        }

        // if endTime < startTime, this will throw. Since endTime should never be
        // less than startTime in safe operation, this is fine.
        return (amount * (currentTime - startTime)) / (endTime - startTime);
    }

    /**
     * @notice Withdraws vesting tokens from the contract.
     * @dev blocks withdrawing locked tokens.
     */
    function withdrawVestingTokens(
        uint256 amount,
        address asset
    ) external onlyOwner {
        IERC20 token = IERC20(asset);
        require(
            token.balanceOf(address(this)) - locked[asset] >= amount,
            "Vesting: Can't withdraw"
        );
        require(token.transfer(owner(), amount), "Vesting: withdraw failed");
    }

    //End of contract
}

File 3 of 13 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "Context.sol";

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

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

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

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

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

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

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

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

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

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

pragma solidity ^0.8.0;

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

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

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

pragma solidity ^0.8.0;

import "IERC20.sol";
import "IERC20Metadata.sol";
import "Context.sol";

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

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

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

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

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

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

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

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

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

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

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

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `amount`.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual override returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, amount);
        _transfer(from, to, amount);
        return true;
    }

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

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

        return true;
    }

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

        _beforeTokenTransfer(from, to, amount);

        uint256 fromBalance = _balances[from];
        require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
        unchecked {
            _balances[from] = fromBalance - amount;
            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
            // decrementing then incrementing.
            _balances[to] += amount;
        }

        emit Transfer(from, to, amount);

        _afterTokenTransfer(from, to, amount);
    }

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

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

        _totalSupply += amount;
        unchecked {
            // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
            _balances[account] += amount;
        }
        emit Transfer(address(0), account, amount);

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

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

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

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        unchecked {
            _balances[account] = accountBalance - amount;
            // Overflow not possible: amount <= accountBalance <= totalSupply.
            _totalSupply -= amount;
        }

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

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

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

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

    /**
     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.
     *
     * Does not update the allowance amount in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Might emit an {Approval} event.
     */
    function _spendAllowance(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            require(currentAllowance >= amount, "ERC20: insufficient allowance");
            unchecked {
                _approve(owner, spender, currentAllowance - amount);
            }
        }
    }

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

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

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

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

pragma solidity ^0.8.0;

import "IERC20.sol";

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

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

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

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

pragma solidity ^0.8.0;

import "IERC20.sol";
import "draft-IERC20Permit.sol";
import "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 9 of 13 : 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 10 of 13 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.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 functionCallWithValue(target, data, 0, "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");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, 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) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, 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) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or 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 {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // 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 11 of 13 : SafeMath.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

File 12 of 13 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

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

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

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

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

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

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

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

File 13 of 13 : TokenLock.sol
// SPDX-License-Identifier: GPL-3.0-only

pragma solidity 0.8.9;

import "Ownable.sol";
import "IERC20.sol";

/**
 * Token Lock contract holds tokens swapped by the Vesting Executor for vested tokens. 

 */

contract TokenLock is Ownable {
    /* ========== Constructor ========== */
    // Owner will be set to VestingExecutor contract
    constructor(address initialOwner) {
        transferOwnership(initialOwner);
    }

    /* ========== Transfer ERC20 Tokens ========== */

    /**
     * @notice Transfers a specific amount of ERC20 tokens to an address.
     * @dev The token transfer is executed using the input token's transfer function. It checks there are enough tokens on
     * the contract's balance before performing the transfer.
     * @param token The address of the ERC20 token contract that we want to make the transfer with.
     * @param to The recipient's address of the tokens.
     * @param amount The amount of tokens to be transferred.
     */

    function transferLockedTokens(
        IERC20 token,
        address to,
        uint256 amount
    ) external onlyOwner {
        uint256 erc20balance = token.balanceOf(address(this));
        require(amount <= erc20balance, "Balance too low to transfer token");
        token.transfer(to, amount);
    }
}

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

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"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":"addresses","type":"address[]"}],"name":"addressesAddedToWhiteList","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"transferAmount","type":"uint256"}],"name":"bonusVestingTokenTransfered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"description","type":"string"},{"indexed":false,"internalType":"uint256","name":"number","type":"uint256"}],"name":"processLog","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"message","type":"string"}],"name":"processLog2","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"address2","type":"address"}],"name":"processLog3","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IERC20","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"withdrawalAmount","type":"uint256"}],"name":"tokenLockWithdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vester","type":"address"},{"indexed":false,"internalType":"uint256","name":"vestedAssetAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"purchaseToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountTransferred","type":"uint256"}],"name":"vestingPurchaseTransactionComplete","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"withdrawalAmount","type":"uint256"}],"name":"vestingTokenWithdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"vester","type":"address"},{"indexed":false,"internalType":"uint256","name":"vestedAssetAmount","type":"uint256"}],"name":"vestingTransactionComplete","type":"event"},{"inputs":[{"internalType":"address[]","name":"_addresses","type":"address[]"}],"name":"addAuthorizedSwapAddresses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"decimals","type":"uint256"}],"name":"addAuthorizedSwapToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"decimals","type":"uint256"},{"internalType":"uint256","name":"numDecimals","type":"uint256"}],"name":"addPurchaseToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"decimals","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"numDecimals","type":"uint256"}],"name":"addVestingToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"fromDecimals","type":"uint256"},{"internalType":"uint256","name":"toDecimals","type":"uint256"}],"name":"adjustDecimals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"authorizedSwapAddresses","outputs":[{"internalType":"address","name":"whitelistaddress","type":"address"},{"internalType":"bool","name":"isSet","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"authorizedSwapTokens","outputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"decimals","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"scheduleId","type":"uint256"}],"name":"cancelVesting","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"scheduleId","type":"uint256"},{"internalType":"address","name":"vestor","type":"address"},{"internalType":"address","name":"vestingAsset","type":"address"}],"name":"claimTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"current_standard_vesting_status","outputs":[{"internalType":"enum VestingExecutor.standardVestingStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"current_swapping_status","outputs":[{"internalType":"enum VestingExecutor.swappingStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"current_token_lock_status","outputs":[{"internalType":"enum VestingExecutor.tokenLockStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"current_vesting_status","outputs":[{"internalType":"enum VestingExecutor.vestingStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"current_whitelist_status","outputs":[{"internalType":"enum VestingExecutor.whiteListStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"isWhitelisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"purchaseAmountThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"purchaseTokens","outputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"decimals","type":"uint256"},{"internalType":"uint256","name":"numDecimals","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_vestingTokenPurchaseAmount","type":"uint256"},{"internalType":"address","name":"_exchangeToken","type":"address"},{"internalType":"address","name":"_vestingAsset","type":"address"},{"components":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"bool","name":"isFixed","type":"bool"},{"internalType":"uint256","name":"cliffWeeks","type":"uint256"},{"internalType":"uint256","name":"vestingWeeks","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"}],"internalType":"struct VestingExecutor.VestingParams","name":"_vestingParams","type":"tuple"}],"name":"purchaseVestingToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"releasePercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"removeAuthorizedSwapAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"removeAuthorizedSwapToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"removePurchaseToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"removeVestingToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vestorAddress","type":"address"}],"name":"retrieveClaimableTokens","outputs":[{"components":[{"internalType":"uint256","name":"scheduleID","type":"uint256"},{"internalType":"uint256","name":"claimableTokens","type":"uint256"}],"internalType":"struct VestingManager.ClaimableInfo[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"retrieveScheduleInfo","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"cliffTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"claimedAmount","type":"uint256"},{"internalType":"uint256","name":"totalAmount","type":"uint256"},{"internalType":"address","name":"asset","type":"address"}],"internalType":"struct VestingManager.ScheduleInfo[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_vestorAddress","type":"address"}],"name":"retrieveTokenClaimData","outputs":[{"components":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"scheduleID","type":"uint256"},{"internalType":"uint256","name":"claimedAmount","type":"uint256"}],"internalType":"struct VestingManager.TokenClaimInfo[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"threshold","type":"uint256"}],"name":"setPurchaseAmountThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_releasePercentage","type":"uint256"}],"name":"setReleasePercentage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"setStandardVestingStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ratio","type":"uint256"}],"name":"setSwapRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"setSwappingStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"setTokenLockStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_purchaseCliffWeeks","type":"uint256"},{"internalType":"uint256","name":"_purchaseVestingWeeks","type":"uint256"},{"internalType":"uint256","name":"_swapCliffWeeks","type":"uint256"},{"internalType":"uint256","name":"_swapVestingWeeks","type":"uint256"}],"name":"setValidVestingParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"setVestingStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"setWhiteListStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vestor","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"components":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"bool","name":"isFixed","type":"bool"},{"internalType":"uint256","name":"cliffWeeks","type":"uint256"},{"internalType":"uint256","name":"vestingWeeks","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"}],"internalType":"struct VestingExecutor.VestingParams","name":"_vestingParams","type":"tuple"}],"name":"standardVesting","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"swapTokenAmount","type":"uint256"},{"internalType":"address","name":"tokenToSwap","type":"address"},{"components":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"bool","name":"isFixed","type":"bool"},{"internalType":"uint256","name":"cliffWeeks","type":"uint256"},{"internalType":"uint256","name":"vestingWeeks","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"}],"internalType":"struct VestingExecutor.VestingParams","name":"_vestingParams","type":"tuple"}],"name":"swapAndVest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenLock","outputs":[{"internalType":"contract TokenLock","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferLockedTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"validVestingParams","outputs":[{"internalType":"uint256","name":"purchaseCliffWeeks","type":"uint256"},{"internalType":"uint256","name":"purchaseVestingWeeks","type":"uint256"},{"internalType":"uint256","name":"swapCliffWeeks","type":"uint256"},{"internalType":"uint256","name":"swapVestingWeeks","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vestingManager","outputs":[{"internalType":"contract VestingManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vestingParams","outputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"bool","name":"isFixed","type":"bool"},{"internalType":"uint256","name":"cliffWeeks","type":"uint256"},{"internalType":"uint256","name":"vestingWeeks","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"vestingTokens","outputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"decimals","type":"uint256"},{"internalType":"uint256","name":"numDecimals","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"assetAddress","type":"address"}],"name":"viewLockedAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"asset","type":"address"}],"name":"withdrawVestingTokens","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60a060405273f950a86013baa227009771181a885e369e158da36080526013805464ffffffffff1916620101001790553480156200003c57600080fd5b5062000048336200031f565b6001805560405130906200005c906200036f565b6001600160a01b039091168152602001604051809103906000f08015801562000089573d6000803e3d6000fd5b50600580546001600160a01b0319166001600160a01b03929092169190911790556040513090620000ba906200037d565b6001600160a01b039091168152602001604051809103906000f080158015620000e7573d6000803e3d6000fd5b50600680546001600160a01b03199081166001600160a01b039384161782556040805160608082018352736b175474e89094c44da98b954eedeac495271d0f808352670de0b6b3a7640000602080850191825260128587019081526000938452600f80835295517f907804fb4f4f34039c621b1a41008798cef5775ce10837f2769fb81032e4d83880548a16918c1691909117905591517f907804fb4f4f34039c621b1a41008798cef5775ce10837f2769fb81032e4d8395590517f907804fb4f4f34039c621b1a41008798cef5775ce10837f2769fb81032e4d83a558451808401865273a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48808252620f42408284018181528389018b815292865287855292517fdf82e8e0ca2e8ef371057fa5118f2005d1fe0db2f7f1913ccbb77b1c43aa572580548b16918d1691909117905591517fdf82e8e0ca2e8ef371057fa5118f2005d1fe0db2f7f1913ccbb77b1c43aa572655517fdf82e8e0ca2e8ef371057fa5118f2005d1fe0db2f7f1913ccbb77b1c43aa5727558551938401865273dac17f958d2ee523a2206206994597c13d831ec78085528483019182529584019788529490915291909152517f9bb1b6fca755b661f193c87a7d9b676dd6054634c764cdbc36564f69cab2d7298054909316941693909317905590517f9bb1b6fca755b661f193c87a7d9b676dd6054634c764cdbc36564f69cab2d72a55517f9bb1b6fca755b661f193c87a7d9b676dd6054634c764cdbc36564f69cab2d72b556200038b565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b61195b8062003ba083390190565b6105de80620054fb83390190565b6080516137e4620003bc6000396000818161140a0152818161176e01528181611cc001526122cf01526137e46000f3fe6080604052600436106102c95760003560e01c8063913c6dc011610175578063c4b02908116100dc578063e151027411610095578063e76234ed1161006f578063e76234ed14610a6e578063eab19a4d14610a8e578063ede5b88d14610aae578063f2fde38b14610ace57600080fd5b8063e1510274146109eb578063e5addb6b14610a0b578063e718234d14610a4e57600080fd5b8063c4b0290814610888578063ce557031146108f3578063cf18c3431461095e578063d37de2b51461098b578063db27b8dd146109ab578063de010640146109cb57600080fd5b8063a2144aca1161012e578063a2144aca14610789578063a26f000d146107a9578063aed27f6414610808578063b23bb9c414610828578063ba2129b114610848578063c2fb97f81461086857600080fd5b8063913c6dc014610696578063949c694c146106a95780639851d082146106c95780639b82b9561461072a5780639db5dbe41461074a5780639ed796a41461076a57600080fd5b806344cc621c11610234578063715018a6116101ed5780637c829dee116101c75780637c829dee1461060e5780637e85f7241461062e5780638da5cb5b14610644578063900ddece1461067657600080fd5b8063715018a614610563578063763b6d9e146105785780637742557e146105ee57600080fd5b806344cc621c1461049457806357981736146104b65780635a835b9e146104d65780635af6d5e6146104f65780635e47861314610516578063619cf6801461054357600080fd5b80632e2bd9ea116102865780632e2bd9ea1461039657806332dc22f4146103b6578063371501cc146103d65780633af32abf146104035780633baaac2d146104535780633f184c011461047457600080fd5b80630e0bfb49146102ce5780630e5a71ae146102f7578063165e5934146103195780631867fd0a1461032f57806327eb1f911461034f5780632a4d6b3714610376575b600080fd5b3480156102da57600080fd5b506102e460045481565b6040519081526020015b60405180910390f35b34801561030357600080fd5b50610317610312366004612c3b565b610aee565b005b34801561032557600080fd5b506102e460035481565b34801561033b57600080fd5b5061031761034a366004612c70565b610bdf565b34801561035b57600080fd5b506013546103699060ff1681565b6040516102ee9190612cc1565b34801561038257600080fd5b50610317610391366004612cd4565b610c72565b3480156103a257600080fd5b506103176103b1366004612d16565b610d36565b3480156103c257600080fd5b506103176103d1366004612c70565b610e0c565b3480156103e257600080fd5b506103f66103f1366004612c70565b610eba565b6040516102ee9190612d42565b34801561040f57600080fd5b5061044361041e366004612c70565b6001600160a01b0316600090815260126020526040902054600160a01b900460ff1690565b60405190151581526020016102ee565b34801561045f57600080fd5b50601354610369906301000000900460ff1681565b34801561048057600080fd5b5061031761048f366004612d91565b610f47565b3480156104a057600080fd5b5060135461036990640100000000900460ff1681565b3480156104c257600080fd5b506103176104d1366004612dcc565b61109d565b3480156104e257600080fd5b506103176104f1366004612dfe565b6110b9565b34801561050257600080fd5b50610317610511366004612f5d565b6110f6565b34801561052257600080fd5b50610536610531366004612c70565b6114d8565b6040516102ee9190612f9c565b34801561054f57600080fd5b5061031761055e366004612dfe565b611560565b34801561056f57600080fd5b5061031761159a565b34801561058457600080fd5b506105c4610593366004612c70565b60106020526000908152604090208054600182015460028301546003909301546001600160a01b0390921692909184565b604080516001600160a01b03909516855260208501939093529183015260608201526080016102ee565b3480156105fa57600080fd5b50610317610609366004613015565b6115ae565b34801561061a57600080fd5b50610317610629366004612dfe565b61172b565b34801561063a57600080fd5b506102e460025481565b34801561065057600080fd5b506000546001600160a01b03165b6040516001600160a01b0390911681526020016102ee565b34801561068257600080fd5b506103176106913660046130a9565b611763565b6103176106a43660046130d9565b611899565b3480156106b557600080fd5b506103176106c4366004612c70565b611f31565b3480156106d557600080fd5b5061070b6106e4366004612c70565b6012602052600090815260409020546001600160a01b03811690600160a01b900460ff1682565b604080516001600160a01b0390931683529015156020830152016102ee565b34801561073657600080fd5b50610317610745366004612dfe565b611fd1565b34801561075657600080fd5b5061031761076536600461312c565b61200d565b34801561077657600080fd5b5060135461036990610100900460ff1681565b34801561079557600080fd5b506103176107a4366004612dfe565b612020565b3480156107b557600080fd5b506107e96107c4366004612c70565b601160205260009081526040902080546001909101546001600160a01b039091169082565b604080516001600160a01b0390931683526020830191909152016102ee565b34801561081457600080fd5b50610317610823366004612c70565b61205e565b34801561083457600080fd5b50610317610843366004612dfe565b6120ff565b34801561085457600080fd5b50610317610863366004612dfe565b61210c565b34801561087457600080fd5b5061031761088336600461312c565b612119565b34801561089457600080fd5b50600754600854600954600a546108c1936001600160a01b03811693600160a01b90910460ff1692909185565b604080516001600160a01b0390961686529315156020860152928401919091526060830152608082015260a0016102ee565b3480156108ff57600080fd5b5061093961090e366004612c70565b600f602052600090815260409020805460018201546002909201546001600160a01b03909116919083565b604080516001600160a01b0390941684526020840192909252908201526060016102ee565b34801561096a57600080fd5b5061097e610979366004612c70565b6121e0565b6040516102ee919061316d565b34801561099757600080fd5b506102e46109a63660046131eb565b612266565b3480156109b757600080fd5b5060055461065e906001600160a01b031681565b3480156109d757600080fd5b506103176109e6366004612d16565b6122c4565b3480156109f757600080fd5b506102e4610a06366004612c70565b61239c565b348015610a1757600080fd5b50600b54600c54600d54600e54610a2e9392919084565b6040805194855260208501939093529183015260608201526080016102ee565b348015610a5a57600080fd5b5060065461065e906001600160a01b031681565b348015610a7a57600080fd5b506013546103699062010000900460ff1681565b348015610a9a57600080fd5b50610317610aa9366004613217565b61241a565b348015610aba57600080fd5b50610317610ac9366004612dfe565b612509565b348015610ada57600080fd5b50610317610ae9366004612c70565b61258c565b610af6612605565b6001600160a01b038316610b255760405162461bcd60e51b8152600401610b1c9061324d565b60405180910390fd5b6001600160a01b038381166000908152600f60205260409020541615610b865760405162461bcd60e51b8152602060048201526016602482015275141d5c98da185cd9481d1bdad95b881bdb881b1a5cdd60521b6044820152606401610b1c565b604080516060810182526001600160a01b0394851680825260208083019586528284019485526000918252600f905291909120905181546001600160a01b03191694169390931783559051600183015551600290910155565b610be7612605565b6001600160a01b0381811660009081526011602052604090205416610c475760405162461bcd60e51b815260206004820152601660248201527514ddd85c081d1bdad95b881b9bdd081bdb881b1a5cdd60521b6044820152606401610b1c565b6001600160a01b0316600090815260116020526040812080546001600160a01b031916815560010155565b6001600160a01b0382163314610cc25760405162461bcd60e51b815260206004820152601560248201527421b630b4b6b2b91034b9903737ba103b32b9ba37b960591b6044820152606401610b1c565b600554604051632cd1b11360e01b8152600481018590526001600160a01b038481166024830152838116604483015290911690632cd1b113906064015b600060405180830381600087803b158015610d1957600080fd5b505af1158015610d2d573d6000803e3d6000fd5b50505050505050565b610d3e612605565b6001600160a01b038216610d645760405162461bcd60e51b8152600401610b1c9061324d565b6001600160a01b038281166000908152601160205260409020541615610dc15760405162461bcd60e51b815260206004820152601260248201527114ddd85c081d1bdad95b881bdb881b1a5cdd60721b6044820152606401610b1c565b6040805180820182526001600160a01b03938416808252602080830194855260009182526011905291909120905181546001600160a01b031916931692909217825551600190910155565b610e14612605565b6001600160a01b038116600090815260126020526040902054600160a01b900460ff16610e935760405162461bcd60e51b815260206004820152602760248201527f4164647265737320646f6573206e6f7420657869737420696e207468652077686044820152661a5d195b1a5cdd60ca1b6064820152608401610b1c565b6001600160a01b0316600090815260126020526040902080546001600160a81b0319169055565b600554604051630dc5407360e21b81526001600160a01b03838116600483015260609260009291169063371501cc9060240160006040518083038186803b158015610f0457600080fd5b505afa158015610f18573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610f40919081019061327c565b9392505050565b610f4f612605565b6001600160a01b038416610f755760405162461bcd60e51b8152600401610b1c9061324d565b6001600160a01b038481166000908152601060205260409020541615610fd55760405162461bcd60e51b815260206004820152601560248201527415995cdd1a5b99c81d1bdad95b881bdb881b1a5cdd605a1b6044820152606401610b1c565b6127108210158015610fea5750621e84808211155b6110365760405162461bcd60e51b815260206004820152601f60248201527f5072696365206d757374206265207363616c656420746f203130202a2a2034006044820152606401610b1c565b604080516080810182526001600160a01b0395861680825260208083019687528284019485526060830195865260009182526010905291909120905181546001600160a01b0319169516949094178455915160018401559051600283015551600390910155565b6110a5612605565b600b93909355600c91909155600d55600e55565b6110c1612605565b8060018111156110d3576110d3612c8d565b6013805460ff1916600183818111156110ee576110ee612c8d565b021790555050565b600060135462010000900460ff16600181111561111557611115612c8d565b146111585760405162461bcd60e51b81526020600482015260136024820152725377617070696e67206e6f742061637469766560681b6044820152606401610b1c565b61116061265f565b606081015133901580159061117d57508160400151826060015110155b801561118f5750600d54604083015110155b80156111a15750600e54606083015110155b6111ed5760405162461bcd60e51b815260206004820152601d60248201527f56657374696e673a206e6f742076616c696420706172616d65746572730000006044820152606401610b1c565b6111f9610e104261333d565b8260800151101561121c5760405162461bcd60e51b8152600401610b1c90613354565b6001600160a01b038381166000908152601160205260409020541661128f5760405162461bcd60e51b815260206004820152602360248201527f546f6b656e206d75737420626520617574686f72697a6564207377617020746f60448201526235b2b760e91b6064820152608401610b1c565b6000601354610100900460ff1660018111156112ad576112ad612c8d565b14156113195733600090815260126020526040902054600160a01b900460ff166113195760405162461bcd60e51b815260206004820152601a60248201527f53656e646572206973206e6f74206f6e2077686974656c6973740000000000006044820152606401610b1c565b600061133c612710611336600454886126b990919063ffffffff16565b906126c5565b905060008051602061378f83398151915281604051611391919060408082526019908201527815995cdd1a5b99c8105b5bdd5b9d0810d85b18dd5b185d1959603a1b6060820152602081019190915260800190565b60405180910390a16001600160a01b038085166000908152601160205260409020546113c091163330886126d1565b6000601354640100000000900460ff1660018111156113e1576113e1612c8d565b1415611404576006546113ff9085906001600160a01b03168761272b565b61142f565b61142f847f00000000000000000000000000000000000000000000000000000000000000008761272b565b604080518181526015818301527414ddd85c08151bdad95b88151c985b9cd9995c9959605a1b606082015260208101879052905160008051602061378f8339815191529181900360800190a161148682828561288a565b604080516001600160a01b0384168152602081018390527f013860ae5eafafe669f2589467c1d6c258042a8acf0fc838c72690df147de3b2910160405180910390a150506114d360018055565b505050565b6005546040516302cdcfad60e41b81526001600160a01b0383811660048301526060921690632cdcfad09060240160006040518083038186803b15801561151e57600080fd5b505afa158015611532573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261155a9190810190613384565b92915050565b611568612605565b80600181111561157a5761157a612c8d565b6013805462ff00001916620100008360018111156110ee576110ee612c8d565b6115a2612605565b6115ac60006128fa565b565b6115b6612605565b60005b81518110156116f05760006001600160a01b03168282815181106115df576115df61344b565b60200260200101516001600160a01b0316141561163e5760405162461bcd60e51b815260206004820152601860248201527f4e756c6c2061646472657373206e6f7420616c6c6f77656400000000000000006044820152606401610b1c565b604051806040016040528083838151811061165b5761165b61344b565b60200260200101516001600160a01b03168152602001600115158152506012600084848151811061168e5761168e61344b565b6020908102919091018101516001600160a01b0390811683528282019390935260409091016000208351815494909201511515600160a01b026001600160a81b03199094169190921617919091179055806116e881613461565b9150506115b9565b507f6365182c588438b31e1fb8508f2afb0a7711f50fc126d7ca4a6519515b30718e81604051611720919061347c565b60405180910390a150565b611733612605565b80600181111561174557611745612c8d565b6013805461ff0019166101008360018111156110ee576110ee612c8d565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146117d15760405162461bcd60e51b815260206004820152601360248201527226bab63a34b9b4b3903737ba1031b0b63632b960691b6044820152606401610b1c565b600554604051634806ef6760e11b8152600481018490526001600160a01b0383811660248301529091169063900ddece90604401600060405180830381600087803b15801561181f57600080fd5b505af1158015611833573d6000803e3d6000fd5b505050506118538161184d6000546001600160a01b031690565b8461272b565b604080516001600160a01b0383168152602081018490527f69c20d72e70e5eb54eb53252bc65b4ce24cf88467ac61cd2883a6626ef23f2a8910160405180910390a15050565b600060135460ff1660018111156118b2576118b2612c8d565b146118f45760405162461bcd60e51b815260206004820152601260248201527156657374696e67206e6f742061637469766560701b6044820152606401610b1c565b6118fc61265f565b6000816060015111801561191857508060400151816060015110155b801561192a5750600c54606082015110155b801561193c5750600b54604082015110155b6119945760405162461bcd60e51b815260206004820152602360248201527f56657374696e673a20696e76616c69642076657374696e6720706172616d73206044820152621cd95d60ea1b6064820152608401610b1c565b6119a0610e104261333d565b816080015110156119c35760405162461bcd60e51b8152600401610b1c90613354565b6001600160a01b038381166000908152600f602052604090205416611a405760405162461bcd60e51b815260206004820152602d60248201527f45786368616e676520746f6b656e206d75737420626520612076616c6964206160448201526c38383937bb32b2103a37b5b2b760991b6064820152608401610b1c565b6001600160a01b038216600090815260106020526040812060030154611a6f90612710906113369088906126b9565b6001600160a01b038085166000908152601060209081526040808320600290810154948a168452600f9092528220015492935091611aae918491612266565b905060008051602061378f83398151915281604051611b1d91906040808252602d908201527f52657175697265642053656c6c20546f6b656e205061796d656e7420416d6f7560608201526c1b9d0810d85b18dd5b185d1959609a1b6080820152602081019190915260a00190565b60405180910390a16040516370a0823160e01b815233600482015281906001600160a01b038716906370a082319060240160206040518083038186803b158015611b6657600080fd5b505afa158015611b7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b9e91906134c9565b1015611c125760405162461bcd60e51b815260206004820152603960248201527f4e6f7420656e6f75676820746f6b656e7320696e2077616c6c657420746f206560448201527f786368616e676520666f722076657374696e6720746f6b656e000000000000006064820152608401610b1c565b6001600160a01b0385166000908152600f60205260408120600101548190611c3b9084906126c5565b905060008051602061378f83398151915281604051611ca891906040808252602b908201527f5363616c656420446f776e20416d6f756e74206f662053656c6c20546f6b656e60608201526a0810d85b18dd5b185d195960aa1b6080820152602081019190915260a00190565b60405180910390a1611ce56001600160a01b038816337f0000000000000000000000000000000000000000000000000000000000000000866126d1565b6002548110611ec4576001600160a01b038616600090815260106020526040812060010154600354611d1d9190611336908c906126b9565b6001600160a01b03881660009081526010602052604081206001015491925090611d55906064906113369061271090829087906126b9565b905060008051602061378f83398151915281604051611dae91906040808252601c908201527f416d6f756e7420746f2052656c656173652043616c63756c61746564000000006060820152602081019190915260800190565b60405180910390a18015611dc757611dc781893361294a565b60408051338152602081018390527f61abec4c161a61671f290a0639ee645e59cc703b1053aedab833585da0947484910160405180910390a1611e0a8a826129bb565b935060008051602061378f83398151915284604051611e5f919060408082526019908201527815995cdd1a5b99c8105b5bdd5b9d0810d85b18dd5b185d1959603a1b6060820152602081019190915260800190565b60405180910390a1611e7233858961288a565b604080518581526001600160a01b038b16602082015290810184905233907f5520459799f5796c0602e6f8b3c955c4cb3b3892d173e93744ec83a70c8ee5fd9060600160405180910390a25050611f1e565b879150611ed233838761288a565b604080518381526001600160a01b038916602082015290810184905233907f5520459799f5796c0602e6f8b3c955c4cb3b3892d173e93744ec83a70c8ee5fd9060600160405180910390a25b50505050611f2b60018055565b50505050565b611f39612605565b6001600160a01b0381811660009081526010602052604090205416611f985760405162461bcd60e51b815260206004820152601560248201527415995cdd1a5b99c81d1bdad95b881bdb881b1a5cdd605a1b6044820152606401610b1c565b6001600160a01b0316600090815260106020526040812080546001600160a01b0319168155600181018290556002810182905560030155565b611fd9612605565b806001811115611feb57611feb612c8d565b6013805463ff000000191663010000008360018111156110ee576110ee612c8d565b612015612605565b6114d383838361272b565b612028612605565b80600181111561203a5761203a612c8d565b6013805464ff0000000019166401000000008360018111156110ee576110ee612c8d565b612066612605565b6001600160a01b038181166000908152600f6020526040902054166120cd5760405162461bcd60e51b815260206004820152601a60248201527f507572636861736520746f6b656e206e6f74206f6e206c6973740000000000006044820152606401610b1c565b6001600160a01b03166000908152600f6020526040812080546001600160a01b03191681556001810182905560020155565b612107612605565b600255565b612114612605565b600455565b612121612605565b60065460405163185f72ff60e31b81526001600160a01b0385811660048301528481166024830152604482018490529091169063c2fb97f890606401600060405180830381600087803b15801561217757600080fd5b505af115801561218b573d6000803e3d6000fd5b5050604080516001600160a01b038088168252861660208201529081018490527fd25f579861b27075004b261043a11a5162757e7007eac235177a6db3988285ec9250606001905060405180910390a1505050565b6005546040516336ccda4f60e01b81526001600160a01b0383811660048301526060926000929116906336ccda4f9060240160006040518083038186803b15801561222a57600080fd5b505afa15801561223e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610f4091908101906134e2565b600081831415612277575082610f40565b818311156122a557612289828461333d565b61229490600a6136a9565b61229e90856136b5565b9050610f40565b6122af838361333d565b6122ba90600a6136a9565b61229e90856136d7565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146123325760405162461bcd60e51b815260206004820152601360248201527226bab63a34b9b4b3903737ba1031b0b63632b960691b6044820152606401610b1c565b600554604051630378041960e61b81526001600160a01b038481166004830152602482018490529091169063de01064090604401600060405180830381600087803b15801561238057600080fd5b505af1158015612394573d6000803e3d6000fd5b505050505050565b60055460405163929ec53760e01b81526001600160a01b038381166004830152600092169063929ec5379060240160206040518083038186803b1580156123e257600080fd5b505afa1580156123f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061155a91906134c9565b60006013546301000000900460ff16600181111561243a5761243a612c8d565b146124875760405162461bcd60e51b815260206004820152601b60248201527f5374616e646172642076657374696e67206e6f742061637469766500000000006044820152606401610b1c565b61248f612605565b61249b610e104261333d565b816080015110156124be5760405162461bcd60e51b8152600401610b1c90613354565b816124ca84828461288a565b60408051338152602081018390527f013860ae5eafafe669f2589467c1d6c258042a8acf0fc838c72690df147de3b2910160405180910390a150505050565b612511612605565b61271081101580156125265750620f42408111155b6125875760405162461bcd60e51b815260206004820152602c60248201527f52656c656173652070657263656e74616765206d757374206265207363616c6560448201526b19081d1bc80c4c080a8a880d60a21b6064820152608401610b1c565b600355565b612594612605565b6001600160a01b0381166125f95760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610b1c565b612602816128fa565b50565b6000546001600160a01b031633146115ac5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b1c565b600260015414156126b25760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610b1c565b6002600155565b6000610f4082846136d7565b6000610f4082846136b5565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052611f2b9085906129c7565b6040516370a0823160e01b81523060048201526000906001600160a01b038516906370a082319060240160206040518083038186803b15801561276d57600080fd5b505afa158015612781573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127a591906134c9565b9050808211156128015760405162461bcd60e51b815260206004820152602160248201527f42616c616e636520746f6f206c6f7720746f207472616e7366657220746f6b656044820152603760f91b6064820152608401610b1c565b60405163a9059cbb60e01b81526001600160a01b0384811660048301526024820184905285169063a9059cbb90604401602060405180830381600087803b15801561284b57600080fd5b505af115801561285f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061288391906136f6565b5050505050565b60055481516020830151604080850151606086015160808701519251630d53588360e01b81526001600160a01b038a81166004830152602482018a905295861660448201529315156064850152608484019190915260a483015260c4820152911690630d5358839060e401610cff565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600554604051634806ef6760e11b8152600481018590526001600160a01b0384811660248301529091169063900ddece90604401600060405180830381600087803b15801561299857600080fd5b505af11580156129ac573d6000803e3d6000fd5b505050506114d382828561272b565b6000610f40828461333d565b6000612a1c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612a999092919063ffffffff16565b8051909150156114d35780806020019051810190612a3a91906136f6565b6114d35760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610b1c565b6060612aa88484600085612ab0565b949350505050565b606082471015612b115760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610b1c565b600080866001600160a01b03168587604051612b2d919061373f565b60006040518083038185875af1925050503d8060008114612b6a576040519150601f19603f3d011682016040523d82523d6000602084013e612b6f565b606091505b5091509150612b8087838387612b8b565b979650505050505050565b60608315612bf7578251612bf0576001600160a01b0385163b612bf05760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b1c565b5081612aa8565b612aa88383815115612c0c5781518083602001fd5b8060405162461bcd60e51b8152600401610b1c919061375b565b6001600160a01b038116811461260257600080fd5b600080600060608486031215612c5057600080fd5b8335612c5b81612c26565b95602085013595506040909401359392505050565b600060208284031215612c8257600080fd5b8135610f4081612c26565b634e487b7160e01b600052602160045260246000fd5b6002811061260257634e487b7160e01b600052602160045260246000fd5b60208101612cce83612ca3565b91905290565b600080600060608486031215612ce957600080fd5b833592506020840135612cfb81612c26565b91506040840135612d0b81612c26565b809150509250925092565b60008060408385031215612d2957600080fd5b8235612d3481612c26565b946020939093013593505050565b602080825282518282018190526000919060409081850190868401855b82811015612d8457815180518552860151868501529284019290850190600101612d5f565b5091979650505050505050565b60008060008060808587031215612da757600080fd5b8435612db281612c26565b966020860135965060408601359560600135945092505050565b60008060008060808587031215612de257600080fd5b5050823594602084013594506040840135936060013592509050565b600060208284031215612e1057600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715612e5057612e50612e17565b60405290565b6040516060810167ffffffffffffffff81118282101715612e5057612e50612e17565b60405160e0810167ffffffffffffffff81118282101715612e5057612e50612e17565b604051601f8201601f1916810167ffffffffffffffff81118282101715612ec557612ec5612e17565b604052919050565b801515811461260257600080fd5b600060a08284031215612eed57600080fd5b60405160a0810181811067ffffffffffffffff82111715612f1057612f10612e17565b6040529050808235612f2181612c26565b81526020830135612f3181612ecd565b806020830152506040830135604082015260608301356060820152608083013560808201525092915050565b600080600060e08486031215612f7257600080fd5b833592506020840135612f8481612c26565b9150612f938560408601612edb565b90509250925092565b602080825282518282018190526000919060409081850190868401855b82811015612d8457815180516001600160a01b0316855286810151878601528501518585015260609093019290850190600101612fb9565b600067ffffffffffffffff82111561300b5761300b612e17565b5060051b60200190565b6000602080838503121561302857600080fd5b823567ffffffffffffffff81111561303f57600080fd5b8301601f8101851361305057600080fd5b803561306361305e82612ff1565b612e9c565b81815260059190911b8201830190838101908783111561308257600080fd5b928401925b82841015612b8057833561309a81612c26565b82529284019290840190613087565b600080604083850312156130bc57600080fd5b8235915060208301356130ce81612c26565b809150509250929050565b60008060008061010085870312156130f057600080fd5b84359350602085013561310281612c26565b9250604085013561311281612c26565b91506131218660608701612edb565b905092959194509250565b60008060006060848603121561314157600080fd5b833561314c81612c26565b9250602084013561315c81612c26565b929592945050506040919091013590565b602080825282518282018190526000919060409081850190868401855b82811015612d845781518051855286810151878601528581015186860152606080820151908601526080808201519086015260a0808201519086015260c0908101516001600160a01b03169085015260e0909301929085019060010161318a565b60008060006060848603121561320057600080fd5b505081359360208301359350604090920135919050565b600080600060e0848603121561322c57600080fd5b833561323781612c26565b925060208401359150612f938560408601612edb565b602080825260159082015274496e76616c696420746f6b656e206164647265737360581b604082015260600190565b6000602080838503121561328f57600080fd5b825167ffffffffffffffff8111156132a657600080fd5b8301601f810185136132b757600080fd5b80516132c561305e82612ff1565b81815260069190911b820183019083810190878311156132e457600080fd5b928401925b82841015612b8057604084890312156133025760008081fd5b61330a612e2d565b8451815285850151868201528252604090930192908401906132e9565b634e487b7160e01b600052601160045260246000fd5b60008282101561334f5761334f613327565b500390565b602080825260169082015275125b9d985b1a59081cdd185c9d081d1a5b59481cd95d60521b604082015260600190565b6000602080838503121561339757600080fd5b825167ffffffffffffffff8111156133ae57600080fd5b8301601f810185136133bf57600080fd5b80516133cd61305e82612ff1565b818152606091820283018401918482019190888411156133ec57600080fd5b938501935b8385101561343f5780858a0312156134095760008081fd5b613411612e56565b855161341c81612c26565b8152858701518782015260408087015190820152835293840193918501916133f1565b50979650505050505050565b634e487b7160e01b600052603260045260246000fd5b600060001982141561347557613475613327565b5060010190565b6020808252825182820181905260009190848201906040850190845b818110156134bd5783516001600160a01b031683529284019291840191600101613498565b50909695505050505050565b6000602082840312156134db57600080fd5b5051919050565b600060208083850312156134f557600080fd5b825167ffffffffffffffff81111561350c57600080fd5b8301601f8101851361351d57600080fd5b805161352b61305e82612ff1565b81815260e0918202830184019184820191908884111561354a57600080fd5b938501935b8385101561343f5780858a0312156135675760008081fd5b61356f612e79565b85518152868601518782015260408087015190820152606080870151908201526080808701519082015260a0808701519082015260c0808701516135b281612c26565b908201528352938401939185019161354f565b600181815b808511156136005781600019048211156135e6576135e6613327565b808516156135f357918102915b93841c93908002906135ca565b509250929050565b6000826136175750600161155a565b816136245750600061155a565b816001811461363a576002811461364457613660565b600191505061155a565b60ff84111561365557613655613327565b50506001821b61155a565b5060208310610133831016604e8410600b8410161715613683575081810a61155a565b61368d83836135c5565b80600019048211156136a1576136a1613327565b029392505050565b6000610f408383613608565b6000826136d257634e487b7160e01b600052601260045260246000fd5b500490565b60008160001904831182151516156136f1576136f1613327565b500290565b60006020828403121561370857600080fd5b8151610f4081612ecd565b60005b8381101561372e578181015183820152602001613716565b83811115611f2b5750506000910152565b60008251613751818460208701613713565b9190910192915050565b602081526000825180602084015261377a816040850160208701613713565b601f01601f1916919091016040019291505056fee520fdce79bb8277387a89e5c39651632ba577f54f87fab58b3f0b21c8fcdee3a264697066735822122036df003e70f9bdc1c12c9df317aa9f9e1d7e80fd9718873d7b77d84b2a73fbc164736f6c6343000809003360a060405273f950a86013baa227009771181a885e369e158da36080523480156200002957600080fd5b506040516200195b3803806200195b8339810160408190526200004c916200019a565b620000573362000069565b6200006281620000b9565b50620001cc565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b620000c36200013c565b6001600160a01b0381166200012e5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b620001398162000069565b50565b6000546001600160a01b03163314620001985760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640162000125565b565b600060208284031215620001ad57600080fd5b81516001600160a01b0381168114620001c557600080fd5b9392505050565b608051611773620001e8600039600061116101526117736000f3fe608060405234801561001057600080fd5b50600436106101005760003560e01c80638da5cb5b11610097578063cbf9fe5f11610066578063cbf9fe5f146102ed578063de0106401461030d578063df681c1414610320578063f2fde38b1461034057600080fd5b80638da5cb5b14610275578063900ddece14610290578063929ec537146102a3578063bc623dd4146102da57600080fd5b806336ccda4f116100d357806336ccda4f1461018e578063371501cc146101ae578063715018a6146101ce578063854e9682146101d657600080fd5b80630d535883146101055780632cd1b1131461011a5780632cdcfad01461012d578063359c937614610156575b600080fd5b6101186101133660046113c8565b610353565b005b610118610128366004611432565b6106c1565b61014061013b36600461146e565b6109bc565b60405161014d9190611490565b60405180910390f35b6101696101643660046114f2565b610a54565b604080516001600160a01b03909416845260208401929092529082015260600161014d565b6101a161019c36600461146e565b610aa0565b60405161014d919061151c565b6101c16101bc36600461146e565b610c0f565b60405161014d919061159a565b610118610ddf565b6102356101e43660046114f2565b600160208181526000938452604080852090915291835291208054918101546002820154600383015460048401546005909401549293919290919060ff81169061010090046001600160a01b031687565b6040805197885260208801969096529486019390935260608501919091526080840152151560a08301526001600160a01b031660c082015260e00161014d565b6000546040516001600160a01b03909116815260200161014d565b61011861029e3660046115dc565b610df3565b6102cc6102b136600461146e565b6001600160a01b031660009081526003602052604090205490565b60405190815260200161014d565b6102cc6102e8366004611608565b610fd0565b6102cc6102fb36600461146e565b60036020526000908152604090205481565b61011861031b3660046114f2565b611015565b6102cc61032e36600461146e565b60026020526000908152604090205481565b61011861034e36600461146e565b61127b565b61035b6112f4565b60008211801561036b5750828210155b80156103775750600086115b6103d45760405162461bcd60e51b815260206004820152602360248201527f56657374696e673a20696e76616c69642076657374696e6720706172616d73206044820152621cd95d60ea1b60648201526084015b60405180910390fd5b6001600160a01b0385166000908152600360205260409020546103f78782611650565b6040516370a0823160e01b81523060048201526001600160a01b038816906370a082319060240160206040518083038186803b15801561043657600080fd5b505afa15801561044a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061046e9190611668565b10156104e25760405162461bcd60e51b815260206004820152603860248201527f56657374696e673a204e6f7420656e6f75676820756e6c6f636b65642073757060448201527f706c7920617661696c61626c6520746f20746f2076657374000000000000000060648201526084016103cb565b6001600160a01b038816600090815260026020908152604080832054815160e0810183528b8152928301939093528101849052606081016105268762093a80611681565b6105309086611650565b81526020016105428662093a80611681565b61054c9086611650565b81528715156020808301919091526001600160a01b03808b166040938401528c811660009081526001808452848220878352845290849020855181559285015183820155928401516002830155606084015160038301556080840151600483015560a08401516005909201805460c09095015190911661010002610100600160a81b0319921515929092166001600160a81b031990941693909317179091556105f6908290611650565b6001600160a01b038a166000908152600260205260409020556106198883611650565b6001600160a01b0380891660008181526003602052604090209290925582908b167f6b2f2257f35a26e12a3c23c761df243c0479a92719945001d91ba6127f7295ac8b8761066a8b62093a80611681565b610674908a611650565b6106818b62093a80611681565b61068b908b611650565b6040805194855260208501939093529183015260608201528a1515608082015260a00160405180910390a4505050505050505050565b6106c96112f4565b6001600160a01b0382166000908152600160209081526040808320868452909152902060038101544210156107405760405162461bcd60e51b815260206004820152601a60248201527f56657374696e673a20636c696666206e6f74207265616368656400000000000060448201526064016103cb565b805461078e5760405162461bcd60e51b815260206004820152601c60248201527f56657374696e673a20546f6b656e206e6f7420636c61696d61626c650000000060448201526064016103cb565b60006107a882600001544284600201548560040154610fd0565b825490915081116107b957806107bc565b81545b905060008260010154826107d091906116a0565b60018401839055600584015461010090046001600160a01b03166000908152600360205260409020549091506108079082906116a0565b600584015461010090046001600160a01b0390811660009081526003602081815260408084209590955589841683526004815284832085516060810187528a861681528083018d81529681018981528254600180820185559387529390952090519290930290920180546001600160a01b031916919094161783559251928201929092559051600290910155600583015460405163a9059cbb60e01b81526001600160a01b038781166004830152602482018490526101009092049091169063a9059cbb90604401602060405180830381600087803b1580156108e957600080fd5b505af11580156108fd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061092191906116b7565b6109685760405162461bcd60e51b815260206004820152601860248201527715995cdd1a5b99ce881d1c985b9cd9995c8819985a5b195960421b60448201526064016103cb565b60408051878152602081018390529081018390526001600160a01b038616907fbd8cb0d1505670d964ee3380ba221a8cc86f3e7d08915f56b0723bf408d732949060600160405180910390a2505050505050565b6001600160a01b0381166000908152600460209081526040808320805482518185028101850190935280835260609492939192909184015b82821015610a49576000848152602090819020604080516060810182526003860290920180546001600160a01b03168352600180820154848601526002909101549183019190915290835290920191016109f4565b505050509050919050565b60046020528160005260406000208181548110610a7057600080fd5b60009182526020909120600390910201805460018201546002909201546001600160a01b03909116935090915083565b6001600160a01b0381166000908152600260205260408120546060918167ffffffffffffffff811115610ad557610ad56116d4565b604051908082528060200260200182016040528015610b4f57816020015b610b3c6040518060e0016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681525090565b815260200190600190039081610af35790505b50905060005b82811015610c07576040805160e0810182528281526001600160a01b0380881660009081526001602081815285832087845280825286842060028101548388015260038101549787019790975260048701546060870152918601546080860152855460a0860152918690529052600590920154610100900490911660c08201528251839083908110610be957610be96116ea565b60200260200101819052508080610bff90611700565b915050610b55565b509392505050565b60606000610c1c83610aa0565b90506000815167ffffffffffffffff811115610c3a57610c3a6116d4565b604051908082528060200260200182016040528015610c7f57816020015b6040805180820190915260008082526020820152815260200190600190039081610c585790505b50905060005b8251811015610c07576000610cf3848381518110610ca557610ca56116ea565b602002602001015160a0015142868581518110610cc457610cc46116ea565b602002602001015160200151878681518110610ce257610ce26116ea565b602002602001015160600151610fd0565b9050838281518110610d0757610d076116ea565b602002602001015160a001518111610d1f5780610d3e565b838281518110610d3157610d316116ea565b602002602001015160a001515b90506000848381518110610d5457610d546116ea565b6020026020010151608001518211610d6d576000610d96565b848381518110610d7f57610d7f6116ea565b60200260200101516080015182610d9691906116a0565b9050604051806040016040528084815260200182815250848481518110610dbf57610dbf6116ea565b602002602001018190525050508080610dd790611700565b915050610c85565b610de76112f4565b610df1600061134e565b565b610dfb6112f4565b6001600160a01b038116600081815260036020526040908190205490516370a0823160e01b815230600482015283928592916370a082319060240160206040518083038186803b158015610e4e57600080fd5b505afa158015610e62573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e869190611668565b610e9091906116a0565b1015610ede5760405162461bcd60e51b815260206004820152601760248201527f56657374696e673a2043616e277420776974686472617700000000000000000060448201526064016103cb565b806001600160a01b031663a9059cbb610eff6000546001600160a01b031690565b6040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260248101869052604401602060405180830381600087803b158015610f4757600080fd5b505af1158015610f5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f7f91906116b7565b610fcb5760405162461bcd60e51b815260206004820152601860248201527f56657374696e673a207769746864726177206661696c6564000000000000000060448201526064016103cb565b505050565b600082841015610fe25750600061100d565b610fec83836116a0565b610ff684866116a0565b6110009087611681565b61100a919061171b565b90505b949350505050565b61101d6112f4565b6001600160a01b03821660009081526001602090815260408083208484529091529020600581015460ff16156110955760405162461bcd60e51b815260206004820152601960248201527f56657374696e673a204163636f756e742069732066697865640000000000000060448201526064016103cb565b600181015481546000916110a8916116a0565b9050806110f75760405162461bcd60e51b815260206004820152601e60248201527f56657374696e673a206e6f206f75747374616e64696e6720746f6b656e73000060448201526064016103cb565b6000808355600583015461010090046001600160a01b03168152600360205260409020546111269082906116a0565b6005830180546001600160a01b0361010091829004811660009081526003602052604090819020949094559154925163a9059cbb60e01b81527f000000000000000000000000000000000000000000000000000000000000000083166004820152602481018590529204169063a9059cbb90604401602060405180830381600087803b1580156111b557600080fd5b505af11580156111c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ed91906116b7565b6112345760405162461bcd60e51b815260206004820152601860248201527715995cdd1a5b99ce881d1c985b9cd9995c8819985a5b195960421b60448201526064016103cb565b604080518481526001600160a01b03861660208201527fb2b7ae35bea638b859686dba7e7fc72dd6b4d3f392847418b677bfcaa19dfc31910160405180910390a150505050565b6112836112f4565b6001600160a01b0381166112e85760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016103cb565b6112f18161134e565b50565b6000546001600160a01b03163314610df15760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103cb565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80356001600160a01b03811681146113b557600080fd5b919050565b80151581146112f157600080fd5b600080600080600080600060e0888a0312156113e357600080fd5b6113ec8861139e565b9650602088013595506114016040890161139e565b94506060880135611411816113ba565b9699959850939660808101359560a0820135955060c0909101359350915050565b60008060006060848603121561144757600080fd5b833592506114576020850161139e565b91506114656040850161139e565b90509250925092565b60006020828403121561148057600080fd5b6114898261139e565b9392505050565b602080825282518282018190526000919060409081850190868401855b828110156114e557815180516001600160a01b03168552868101518786015285015185850152606090930192908501906001016114ad565b5091979650505050505050565b6000806040838503121561150557600080fd5b61150e8361139e565b946020939093013593505050565b602080825282518282018190526000919060409081850190868401855b828110156114e55781518051855286810151878601528581015186860152606080820151908601526080808201519086015260a0808201519086015260c0908101516001600160a01b03169085015260e09093019290850190600101611539565b602080825282518282018190526000919060409081850190868401855b828110156114e5578151805185528601518685015292840192908501906001016115b7565b600080604083850312156115ef57600080fd5b823591506115ff6020840161139e565b90509250929050565b6000806000806080858703121561161e57600080fd5b5050823594602084013594506040840135936060013592509050565b634e487b7160e01b600052601160045260246000fd5b600082198211156116635761166361163a565b500190565b60006020828403121561167a57600080fd5b5051919050565b600081600019048311821515161561169b5761169b61163a565b500290565b6000828210156116b2576116b261163a565b500390565b6000602082840312156116c957600080fd5b8151611489816113ba565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60006000198214156117145761171461163a565b5060010190565b60008261173857634e487b7160e01b600052601260045260246000fd5b50049056fea2646970667358221220a62c6ca8f319a95d4e2d4c79a17980884ac5a6c9f4ea95b4727a6779086931e064736f6c63430008090033608060405234801561001057600080fd5b506040516105de3803806105de83398101604081905261002f91610171565b61003833610047565b61004181610097565b506101a1565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b61009f610115565b6001600160a01b0381166101095760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b61011281610047565b50565b6000546001600160a01b0316331461016f5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610100565b565b60006020828403121561018357600080fd5b81516001600160a01b038116811461019a57600080fd5b9392505050565b61042e806101b06000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c8063715018a6146100515780638da5cb5b1461005b578063c2fb97f81461007a578063f2fde38b1461008d575b600080fd5b6100596100a0565b005b600054604080516001600160a01b039092168252519081900360200190f35b610059610088366004610358565b6100b4565b61005961009b366004610399565b610220565b6100a8610299565b6100b260006102f3565b565b6100bc610299565b6040516370a0823160e01b81523060048201526000906001600160a01b038516906370a082319060240160206040518083038186803b1580156100fe57600080fd5b505afa158015610112573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061013691906103bd565b9050808211156101975760405162461bcd60e51b815260206004820152602160248201527f42616c616e636520746f6f206c6f7720746f207472616e7366657220746f6b656044820152603760f91b60648201526084015b60405180910390fd5b60405163a9059cbb60e01b81526001600160a01b0384811660048301526024820184905285169063a9059cbb90604401602060405180830381600087803b1580156101e157600080fd5b505af11580156101f5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061021991906103d6565b5050505050565b610228610299565b6001600160a01b03811661028d5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161018e565b610296816102f3565b50565b6000546001600160a01b031633146100b25760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161018e565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b038116811461029657600080fd5b60008060006060848603121561036d57600080fd5b833561037881610343565b9250602084013561038881610343565b929592945050506040919091013590565b6000602082840312156103ab57600080fd5b81356103b681610343565b9392505050565b6000602082840312156103cf57600080fd5b5051919050565b6000602082840312156103e857600080fd5b815180151581146103b657600080fdfea264697066735822122071077358b908fded79f84649adeedc54814b5358875e2061b114720f3dc543a464736f6c63430008090033

Deployed Bytecode

0x6080604052600436106102c95760003560e01c8063913c6dc011610175578063c4b02908116100dc578063e151027411610095578063e76234ed1161006f578063e76234ed14610a6e578063eab19a4d14610a8e578063ede5b88d14610aae578063f2fde38b14610ace57600080fd5b8063e1510274146109eb578063e5addb6b14610a0b578063e718234d14610a4e57600080fd5b8063c4b0290814610888578063ce557031146108f3578063cf18c3431461095e578063d37de2b51461098b578063db27b8dd146109ab578063de010640146109cb57600080fd5b8063a2144aca1161012e578063a2144aca14610789578063a26f000d146107a9578063aed27f6414610808578063b23bb9c414610828578063ba2129b114610848578063c2fb97f81461086857600080fd5b8063913c6dc014610696578063949c694c146106a95780639851d082146106c95780639b82b9561461072a5780639db5dbe41461074a5780639ed796a41461076a57600080fd5b806344cc621c11610234578063715018a6116101ed5780637c829dee116101c75780637c829dee1461060e5780637e85f7241461062e5780638da5cb5b14610644578063900ddece1461067657600080fd5b8063715018a614610563578063763b6d9e146105785780637742557e146105ee57600080fd5b806344cc621c1461049457806357981736146104b65780635a835b9e146104d65780635af6d5e6146104f65780635e47861314610516578063619cf6801461054357600080fd5b80632e2bd9ea116102865780632e2bd9ea1461039657806332dc22f4146103b6578063371501cc146103d65780633af32abf146104035780633baaac2d146104535780633f184c011461047457600080fd5b80630e0bfb49146102ce5780630e5a71ae146102f7578063165e5934146103195780631867fd0a1461032f57806327eb1f911461034f5780632a4d6b3714610376575b600080fd5b3480156102da57600080fd5b506102e460045481565b6040519081526020015b60405180910390f35b34801561030357600080fd5b50610317610312366004612c3b565b610aee565b005b34801561032557600080fd5b506102e460035481565b34801561033b57600080fd5b5061031761034a366004612c70565b610bdf565b34801561035b57600080fd5b506013546103699060ff1681565b6040516102ee9190612cc1565b34801561038257600080fd5b50610317610391366004612cd4565b610c72565b3480156103a257600080fd5b506103176103b1366004612d16565b610d36565b3480156103c257600080fd5b506103176103d1366004612c70565b610e0c565b3480156103e257600080fd5b506103f66103f1366004612c70565b610eba565b6040516102ee9190612d42565b34801561040f57600080fd5b5061044361041e366004612c70565b6001600160a01b0316600090815260126020526040902054600160a01b900460ff1690565b60405190151581526020016102ee565b34801561045f57600080fd5b50601354610369906301000000900460ff1681565b34801561048057600080fd5b5061031761048f366004612d91565b610f47565b3480156104a057600080fd5b5060135461036990640100000000900460ff1681565b3480156104c257600080fd5b506103176104d1366004612dcc565b61109d565b3480156104e257600080fd5b506103176104f1366004612dfe565b6110b9565b34801561050257600080fd5b50610317610511366004612f5d565b6110f6565b34801561052257600080fd5b50610536610531366004612c70565b6114d8565b6040516102ee9190612f9c565b34801561054f57600080fd5b5061031761055e366004612dfe565b611560565b34801561056f57600080fd5b5061031761159a565b34801561058457600080fd5b506105c4610593366004612c70565b60106020526000908152604090208054600182015460028301546003909301546001600160a01b0390921692909184565b604080516001600160a01b03909516855260208501939093529183015260608201526080016102ee565b3480156105fa57600080fd5b50610317610609366004613015565b6115ae565b34801561061a57600080fd5b50610317610629366004612dfe565b61172b565b34801561063a57600080fd5b506102e460025481565b34801561065057600080fd5b506000546001600160a01b03165b6040516001600160a01b0390911681526020016102ee565b34801561068257600080fd5b506103176106913660046130a9565b611763565b6103176106a43660046130d9565b611899565b3480156106b557600080fd5b506103176106c4366004612c70565b611f31565b3480156106d557600080fd5b5061070b6106e4366004612c70565b6012602052600090815260409020546001600160a01b03811690600160a01b900460ff1682565b604080516001600160a01b0390931683529015156020830152016102ee565b34801561073657600080fd5b50610317610745366004612dfe565b611fd1565b34801561075657600080fd5b5061031761076536600461312c565b61200d565b34801561077657600080fd5b5060135461036990610100900460ff1681565b34801561079557600080fd5b506103176107a4366004612dfe565b612020565b3480156107b557600080fd5b506107e96107c4366004612c70565b601160205260009081526040902080546001909101546001600160a01b039091169082565b604080516001600160a01b0390931683526020830191909152016102ee565b34801561081457600080fd5b50610317610823366004612c70565b61205e565b34801561083457600080fd5b50610317610843366004612dfe565b6120ff565b34801561085457600080fd5b50610317610863366004612dfe565b61210c565b34801561087457600080fd5b5061031761088336600461312c565b612119565b34801561089457600080fd5b50600754600854600954600a546108c1936001600160a01b03811693600160a01b90910460ff1692909185565b604080516001600160a01b0390961686529315156020860152928401919091526060830152608082015260a0016102ee565b3480156108ff57600080fd5b5061093961090e366004612c70565b600f602052600090815260409020805460018201546002909201546001600160a01b03909116919083565b604080516001600160a01b0390941684526020840192909252908201526060016102ee565b34801561096a57600080fd5b5061097e610979366004612c70565b6121e0565b6040516102ee919061316d565b34801561099757600080fd5b506102e46109a63660046131eb565b612266565b3480156109b757600080fd5b5060055461065e906001600160a01b031681565b3480156109d757600080fd5b506103176109e6366004612d16565b6122c4565b3480156109f757600080fd5b506102e4610a06366004612c70565b61239c565b348015610a1757600080fd5b50600b54600c54600d54600e54610a2e9392919084565b6040805194855260208501939093529183015260608201526080016102ee565b348015610a5a57600080fd5b5060065461065e906001600160a01b031681565b348015610a7a57600080fd5b506013546103699062010000900460ff1681565b348015610a9a57600080fd5b50610317610aa9366004613217565b61241a565b348015610aba57600080fd5b50610317610ac9366004612dfe565b612509565b348015610ada57600080fd5b50610317610ae9366004612c70565b61258c565b610af6612605565b6001600160a01b038316610b255760405162461bcd60e51b8152600401610b1c9061324d565b60405180910390fd5b6001600160a01b038381166000908152600f60205260409020541615610b865760405162461bcd60e51b8152602060048201526016602482015275141d5c98da185cd9481d1bdad95b881bdb881b1a5cdd60521b6044820152606401610b1c565b604080516060810182526001600160a01b0394851680825260208083019586528284019485526000918252600f905291909120905181546001600160a01b03191694169390931783559051600183015551600290910155565b610be7612605565b6001600160a01b0381811660009081526011602052604090205416610c475760405162461bcd60e51b815260206004820152601660248201527514ddd85c081d1bdad95b881b9bdd081bdb881b1a5cdd60521b6044820152606401610b1c565b6001600160a01b0316600090815260116020526040812080546001600160a01b031916815560010155565b6001600160a01b0382163314610cc25760405162461bcd60e51b815260206004820152601560248201527421b630b4b6b2b91034b9903737ba103b32b9ba37b960591b6044820152606401610b1c565b600554604051632cd1b11360e01b8152600481018590526001600160a01b038481166024830152838116604483015290911690632cd1b113906064015b600060405180830381600087803b158015610d1957600080fd5b505af1158015610d2d573d6000803e3d6000fd5b50505050505050565b610d3e612605565b6001600160a01b038216610d645760405162461bcd60e51b8152600401610b1c9061324d565b6001600160a01b038281166000908152601160205260409020541615610dc15760405162461bcd60e51b815260206004820152601260248201527114ddd85c081d1bdad95b881bdb881b1a5cdd60721b6044820152606401610b1c565b6040805180820182526001600160a01b03938416808252602080830194855260009182526011905291909120905181546001600160a01b031916931692909217825551600190910155565b610e14612605565b6001600160a01b038116600090815260126020526040902054600160a01b900460ff16610e935760405162461bcd60e51b815260206004820152602760248201527f4164647265737320646f6573206e6f7420657869737420696e207468652077686044820152661a5d195b1a5cdd60ca1b6064820152608401610b1c565b6001600160a01b0316600090815260126020526040902080546001600160a81b0319169055565b600554604051630dc5407360e21b81526001600160a01b03838116600483015260609260009291169063371501cc9060240160006040518083038186803b158015610f0457600080fd5b505afa158015610f18573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610f40919081019061327c565b9392505050565b610f4f612605565b6001600160a01b038416610f755760405162461bcd60e51b8152600401610b1c9061324d565b6001600160a01b038481166000908152601060205260409020541615610fd55760405162461bcd60e51b815260206004820152601560248201527415995cdd1a5b99c81d1bdad95b881bdb881b1a5cdd605a1b6044820152606401610b1c565b6127108210158015610fea5750621e84808211155b6110365760405162461bcd60e51b815260206004820152601f60248201527f5072696365206d757374206265207363616c656420746f203130202a2a2034006044820152606401610b1c565b604080516080810182526001600160a01b0395861680825260208083019687528284019485526060830195865260009182526010905291909120905181546001600160a01b0319169516949094178455915160018401559051600283015551600390910155565b6110a5612605565b600b93909355600c91909155600d55600e55565b6110c1612605565b8060018111156110d3576110d3612c8d565b6013805460ff1916600183818111156110ee576110ee612c8d565b021790555050565b600060135462010000900460ff16600181111561111557611115612c8d565b146111585760405162461bcd60e51b81526020600482015260136024820152725377617070696e67206e6f742061637469766560681b6044820152606401610b1c565b61116061265f565b606081015133901580159061117d57508160400151826060015110155b801561118f5750600d54604083015110155b80156111a15750600e54606083015110155b6111ed5760405162461bcd60e51b815260206004820152601d60248201527f56657374696e673a206e6f742076616c696420706172616d65746572730000006044820152606401610b1c565b6111f9610e104261333d565b8260800151101561121c5760405162461bcd60e51b8152600401610b1c90613354565b6001600160a01b038381166000908152601160205260409020541661128f5760405162461bcd60e51b815260206004820152602360248201527f546f6b656e206d75737420626520617574686f72697a6564207377617020746f60448201526235b2b760e91b6064820152608401610b1c565b6000601354610100900460ff1660018111156112ad576112ad612c8d565b14156113195733600090815260126020526040902054600160a01b900460ff166113195760405162461bcd60e51b815260206004820152601a60248201527f53656e646572206973206e6f74206f6e2077686974656c6973740000000000006044820152606401610b1c565b600061133c612710611336600454886126b990919063ffffffff16565b906126c5565b905060008051602061378f83398151915281604051611391919060408082526019908201527815995cdd1a5b99c8105b5bdd5b9d0810d85b18dd5b185d1959603a1b6060820152602081019190915260800190565b60405180910390a16001600160a01b038085166000908152601160205260409020546113c091163330886126d1565b6000601354640100000000900460ff1660018111156113e1576113e1612c8d565b1415611404576006546113ff9085906001600160a01b03168761272b565b61142f565b61142f847f000000000000000000000000f950a86013baa227009771181a885e369e158da38761272b565b604080518181526015818301527414ddd85c08151bdad95b88151c985b9cd9995c9959605a1b606082015260208101879052905160008051602061378f8339815191529181900360800190a161148682828561288a565b604080516001600160a01b0384168152602081018390527f013860ae5eafafe669f2589467c1d6c258042a8acf0fc838c72690df147de3b2910160405180910390a150506114d360018055565b505050565b6005546040516302cdcfad60e41b81526001600160a01b0383811660048301526060921690632cdcfad09060240160006040518083038186803b15801561151e57600080fd5b505afa158015611532573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261155a9190810190613384565b92915050565b611568612605565b80600181111561157a5761157a612c8d565b6013805462ff00001916620100008360018111156110ee576110ee612c8d565b6115a2612605565b6115ac60006128fa565b565b6115b6612605565b60005b81518110156116f05760006001600160a01b03168282815181106115df576115df61344b565b60200260200101516001600160a01b0316141561163e5760405162461bcd60e51b815260206004820152601860248201527f4e756c6c2061646472657373206e6f7420616c6c6f77656400000000000000006044820152606401610b1c565b604051806040016040528083838151811061165b5761165b61344b565b60200260200101516001600160a01b03168152602001600115158152506012600084848151811061168e5761168e61344b565b6020908102919091018101516001600160a01b0390811683528282019390935260409091016000208351815494909201511515600160a01b026001600160a81b03199094169190921617919091179055806116e881613461565b9150506115b9565b507f6365182c588438b31e1fb8508f2afb0a7711f50fc126d7ca4a6519515b30718e81604051611720919061347c565b60405180910390a150565b611733612605565b80600181111561174557611745612c8d565b6013805461ff0019166101008360018111156110ee576110ee612c8d565b336001600160a01b037f000000000000000000000000f950a86013baa227009771181a885e369e158da316146117d15760405162461bcd60e51b815260206004820152601360248201527226bab63a34b9b4b3903737ba1031b0b63632b960691b6044820152606401610b1c565b600554604051634806ef6760e11b8152600481018490526001600160a01b0383811660248301529091169063900ddece90604401600060405180830381600087803b15801561181f57600080fd5b505af1158015611833573d6000803e3d6000fd5b505050506118538161184d6000546001600160a01b031690565b8461272b565b604080516001600160a01b0383168152602081018490527f69c20d72e70e5eb54eb53252bc65b4ce24cf88467ac61cd2883a6626ef23f2a8910160405180910390a15050565b600060135460ff1660018111156118b2576118b2612c8d565b146118f45760405162461bcd60e51b815260206004820152601260248201527156657374696e67206e6f742061637469766560701b6044820152606401610b1c565b6118fc61265f565b6000816060015111801561191857508060400151816060015110155b801561192a5750600c54606082015110155b801561193c5750600b54604082015110155b6119945760405162461bcd60e51b815260206004820152602360248201527f56657374696e673a20696e76616c69642076657374696e6720706172616d73206044820152621cd95d60ea1b6064820152608401610b1c565b6119a0610e104261333d565b816080015110156119c35760405162461bcd60e51b8152600401610b1c90613354565b6001600160a01b038381166000908152600f602052604090205416611a405760405162461bcd60e51b815260206004820152602d60248201527f45786368616e676520746f6b656e206d75737420626520612076616c6964206160448201526c38383937bb32b2103a37b5b2b760991b6064820152608401610b1c565b6001600160a01b038216600090815260106020526040812060030154611a6f90612710906113369088906126b9565b6001600160a01b038085166000908152601060209081526040808320600290810154948a168452600f9092528220015492935091611aae918491612266565b905060008051602061378f83398151915281604051611b1d91906040808252602d908201527f52657175697265642053656c6c20546f6b656e205061796d656e7420416d6f7560608201526c1b9d0810d85b18dd5b185d1959609a1b6080820152602081019190915260a00190565b60405180910390a16040516370a0823160e01b815233600482015281906001600160a01b038716906370a082319060240160206040518083038186803b158015611b6657600080fd5b505afa158015611b7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b9e91906134c9565b1015611c125760405162461bcd60e51b815260206004820152603960248201527f4e6f7420656e6f75676820746f6b656e7320696e2077616c6c657420746f206560448201527f786368616e676520666f722076657374696e6720746f6b656e000000000000006064820152608401610b1c565b6001600160a01b0385166000908152600f60205260408120600101548190611c3b9084906126c5565b905060008051602061378f83398151915281604051611ca891906040808252602b908201527f5363616c656420446f776e20416d6f756e74206f662053656c6c20546f6b656e60608201526a0810d85b18dd5b185d195960aa1b6080820152602081019190915260a00190565b60405180910390a1611ce56001600160a01b038816337f000000000000000000000000f950a86013baa227009771181a885e369e158da3866126d1565b6002548110611ec4576001600160a01b038616600090815260106020526040812060010154600354611d1d9190611336908c906126b9565b6001600160a01b03881660009081526010602052604081206001015491925090611d55906064906113369061271090829087906126b9565b905060008051602061378f83398151915281604051611dae91906040808252601c908201527f416d6f756e7420746f2052656c656173652043616c63756c61746564000000006060820152602081019190915260800190565b60405180910390a18015611dc757611dc781893361294a565b60408051338152602081018390527f61abec4c161a61671f290a0639ee645e59cc703b1053aedab833585da0947484910160405180910390a1611e0a8a826129bb565b935060008051602061378f83398151915284604051611e5f919060408082526019908201527815995cdd1a5b99c8105b5bdd5b9d0810d85b18dd5b185d1959603a1b6060820152602081019190915260800190565b60405180910390a1611e7233858961288a565b604080518581526001600160a01b038b16602082015290810184905233907f5520459799f5796c0602e6f8b3c955c4cb3b3892d173e93744ec83a70c8ee5fd9060600160405180910390a25050611f1e565b879150611ed233838761288a565b604080518381526001600160a01b038916602082015290810184905233907f5520459799f5796c0602e6f8b3c955c4cb3b3892d173e93744ec83a70c8ee5fd9060600160405180910390a25b50505050611f2b60018055565b50505050565b611f39612605565b6001600160a01b0381811660009081526010602052604090205416611f985760405162461bcd60e51b815260206004820152601560248201527415995cdd1a5b99c81d1bdad95b881bdb881b1a5cdd605a1b6044820152606401610b1c565b6001600160a01b0316600090815260106020526040812080546001600160a01b0319168155600181018290556002810182905560030155565b611fd9612605565b806001811115611feb57611feb612c8d565b6013805463ff000000191663010000008360018111156110ee576110ee612c8d565b612015612605565b6114d383838361272b565b612028612605565b80600181111561203a5761203a612c8d565b6013805464ff0000000019166401000000008360018111156110ee576110ee612c8d565b612066612605565b6001600160a01b038181166000908152600f6020526040902054166120cd5760405162461bcd60e51b815260206004820152601a60248201527f507572636861736520746f6b656e206e6f74206f6e206c6973740000000000006044820152606401610b1c565b6001600160a01b03166000908152600f6020526040812080546001600160a01b03191681556001810182905560020155565b612107612605565b600255565b612114612605565b600455565b612121612605565b60065460405163185f72ff60e31b81526001600160a01b0385811660048301528481166024830152604482018490529091169063c2fb97f890606401600060405180830381600087803b15801561217757600080fd5b505af115801561218b573d6000803e3d6000fd5b5050604080516001600160a01b038088168252861660208201529081018490527fd25f579861b27075004b261043a11a5162757e7007eac235177a6db3988285ec9250606001905060405180910390a1505050565b6005546040516336ccda4f60e01b81526001600160a01b0383811660048301526060926000929116906336ccda4f9060240160006040518083038186803b15801561222a57600080fd5b505afa15801561223e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610f4091908101906134e2565b600081831415612277575082610f40565b818311156122a557612289828461333d565b61229490600a6136a9565b61229e90856136b5565b9050610f40565b6122af838361333d565b6122ba90600a6136a9565b61229e90856136d7565b336001600160a01b037f000000000000000000000000f950a86013baa227009771181a885e369e158da316146123325760405162461bcd60e51b815260206004820152601360248201527226bab63a34b9b4b3903737ba1031b0b63632b960691b6044820152606401610b1c565b600554604051630378041960e61b81526001600160a01b038481166004830152602482018490529091169063de01064090604401600060405180830381600087803b15801561238057600080fd5b505af1158015612394573d6000803e3d6000fd5b505050505050565b60055460405163929ec53760e01b81526001600160a01b038381166004830152600092169063929ec5379060240160206040518083038186803b1580156123e257600080fd5b505afa1580156123f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061155a91906134c9565b60006013546301000000900460ff16600181111561243a5761243a612c8d565b146124875760405162461bcd60e51b815260206004820152601b60248201527f5374616e646172642076657374696e67206e6f742061637469766500000000006044820152606401610b1c565b61248f612605565b61249b610e104261333d565b816080015110156124be5760405162461bcd60e51b8152600401610b1c90613354565b816124ca84828461288a565b60408051338152602081018390527f013860ae5eafafe669f2589467c1d6c258042a8acf0fc838c72690df147de3b2910160405180910390a150505050565b612511612605565b61271081101580156125265750620f42408111155b6125875760405162461bcd60e51b815260206004820152602c60248201527f52656c656173652070657263656e74616765206d757374206265207363616c6560448201526b19081d1bc80c4c080a8a880d60a21b6064820152608401610b1c565b600355565b612594612605565b6001600160a01b0381166125f95760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610b1c565b612602816128fa565b50565b6000546001600160a01b031633146115ac5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b1c565b600260015414156126b25760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610b1c565b6002600155565b6000610f4082846136d7565b6000610f4082846136b5565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052611f2b9085906129c7565b6040516370a0823160e01b81523060048201526000906001600160a01b038516906370a082319060240160206040518083038186803b15801561276d57600080fd5b505afa158015612781573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127a591906134c9565b9050808211156128015760405162461bcd60e51b815260206004820152602160248201527f42616c616e636520746f6f206c6f7720746f207472616e7366657220746f6b656044820152603760f91b6064820152608401610b1c565b60405163a9059cbb60e01b81526001600160a01b0384811660048301526024820184905285169063a9059cbb90604401602060405180830381600087803b15801561284b57600080fd5b505af115801561285f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061288391906136f6565b5050505050565b60055481516020830151604080850151606086015160808701519251630d53588360e01b81526001600160a01b038a81166004830152602482018a905295861660448201529315156064850152608484019190915260a483015260c4820152911690630d5358839060e401610cff565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600554604051634806ef6760e11b8152600481018590526001600160a01b0384811660248301529091169063900ddece90604401600060405180830381600087803b15801561299857600080fd5b505af11580156129ac573d6000803e3d6000fd5b505050506114d382828561272b565b6000610f40828461333d565b6000612a1c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612a999092919063ffffffff16565b8051909150156114d35780806020019051810190612a3a91906136f6565b6114d35760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610b1c565b6060612aa88484600085612ab0565b949350505050565b606082471015612b115760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610b1c565b600080866001600160a01b03168587604051612b2d919061373f565b60006040518083038185875af1925050503d8060008114612b6a576040519150601f19603f3d011682016040523d82523d6000602084013e612b6f565b606091505b5091509150612b8087838387612b8b565b979650505050505050565b60608315612bf7578251612bf0576001600160a01b0385163b612bf05760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b1c565b5081612aa8565b612aa88383815115612c0c5781518083602001fd5b8060405162461bcd60e51b8152600401610b1c919061375b565b6001600160a01b038116811461260257600080fd5b600080600060608486031215612c5057600080fd5b8335612c5b81612c26565b95602085013595506040909401359392505050565b600060208284031215612c8257600080fd5b8135610f4081612c26565b634e487b7160e01b600052602160045260246000fd5b6002811061260257634e487b7160e01b600052602160045260246000fd5b60208101612cce83612ca3565b91905290565b600080600060608486031215612ce957600080fd5b833592506020840135612cfb81612c26565b91506040840135612d0b81612c26565b809150509250925092565b60008060408385031215612d2957600080fd5b8235612d3481612c26565b946020939093013593505050565b602080825282518282018190526000919060409081850190868401855b82811015612d8457815180518552860151868501529284019290850190600101612d5f565b5091979650505050505050565b60008060008060808587031215612da757600080fd5b8435612db281612c26565b966020860135965060408601359560600135945092505050565b60008060008060808587031215612de257600080fd5b5050823594602084013594506040840135936060013592509050565b600060208284031215612e1057600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715612e5057612e50612e17565b60405290565b6040516060810167ffffffffffffffff81118282101715612e5057612e50612e17565b60405160e0810167ffffffffffffffff81118282101715612e5057612e50612e17565b604051601f8201601f1916810167ffffffffffffffff81118282101715612ec557612ec5612e17565b604052919050565b801515811461260257600080fd5b600060a08284031215612eed57600080fd5b60405160a0810181811067ffffffffffffffff82111715612f1057612f10612e17565b6040529050808235612f2181612c26565b81526020830135612f3181612ecd565b806020830152506040830135604082015260608301356060820152608083013560808201525092915050565b600080600060e08486031215612f7257600080fd5b833592506020840135612f8481612c26565b9150612f938560408601612edb565b90509250925092565b602080825282518282018190526000919060409081850190868401855b82811015612d8457815180516001600160a01b0316855286810151878601528501518585015260609093019290850190600101612fb9565b600067ffffffffffffffff82111561300b5761300b612e17565b5060051b60200190565b6000602080838503121561302857600080fd5b823567ffffffffffffffff81111561303f57600080fd5b8301601f8101851361305057600080fd5b803561306361305e82612ff1565b612e9c565b81815260059190911b8201830190838101908783111561308257600080fd5b928401925b82841015612b8057833561309a81612c26565b82529284019290840190613087565b600080604083850312156130bc57600080fd5b8235915060208301356130ce81612c26565b809150509250929050565b60008060008061010085870312156130f057600080fd5b84359350602085013561310281612c26565b9250604085013561311281612c26565b91506131218660608701612edb565b905092959194509250565b60008060006060848603121561314157600080fd5b833561314c81612c26565b9250602084013561315c81612c26565b929592945050506040919091013590565b602080825282518282018190526000919060409081850190868401855b82811015612d845781518051855286810151878601528581015186860152606080820151908601526080808201519086015260a0808201519086015260c0908101516001600160a01b03169085015260e0909301929085019060010161318a565b60008060006060848603121561320057600080fd5b505081359360208301359350604090920135919050565b600080600060e0848603121561322c57600080fd5b833561323781612c26565b925060208401359150612f938560408601612edb565b602080825260159082015274496e76616c696420746f6b656e206164647265737360581b604082015260600190565b6000602080838503121561328f57600080fd5b825167ffffffffffffffff8111156132a657600080fd5b8301601f810185136132b757600080fd5b80516132c561305e82612ff1565b81815260069190911b820183019083810190878311156132e457600080fd5b928401925b82841015612b8057604084890312156133025760008081fd5b61330a612e2d565b8451815285850151868201528252604090930192908401906132e9565b634e487b7160e01b600052601160045260246000fd5b60008282101561334f5761334f613327565b500390565b602080825260169082015275125b9d985b1a59081cdd185c9d081d1a5b59481cd95d60521b604082015260600190565b6000602080838503121561339757600080fd5b825167ffffffffffffffff8111156133ae57600080fd5b8301601f810185136133bf57600080fd5b80516133cd61305e82612ff1565b818152606091820283018401918482019190888411156133ec57600080fd5b938501935b8385101561343f5780858a0312156134095760008081fd5b613411612e56565b855161341c81612c26565b8152858701518782015260408087015190820152835293840193918501916133f1565b50979650505050505050565b634e487b7160e01b600052603260045260246000fd5b600060001982141561347557613475613327565b5060010190565b6020808252825182820181905260009190848201906040850190845b818110156134bd5783516001600160a01b031683529284019291840191600101613498565b50909695505050505050565b6000602082840312156134db57600080fd5b5051919050565b600060208083850312156134f557600080fd5b825167ffffffffffffffff81111561350c57600080fd5b8301601f8101851361351d57600080fd5b805161352b61305e82612ff1565b81815260e0918202830184019184820191908884111561354a57600080fd5b938501935b8385101561343f5780858a0312156135675760008081fd5b61356f612e79565b85518152868601518782015260408087015190820152606080870151908201526080808701519082015260a0808701519082015260c0808701516135b281612c26565b908201528352938401939185019161354f565b600181815b808511156136005781600019048211156135e6576135e6613327565b808516156135f357918102915b93841c93908002906135ca565b509250929050565b6000826136175750600161155a565b816136245750600061155a565b816001811461363a576002811461364457613660565b600191505061155a565b60ff84111561365557613655613327565b50506001821b61155a565b5060208310610133831016604e8410600b8410161715613683575081810a61155a565b61368d83836135c5565b80600019048211156136a1576136a1613327565b029392505050565b6000610f408383613608565b6000826136d257634e487b7160e01b600052601260045260246000fd5b500490565b60008160001904831182151516156136f1576136f1613327565b500290565b60006020828403121561370857600080fd5b8151610f4081612ecd565b60005b8381101561372e578181015183820152602001613716565b83811115611f2b5750506000910152565b60008251613751818460208701613713565b9190910192915050565b602081526000825180602084015261377a816040850160208701613713565b601f01601f1916919091016040019291505056fee520fdce79bb8277387a89e5c39651632ba577f54f87fab58b3f0b21c8fcdee3a264697066735822122036df003e70f9bdc1c12c9df317aa9f9e1d7e80fd9718873d7b77d84b2a73fbc164736f6c63430008090033

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  ]
[ 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.