ETH Price: $1,914.32 (-1.48%)

Contract

0x483ea73F891525a62bEe36de6A2f25C425A331Bb

Overview

ETH Balance

0 ETH

ETH Value

$0.00

More Info

Private Name Tags

TokenTracker

Multichain Info

No addresses found
Transaction Hash
Block
From
To

There are no matching entries

Please try again later

Parent Transaction Hash Block From To
View All Internal Transactions

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
WethPool

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
// SPDX-License-Identifier: BUSL-1.1
// Last deployed from commit: 5ec1894d31c2b378fec21fa1613df34e7438169c;
pragma solidity 0.8.17;

import "../../WrappedNativeTokenPool.sol";


/**
 * @title WethPool
 * @dev Contract allowing user to deposit to and borrow WETH from a dedicated user account
 */
contract WethPool is WrappedNativeTokenPool {
    // Returns max. acceptable pool utilisation after borrow action
    function getMaxPoolUtilisationForBorrowing() override public view returns (uint256) {
        return 0.9e18;
    }

    function name() public virtual override pure returns(string memory _name){
        _name = "DeltaPrimeWrappedETH";
    }

    function symbol() public virtual override pure returns(string memory _symbol){
        _symbol = "DPWETH";
    }

    function decimals() public virtual override pure returns(uint8 decimals){
        decimals = 18;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.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 OwnableUpgradeable is Initializable, ContextUpgradeable {
    address private _owner;

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    function __Ownable_init() internal onlyInitializing {
        __Ownable_init_unchained();
    }

    function __Ownable_init_unchained() internal onlyInitializing {
        _transferOwnership(_msgSender());
    }

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

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        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);
    }

    /**
     * This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}

File 3 of 18 : Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.0;

import "../../utils/AddressUpgradeable.sol";

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To initialize the implementation contract, you can either invoke the
 * initializer manually, or you can include a constructor to automatically mark it as initialized when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() initializer {}
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     */
    bool private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Modifier to protect an initializer function from being invoked twice.
     */
    modifier initializer() {
        // If the contract is initializing we ignore whether _initialized is set in order to support multiple
        // inheritance patterns, but we only do this in the context of a constructor, because in other contexts the
        // contract may have been reentered.
        require(_initializing ? _isConstructor() : !_initialized, "Initializable: contract is already initialized");

        bool isTopLevelCall = !_initializing;
        if (isTopLevelCall) {
            _initializing = true;
            _initialized = true;
        }

        _;

        if (isTopLevelCall) {
            _initializing = false;
        }
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} modifier, directly or indirectly.
     */
    modifier onlyInitializing() {
        require(_initializing, "Initializable: contract is not initializing");
        _;
    }

    function _isConstructor() private view returns (bool) {
        return !AddressUpgradeable.isContract(address(this));
    }
}

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

pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";

/**
 * @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 ReentrancyGuardUpgradeable is Initializable {
    // 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;

    function __ReentrancyGuard_init() internal onlyInitializing {
        __ReentrancyGuard_init_unchained();
    }

    function __ReentrancyGuard_init_unchained() internal onlyInitializing {
        _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() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

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

        _;

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

    /**
     * This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)

pragma solidity ^0.8.1;

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

        return account.code.length > 0;
    }

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

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

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

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

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

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

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

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

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

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

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

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

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

pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";

/**
 * @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 ContextUpgradeable is Initializable {
    function __Context_init() internal onlyInitializing {
    }

    function __Context_init_unchained() internal onlyInitializing {
    }
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

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

    /**
     * This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

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

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

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

    /**
     * @dev Moves `amount` tokens from the caller's account to `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);

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a / b + (a % b == 0 ? 0 : 1);
    }
}

// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity >=0.6.0;

// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
library TransferHelper {
    function safeApprove(
        address token,
        address to,
        uint256 value
    ) internal {
        // bytes4(keccak256(bytes('approve(address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
        require(
            success && (data.length == 0 || abi.decode(data, (bool))),
            'TransferHelper::safeApprove: approve failed'
        );
    }

    function safeTransfer(
        address token,
        address to,
        uint256 value
    ) internal {
        // bytes4(keccak256(bytes('transfer(address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
        require(
            success && (data.length == 0 || abi.decode(data, (bool))),
            'TransferHelper::safeTransfer: transfer failed'
        );
    }

    function safeTransferFrom(
        address token,
        address from,
        address to,
        uint256 value
    ) internal {
        // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
        require(
            success && (data.length == 0 || abi.decode(data, (bool))),
            'TransferHelper::transferFrom: transferFrom failed'
        );
    }

    function safeTransferETH(address to, uint256 value) internal {
        (bool success, ) = to.call{value: value}(new bytes(0));
        require(success, 'TransferHelper::safeTransferETH: ETH transfer failed');
    }
}

// SPDX-License-Identifier: BUSL-1.1
// Last deployed from commit: ;
pragma solidity 0.8.17;

/**
 * @title IBorrowersRegistry
 * Keeps a registry of created trading accounts to verify their borrowing rights
 */
interface IBorrowersRegistry {
    function canBorrow(address _account) external view returns (bool);

    function getLoanForOwner(address _owner) external view returns (address);

    function getOwnerOfLoan(address _loan) external view returns (address);
}

// SPDX-License-Identifier: BUSL-1.1
// Last deployed from commit: c5c938a0524b45376dd482cd5c8fb83fa94c2fcc;
pragma solidity 0.8.17;

interface IIndex {

    function setRate(uint256 _rate) external;

    function updateUser(address user) external;

    function getIndex() external view returns (uint256);

    function getIndexedValue(uint256 value, address user) external view returns (uint256);

}

// SPDX-License-Identifier: BUSL-1.1
// Last deployed from commit: ;
pragma solidity ^0.8.17;

interface IPoolRewarder {

    function stakeFor(uint _amount, address _stakeFor) external;

    function withdrawFor(uint _amount, address _unstakeFor) external returns (uint);

    function getRewardsFor(address _user) external;

    function earned(address _account) external view returns (uint);

    function balanceOf(address _account) external view returns (uint);
}

// SPDX-License-Identifier: BUSL-1.1
// Last deployed from commit: ;
pragma solidity 0.8.17;

/**
 * @title IRatesCalculator
 * @dev Interface defining base method for contracts implementing interest rates calculation.
 * The calculated value could be based on the relation between funds borrowed and deposited.
 */
interface IRatesCalculator {
    function calculateBorrowingRate(uint256 totalLoans, uint256 totalDeposits) external view returns (uint256);

    function calculateDepositRate(uint256 totalLoans, uint256 totalDeposits) external view returns (uint256);
}

// SPDX-License-Identifier: BUSL-1.1

pragma solidity 0.8.17;

interface IWrappedNativeToken {

    function balanceOf(address account) external view returns (uint);

    function deposit() external payable;

    function withdraw(uint wad) external;

    function totalSupply() external view returns (uint);

    function approve(address guy, uint wad) external returns (bool);

    function transfer(address dst, uint wad) external returns (bool);

    function transferFrom(address src, address dst, uint wad) external returns (bool);

}

File 16 of 18 : Pool.sol
// SPDX-License-Identifier: BUSL-1.1
// Last deployed from commit: 5ec1894d31c2b378fec21fa1613df34e7438169c;
pragma solidity 0.8.17;

import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
import "@uniswap/lib/contracts/libraries/TransferHelper.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";
import "./interfaces/IIndex.sol";
import "./interfaces/IRatesCalculator.sol";
import "./interfaces/IBorrowersRegistry.sol";
import "./interfaces/IPoolRewarder.sol";
import "./VestingDistributor.sol";


/**
 * @title Pool
 * @dev Contract allowing user to deposit to and borrow from a dedicated user account
 * Depositors are rewarded with the interest rates collected from borrowers.
 * The interest rates calculation is delegated to an external calculator contract.
 */
contract Pool is OwnableUpgradeable, ReentrancyGuardUpgradeable, IERC20 {
    using TransferHelper for address payable;

    uint256 public totalSupplyCap;

    mapping(address => mapping(address => uint256)) private _allowed;
    mapping(address => uint256) internal _deposited;

    mapping(address => uint256) public borrowed;

    IRatesCalculator public ratesCalculator;
    IBorrowersRegistry public borrowersRegistry;
    IPoolRewarder public poolRewarder;

    IIndex public depositIndex;
    IIndex public borrowIndex;

    address payable public tokenAddress;

    VestingDistributor public vestingDistributor;

    uint8 internal _decimals;


    function initialize(IRatesCalculator ratesCalculator_, IBorrowersRegistry borrowersRegistry_, IIndex depositIndex_, IIndex borrowIndex_, address payable tokenAddress_, IPoolRewarder poolRewarder_, uint256 _totalSupplyCap) public initializer {
        require(AddressUpgradeable.isContract(address(ratesCalculator_))
            && AddressUpgradeable.isContract(address(borrowersRegistry_))
            && AddressUpgradeable.isContract(address(depositIndex_))
            && AddressUpgradeable.isContract(address(borrowIndex_))
            && (AddressUpgradeable.isContract(address(poolRewarder_)) || address(poolRewarder_) == address(0)), "Wrong init arguments");

        borrowersRegistry = borrowersRegistry_;
        ratesCalculator = ratesCalculator_;
        depositIndex = depositIndex_;
        borrowIndex = borrowIndex_;
        poolRewarder = poolRewarder_;
        tokenAddress = tokenAddress_;
        totalSupplyCap = _totalSupplyCap;

        _decimals = IERC20Metadata(tokenAddress_).decimals();

        __Ownable_init();
        __ReentrancyGuard_init();
        _updateRates();
    }

    /* ========== SETTERS ========== */

    /**
     * Sets new totalSupplyCap limiting how much in total can be deposited to the Pool.
     * Only the owner of the Contract can execute this function.
     * @dev _newTotalSupplyCap new deposit cap
    **/
    function setTotalSupplyCap(uint256 _newTotalSupplyCap) external onlyOwner {
        totalSupplyCap = _newTotalSupplyCap;
    }

    /**
     * Sets the new Pool Rewarder.
     * The IPoolRewarder that distributes additional token rewards to people having a stake in this pool proportionally to their stake and time of participance.
     * Only the owner of the Contract can execute this function.
     * @dev _poolRewarder the address of PoolRewarder
    **/
    function setPoolRewarder(IPoolRewarder _poolRewarder) external onlyOwner {
        if(!AddressUpgradeable.isContract(address(_poolRewarder)) && address(_poolRewarder) != address(0)) revert NotAContract(address(poolRewarder));
        poolRewarder = _poolRewarder;

        emit PoolRewarderChanged(address(_poolRewarder), block.timestamp);
    }

    /**
     * Sets the new rate calculator.
     * The calculator is an external contract that contains the logic for calculating deposit and borrowing rates.
     * Only the owner of the Contract can execute this function.
     * @dev ratesCalculator the address of rates calculator
     **/
    function setRatesCalculator(IRatesCalculator ratesCalculator_) external onlyOwner {
        // setting address(0) ratesCalculator_ freezes the pool
        if(!AddressUpgradeable.isContract(address(ratesCalculator_)) && address(ratesCalculator_) != address(0)) revert NotAContract(address(ratesCalculator_));
        ratesCalculator = ratesCalculator_;
        if (address(ratesCalculator_) != address(0)) {
            _updateRates();
        }

        emit RatesCalculatorChanged(address(ratesCalculator_), block.timestamp);
    }

    /**
     * Sets the new borrowers registry contract.
     * The borrowers registry decides if an account can borrow funds.
     * Only the owner of the Contract can execute this function.
     * @dev borrowersRegistry the address of borrowers registry
     **/
    function setBorrowersRegistry(IBorrowersRegistry borrowersRegistry_) external onlyOwner {
        if(!AddressUpgradeable.isContract(address(borrowersRegistry_))) revert NotAContract(address(borrowersRegistry_));

        borrowersRegistry = borrowersRegistry_;
        emit BorrowersRegistryChanged(address(borrowersRegistry_), block.timestamp);
    }

    /**
     * Sets the new Pool Rewarder.
     * The IPoolRewarder that distributes additional token rewards to people having a stake in this pool proportionally to their stake and time of participance.
     * Only the owner of the Contract can execute this function.
     * @dev _poolRewarder the address of PoolRewarder
    **/
    function setVestingDistributor(address _distributor) external onlyOwner {
        if(!AddressUpgradeable.isContract(_distributor) && _distributor != address(0)) revert NotAContract(_distributor);
        vestingDistributor = VestingDistributor(_distributor);

        emit VestingDistributorChanged(_distributor, block.timestamp);
    }

    /* ========== MUTATIVE FUNCTIONS ========== */
    function transfer(address recipient, uint256 amount) external override nonReentrant returns (bool) {
        if(recipient == address(0)) revert TransferToZeroAddress();

        if(recipient == address(this)) revert TransferToPoolAddress();

        address account = msg.sender;
        _accumulateDepositInterest(account);

        (uint256 lockedAmount, uint256 transferrableAmount) = _getAmounts(account);
        if(amount > transferrableAmount) revert TransferAmountExceedsBalance(amount, transferrableAmount);

        _updateWithdrawn(account, amount, lockedAmount);

        // (this is verified in "require" above)
        unchecked {
            _deposited[account] -= amount;
        }

        _accumulateDepositInterest(recipient);
        _deposited[recipient] += amount;

        // Handle rewards
        if(address(poolRewarder) != address(0) && amount != 0){
            uint256 unstaked = poolRewarder.withdrawFor(amount, account);
            if(unstaked > 0) {
                poolRewarder.stakeFor(unstaked, recipient);
            }
        }

        emit Transfer(account, recipient, amount);

        return true;
    }

    function allowance(address owner, address spender) external view override returns (uint256) {
        return _allowed[owner][spender];
    }

    function increaseAllowance(address spender, uint256 addedValue) external returns (bool) {
        if(spender == address(0)) revert SpenderZeroAddress();
        uint256 newAllowance = _allowed[msg.sender][spender] + addedValue;
        _allowed[msg.sender][spender] = newAllowance;

        emit Approval(msg.sender, spender, newAllowance);
        return true;
    }

    function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool) {
        if(spender == address(0)) revert SpenderZeroAddress();
        uint256 currentAllowance = _allowed[msg.sender][spender];
        if(currentAllowance < subtractedValue) revert InsufficientAllowance(subtractedValue, currentAllowance);

        uint256 newAllowance = currentAllowance - subtractedValue;
        _allowed[msg.sender][spender] = newAllowance;

        emit Approval(msg.sender, spender, newAllowance);
        return true;
    }

    function approve(address spender, uint256 amount) external override returns (bool) {
        if(spender == address(0)) revert SpenderZeroAddress();
        _allowed[msg.sender][spender] = amount;

        emit Approval(msg.sender, spender, amount);

        return true;
    }

    function transferFrom(address sender, address recipient, uint256 amount) external override nonReentrant returns (bool) {
        if(_allowed[sender][msg.sender] < amount) revert InsufficientAllowance(amount, _allowed[sender][msg.sender]);

        if(recipient == address(0)) revert TransferToZeroAddress();

        if(recipient == address(this)) revert TransferToPoolAddress();

        _accumulateDepositInterest(sender);

        (uint256 lockedAmount, uint256 transferrableAmount) = _getAmounts(sender);
        if(amount > transferrableAmount) revert TransferAmountExceedsBalance(amount, transferrableAmount);

        _updateWithdrawn(sender, amount, lockedAmount);

        _deposited[sender] -= amount;
        _allowed[sender][msg.sender] -= amount;

        _accumulateDepositInterest(recipient);
        _deposited[recipient] += amount;

        // Handle rewards
        if(address(poolRewarder) != address(0) && amount != 0){
            uint256 unstaked = poolRewarder.withdrawFor(amount, sender);
            if(unstaked > 0) {
                poolRewarder.stakeFor(unstaked, recipient);
            }
        }

        emit Transfer(sender, recipient, amount);

        return true;
    }


    /**
     * Deposits the amount
     * It updates user deposited balance, total deposited and rates
     **/
    function deposit(uint256 _amount) public virtual {
        depositOnBehalf(_amount, msg.sender);
    }

    /**
     * Deposits the amount on behalf of `_of` user.
     * It updates `_of` user deposited balance, total deposited and rates
     **/
    function depositOnBehalf(uint256 _amount, address _of) public virtual nonReentrant {
        if(_amount == 0) revert ZeroDepositAmount();
        require(_of != address(0), "Address zero");
        require(_of != address(this), "Cannot deposit on behalf of pool");

        _amount = Math.min(_amount, IERC20(tokenAddress).balanceOf(msg.sender));

        _accumulateDepositInterest(_of);

        if(totalSupplyCap != 0){
            if(_deposited[address(this)] + _amount > totalSupplyCap) revert TotalSupplyCapBreached();
        }

        _transferToPool(msg.sender, _amount);

        _mint(_of, _amount);
        _deposited[address(this)] += _amount;
        _updateRates();

        if (address(poolRewarder) != address(0)) {
            poolRewarder.stakeFor(_amount, _of);
        }

        emit DepositOnBehalfOf(msg.sender, _of, _amount, block.timestamp);
    }

    function _transferToPool(address from, uint256 amount) internal virtual {
        tokenAddress.safeTransferFrom(from, address(this), amount);
    }

    function _transferFromPool(address to, uint256 amount) internal virtual {
        tokenAddress.safeTransfer(to, amount);
    }

    /**
     * Withdraws selected amount from the user deposits
     * @dev _amount the amount to be withdrawn
     **/
    function withdraw(uint256 _amount) external nonReentrant {
        _accumulateDepositInterest(msg.sender);
        _amount = Math.min(_amount, _deposited[msg.sender]);

        if(_amount > IERC20(tokenAddress).balanceOf(address(this))) revert InsufficientPoolFunds();

        if(_amount > _deposited[address(this)]) revert BurnAmountExceedsBalance();
        // verified in "require" above
        unchecked {
            _deposited[address(this)] -= _amount;
        }
        _burn(msg.sender, _amount);

        _updateRates();

        _transferFromPool(msg.sender, _amount);

        if (address(poolRewarder) != address(0)) {
            poolRewarder.withdrawFor(_amount, msg.sender);
        }

        emit Withdrawal(msg.sender, _amount, block.timestamp);
    }

    /**
     * Borrows the specified amount
     * It updates user borrowed balance, total borrowed amount and rates
     * @dev _amount the amount to be borrowed
     * @dev It is only meant to be used by a SmartLoanDiamondProxy
     **/
    function borrow(uint256 _amount) public virtual canBorrow nonReentrant {
        if (_amount > IERC20(tokenAddress).balanceOf(address(this))) revert InsufficientPoolFunds();

        _accumulateBorrowingInterest(msg.sender);

        borrowed[msg.sender] += _amount;
        borrowed[address(this)] += _amount;

        _transferFromPool(msg.sender, _amount);

        _updateRates();

        emit Borrowing(msg.sender, _amount, block.timestamp);
    }

    /**
     * Repays the amount
     * It updates user borrowed balance, total borrowed amount and rates
     * @dev It is only meant to be used by a SmartLoanDiamondProxy
     **/
    function repay(uint256 amount) external nonReentrant {
        _accumulateBorrowingInterest(msg.sender);

        if(amount > borrowed[msg.sender]) revert RepayingMoreThanWasBorrowed();
        _transferToPool(msg.sender, amount);

        borrowed[msg.sender] -= amount;
        borrowed[address(this)] -= amount;

        _updateRates();

        emit Repayment(msg.sender, amount, block.timestamp);
    }

    /* =========


    /**
     * Returns the current borrowed amount for the given user
     * The value includes the interest rates owned at the current moment
     * @dev _user the address of queried borrower
    **/
    function getBorrowed(address _user) public view returns (uint256) {
        return borrowIndex.getIndexedValue(borrowed[_user], _user);
    }

    function name() public virtual pure returns(string memory _name){
        _name = "";
    }

    function symbol() public virtual pure returns(string memory _symbol){
        _symbol = "";
    }

    function decimals() public virtual view returns(uint8){
        return _decimals;
    }

    function totalSupply() public view override returns (uint256) {
        return balanceOf(address(this));
    }

    function totalBorrowed() public view returns (uint256) {
        return getBorrowed(address(this));
    }


    // Calls the IPoolRewarder.getRewardsFor() that sends pending rewards to msg.sender
    function getRewards() external {
        poolRewarder.getRewardsFor(msg.sender);
    }

    // Returns number of pending rewards for msg.sender
    function checkRewards() external view returns (uint256) {
        return poolRewarder.earned(msg.sender);
    }

    // Returns max. acceptable pool utilisation after borrow action
    function getMaxPoolUtilisationForBorrowing() virtual public view returns (uint256) {
        return 0.9e18;
    }

    /**
     * Returns the current deposited amount for the given user
     * The value includes the interest rates earned at the current moment
     * @dev _user the address of queried depositor
     **/
    function balanceOf(address user) public view override returns (uint256) {
        return depositIndex.getIndexedValue(_deposited[user], user);
    }

    /**
     * Returns the current interest rate for deposits
     **/
    function getDepositRate() public view returns (uint256) {
        return ratesCalculator.calculateDepositRate(totalBorrowed(), totalSupply());
    }

    /**
     * Returns the current interest rate for borrowings
     **/
    function getBorrowingRate() public view returns (uint256) {
        return ratesCalculator.calculateBorrowingRate(totalBorrowed(), totalSupply());
    }

    /**
     * Returns full pool status
     */
    function getFullPoolStatus() public view returns (uint256[5] memory) {
        return [
            totalSupply(),
            getDepositRate(),
            getBorrowingRate(),
            totalBorrowed(),
            getMaxPoolUtilisationForBorrowing()
        ];
    }

    /**
     * Recovers the surplus funds resultant from difference between deposit and borrowing rates
     **/
    function recoverSurplus(uint256 amount, address account) public onlyOwner nonReentrant {
        uint256 balance = IERC20(tokenAddress).balanceOf(address(this));
        uint256 surplus = balance + totalBorrowed() - totalSupply();

        if(amount > balance) revert InsufficientPoolFunds();
        if(surplus < amount) revert InsufficientSurplus();

        _transferFromPool(account, amount);
    }

    /* ========== INTERNAL FUNCTIONS ========== */

    function _mint(address to, uint256 amount) internal {
        if(to == address(0)) revert MintToAddressZero();

        _deposited[to] += amount;

        emit Transfer(address(0), to, amount);
    }

    function _burn(address account, uint256 amount) internal {
        if(amount > _deposited[account]) revert BurnAmountExceedsBalance();
        (uint256 lockedAmount, uint256 transferrableAmount) = _getAmounts(account);
        if(amount > transferrableAmount) revert BurnAmountExceedsAvailableForUser();

        _updateWithdrawn(account, amount, lockedAmount);

        // verified in "require" above
        unchecked {
            _deposited[account] -= amount;
        }

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

    function _getAmounts(address account) internal view returns (uint256 lockedAmount, uint256 transferrableAmount) {
        if (address(vestingDistributor) != address(0)) {
            lockedAmount = vestingDistributor.locked(account);
            transferrableAmount = _deposited[account] - (lockedAmount - vestingDistributor.availableToWithdraw(account));
        } else {
            transferrableAmount = _deposited[account];
        }
    }

    function _updateWithdrawn(address account, uint256 amount, uint256 lockedAmount) internal {
        uint256 availableUnvested = _deposited[account] - lockedAmount;
        if (amount > availableUnvested && address(vestingDistributor) != address(0)) {
            vestingDistributor.updateWithdrawn(account, amount - availableUnvested);
        }
    }

    function _updateRates() internal {
        uint256 _totalBorrowed = totalBorrowed();
        uint256 _totalSupply = totalSupply();
        if(address(ratesCalculator) == address(0)) revert PoolFrozen();
        depositIndex.setRate(ratesCalculator.calculateDepositRate(_totalBorrowed, _totalSupply));
        borrowIndex.setRate(ratesCalculator.calculateBorrowingRate(_totalBorrowed, _totalSupply));
    }

    function _accumulateDepositInterest(address user) internal {
        uint256 interest = balanceOf(user) - _deposited[user];

        _mint(user, interest);
        _deposited[address(this)] = balanceOf(address(this));

        emit InterestCollected(user, interest, block.timestamp);

        depositIndex.updateUser(user);
        depositIndex.updateUser(address(this));
    }

    function _accumulateBorrowingInterest(address user) internal {
        borrowed[user] = getBorrowed(user);
        borrowed[address(this)] = getBorrowed(address(this));

        borrowIndex.updateUser(user);
        borrowIndex.updateUser(address(this));
    }

    /* ========== OVERRIDDEN FUNCTIONS ========== */

    function renounceOwnership() public virtual override {}

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

    modifier canBorrow() {
        if(address(borrowersRegistry) == address(0)) revert BorrowersRegistryNotConfigured();
        if(!borrowersRegistry.canBorrow(msg.sender)) revert NotAuthorizedToBorrow();
        if(totalSupply() == 0) revert InsufficientPoolFunds();
        _;
        if((totalBorrowed() * 1e18) / totalSupply() > getMaxPoolUtilisationForBorrowing()) revert MaxPoolUtilisationBreached();
    }

    /* ========== EVENTS ========== */

    /**
     * @dev emitted after the user deposits funds
     * @param user the address performing the deposit
     * @param value the amount deposited
     * @param timestamp of the deposit
     **/
    event Deposit(address indexed user, uint256 value, uint256 timestamp);

    /**
     * @dev emitted after the user deposits funds on behalf of other user
     * @param user the address performing the deposit
     * @param _of the address on behalf of which the deposit is being performed
     * @param value the amount deposited
     * @param timestamp of the deposit
     **/
    event DepositOnBehalfOf(address indexed user, address indexed _of, uint256 value, uint256 timestamp);

    /**
     * @dev emitted after the user withdraws funds
     * @param user the address performing the withdrawal
     * @param value the amount withdrawn
     * @param timestamp of the withdrawal
     **/
    event Withdrawal(address indexed user, uint256 value, uint256 timestamp);

    /**
     * @dev emitted after the user borrows funds
     * @param user the address that borrows
     * @param value the amount borrowed
     * @param timestamp time of the borrowing
     **/
    event Borrowing(address indexed user, uint256 value, uint256 timestamp);

    /**
     * @dev emitted after the user repays debt
     * @param user the address that repays debt
     * @param value the amount repaid
     * @param timestamp of the repayment
     **/
    event Repayment(address indexed user, uint256 value, uint256 timestamp);

    /**
     * @dev emitted after accumulating deposit interest
     * @param user the address that the deposit interest is accumulated for
     * @param value the amount that interest is calculated from
     * @param timestamp of the interest accumulation
     **/
    event InterestCollected(address indexed user, uint256 value, uint256 timestamp);

    /**
    * @dev emitted after changing borrowers registry
    * @param registry an address of the newly set borrowers registry
    * @param timestamp of the borrowers registry change
    **/
    event BorrowersRegistryChanged(address indexed registry, uint256 timestamp);

    /**
    * @dev emitted after changing rates calculator
    * @param calculator an address of the newly set rates calculator
    * @param timestamp of the borrowers registry change
    **/
    event RatesCalculatorChanged(address indexed calculator, uint256 timestamp);

    /**
    * @dev emitted after changing pool rewarder
    * @param poolRewarder an address of the newly set pool rewarder
    * @param timestamp of the pool rewarder change
    **/
    event PoolRewarderChanged(address indexed poolRewarder, uint256 timestamp);

    /**
    * @dev emitted after changing vesting distributor
    * @param distributor an address of the newly set distributor
    * @param timestamp of the distributor change
    **/
    event VestingDistributorChanged(address indexed distributor, uint256 timestamp);

    /* ========== ERRORS ========== */

    // Only authorized accounts may borrow
    error NotAuthorizedToBorrow();

    // Borrowers registry is not configured
    error BorrowersRegistryNotConfigured();

    // Pool is frozen
    error PoolFrozen();

    // Not enough funds in the pool.
    error InsufficientPoolFunds();

    // Insufficient pool surplus to cover the requested recover amount
    error InsufficientSurplus();

    // Address (`target`) must be a contract
    // @param target target address that must be a contract
    error NotAContract(address target);

    //  ERC20: Spender cannot be a zero address
    error SpenderZeroAddress();

    //  ERC20: cannot transfer to the zero address
    error TransferToZeroAddress();

    //  ERC20: cannot transfer to the pool address
    error TransferToPoolAddress();

    //  ERC20: transfer amount (`amount`) exceeds balance (`balance`)
    /// @param amount transfer amount
    /// @param balance available balance
    error TransferAmountExceedsBalance(uint256 amount, uint256 balance);

    //  ERC20: requested transfer amount (`requested`) exceeds current allowance (`allowance`)
    /// @param requested requested transfer amount
    /// @param allowance current allowance
    error InsufficientAllowance(uint256 requested, uint256 allowance);

    //  This deposit operation would result in a breach of the totalSupplyCap
    error TotalSupplyCapBreached();

    // The deposit amount must be > 0
    error ZeroDepositAmount();

    // ERC20: cannot mint to the zero address
    error MintToAddressZero();

    // ERC20: burn amount exceeds current pool indexed balance
    error BurnAmountExceedsBalance();

    // ERC20: burn amount exceeds current amount available (including vesting)
    error BurnAmountExceedsAvailableForUser();

    // Trying to repay more than was borrowed
    error RepayingMoreThanWasBorrowed();

    // getMaxPoolUtilisationForBorrowing was breached
    error MaxPoolUtilisationBreached();
}

// SPDX-License-Identifier: BUSL-1.1
// Last deployed from commit: 9f1e1bba11316303810f35a4440e20bc5ad0ef86;
pragma solidity 0.8.17;

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

/**
 * @title VestingDistributor
 * @dev Contract distributing pool's spread among vesting participants.
 */
contract VestingDistributor {

    Pool pool;
    IERC20Metadata poolToken;
    address keeper;
    address pendingKeeper;

    uint256 totalLockedMultiplied;
    address[] public participants;
    mapping(address => uint256) public locked;
    mapping(address => uint256) public withdrawn;
    mapping(address => uint256) public unvestingTime;
    mapping(address => uint256) public unlockTimestamp;
    mapping(address => uint256) public multiplier;
    mapping(uint256 => uint256) rewardAmount;
    mapping(uint256 => mapping(address => bool)) rewardDistributed;
    mapping(uint256 => uint256) numRewardDistributed;

    uint256 lastUpdated;
    uint256 updateInterval = 6 hours;

    uint256 public constant ONE_DAY = 24 * 3600; // 24 hours * 3600 seconds
    uint256 public constant MIN_VESTING_TIME = ONE_DAY; // 1 day * 24 hours * 3600 seconds
    uint256 public constant MAX_VESTING_TIME = 30 * ONE_DAY; // 30 days * 24 hours * 3600 seconds

    modifier onlyPool() {
        require(msg.sender == address(pool), "Unauthorized: onlyPool");
        _;
    }

    modifier onlyKeeper() {
        require(msg.sender == keeper, "Unauthorized: onlyKeeper");
        _;
    }

    modifier onlyPendingKeeper() {
        require(msg.sender == pendingKeeper, "Unauthorized: onlyPendingKeeper");
        _;
    }

    constructor(address poolAddress, address keeperAddress) {
        pool = Pool(poolAddress);
        poolToken = IERC20Metadata(pool.tokenAddress());
        keeper = keeperAddress;
        lastUpdated = block.timestamp;
    }

    function transferKeeper(address keeperAddress) external onlyKeeper {
        pendingKeeper = keeperAddress;
    }

    function acceptKeeper() external onlyPendingKeeper {
        keeper = pendingKeeper;
        pendingKeeper = address(0);
    }

    /**
     * Add vesting participant (msg.sender)
     **/
    function startVesting(uint256 amount, uint256 time) public {
        if (time < MIN_VESTING_TIME || time > MAX_VESTING_TIME) revert InvalidVestingTime();
        if (pool.balanceOf(msg.sender) < amount) revert InsufficientPoolBalance();
        if (locked[msg.sender] > 0 || unvestingTime[msg.sender] > 0) revert AlreadyLocked();

        participants.push(msg.sender);
        locked[msg.sender] = amount;
        unvestingTime[msg.sender] = time;
        multiplier[msg.sender] = getMultiplier(time);

        totalLockedMultiplied += amount * multiplier[msg.sender] / 1e18;
    }

    /**
     * Increase vesting of msg.sender
     **/
    function increaseVesting(uint256 amount) public {
        if (locked[msg.sender] == 0 || unvestingTime[msg.sender] == 0) revert UserNotLocked();
        if (pool.balanceOf(msg.sender) < locked[msg.sender] + amount) revert InsufficientPoolBalance();
        if (unlockTimestamp[msg.sender] > 0) revert TooLate();

        locked[msg.sender] += amount;

        totalLockedMultiplied += amount * multiplier[msg.sender] / 1e18;
    }

    /**
     * Unlock funds - start of unvesting
     **/
    function unlock() public {
        if (locked[msg.sender] == 0 || unvestingTime[msg.sender] == 0) revert UserNotLocked();

        unlockTimestamp[msg.sender] = block.timestamp;
    }

    /**
     * Check how much user can withdraw
     **/
    function availableToWithdraw(address account) public view returns (uint256) {
        if (locked[account] == 0 || unvestingTime[account] == 0) revert UserNotLocked();
        if (unlockTimestamp[account] == 0) revert UserLocked();

        uint256 timeFromUnlock = block.timestamp - unlockTimestamp[account];
        if (timeFromUnlock > unvestingTime[account]) timeFromUnlock = unvestingTime[account];
        uint256 initialUnlock = ONE_DAY * locked[account] / (unvestingTime[account] + ONE_DAY); // 1D / vesting days * locked amount

        return initialUnlock + timeFromUnlock * (locked[account] - initialUnlock) / unvestingTime[account];
    }

    /**
     * Gets pool's spread and distributes among vesting participants.
     * @dev _totalLoans total value of loans
     * @dev _totalDeposits total value of deposits
     **/
    //TODO: run periodically by bots
    function distributeRewards(uint256 fromIndex, uint256 toIndex) public onlyKeeper {
        if (block.timestamp < lastUpdated + updateInterval) revert DistributeTooEarly();

        (fromIndex, toIndex) = fromIndex < toIndex ? (fromIndex, toIndex) : (toIndex, fromIndex);
        toIndex = toIndex < participants.length ? toIndex : participants.length - 1;

        if (rewardAmount[lastUpdated] == 0) {
            rewardAmount[lastUpdated] = pool.balanceOf(address(this));
        }
        uint256 rewards = rewardAmount[lastUpdated];

        for (uint256 i = fromIndex; i <= toIndex; i++) {
            address participant = participants[i];
            if (rewardDistributed[lastUpdated][participant]) {
                continue;
            }

            //TODO: right now we distribute rewards even when someone start withdrawing. The rewards should depend on the amount which is still locked.
            uint256 participantReward = rewards * (locked[participant] - withdrawn[participant]) * multiplier[participant] / 1e18 / totalLockedMultiplied;

            pool.transfer(participant, participantReward);

            rewardDistributed[lastUpdated][participant] = true;
            ++numRewardDistributed[lastUpdated];
            if (numRewardDistributed[lastUpdated] == participants.length) {
                lastUpdated = block.timestamp;
            }
        }
    }

    //TODO: run periodically by bots
    function updateParticipants(uint256 fromIndex, uint256 toIndex) public onlyKeeper {
        (fromIndex, toIndex) = fromIndex < toIndex ? (fromIndex, toIndex) : (toIndex, fromIndex);
        toIndex = toIndex < participants.length ? toIndex : participants.length - 1;
        for (uint256 i = fromIndex; i <= toIndex;) {
            address participant = participants[i];
            if (unlockTimestamp[participant] > 0 && (block.timestamp - unlockTimestamp[participant]) > unvestingTime[participant]) {
                totalLockedMultiplied -= (locked[participant] - withdrawn[participant]) * multiplier[participant] / 1e18;

                unvestingTime[participant] = 0;
                locked[participant] = 0;
                unlockTimestamp[participant] = 0;
                withdrawn[participant] = 0;
                multiplier[participant] = 0;

                participants[i] = participants[participants.length - 1];
                participants.pop();
                --toIndex;
            } else {
                ++i;
            }
        }
    }

    function updateWithdrawn(address account, uint256 amount) public onlyPool {
        withdrawn[account] += amount;
        if (withdrawn[account] > locked[account]) {
            revert WithdrawMoreThanLocked();
        }
        totalLockedMultiplied -= amount * multiplier[account] / 1e18;
    }

    function getMultiplier(uint256 time) public pure returns (uint256){
        if (time >= 30 * ONE_DAY) return 2e18; // min. 30 days
        if (time >= 29 * ONE_DAY) return 1.99e18; // min. 29 days
        if (time >= 28 * ONE_DAY) return 1.98e18; // min. 28 days
        if (time >= 27 * ONE_DAY) return 1.97e18; // min. 27 days
        if (time >= 26 * ONE_DAY) return 1.96e18; // min. 26 days
        if (time >= 25 * ONE_DAY) return 1.948e18; // min. 25 days
        if (time >= 24 * ONE_DAY) return 1.936e18; // min. 24 days
        if (time >= 23 * ONE_DAY) return 1.924e18; // min. 23 days
        if (time >= 22 * ONE_DAY) return 1.912e18; // min. 22 days
        if (time >= 21 * ONE_DAY) return 1.9e18; // min. 21 days
        if (time >= 20 * ONE_DAY) return 1.885e18; // min. 20 days
        if (time >= 19 * ONE_DAY) return 1.871e18; // min. 19 days
        if (time >= 18 * ONE_DAY) return 1.856e18; // min. 18 days
        if (time >= 17 * ONE_DAY) return 1.841e18; // min. 17 days
        if (time >= 16 * ONE_DAY) return 1.824e18; // min. 16 days
        if (time >= 15 * ONE_DAY) return 1.806e18; // min. 15 days
        if (time >= 14 * ONE_DAY) return 1.788e18; // min. 14 days
        if (time >= 13 * ONE_DAY) return 1.768e18; // min. 13 days
        if (time >= 12 * ONE_DAY) return 1.746e18; // min. 12 days
        if (time >= 11 * ONE_DAY) return 1.723e18; // min. 11 days
        if (time >= 10 * ONE_DAY) return 1.698e18; // min. 10 days
        if (time >= 9 * ONE_DAY) return 1.67e18; // min. 9 days
        if (time >= 8 * ONE_DAY) return 1.64e18; // min. 8 days
        if (time >= 7 * ONE_DAY) return 1.605e18; // min. 7 days
        if (time >= 6 * ONE_DAY) return 1.566e18; // min. 6 days
        if (time >= 5 * ONE_DAY) return 1.521e18; // min. 5 days
        if (time >= 4 * ONE_DAY) return 1.468e18; // min. 4 days
        if (time >= 3 * ONE_DAY) return 1.4e18; // min. 3 days
        if (time >= 2 * ONE_DAY) return 1.32e18; // min. 2 days
        if (time >= 1 * ONE_DAY) return 1.2e18; // min. 1 day

        return 1;
    }


    // Trying to distribute before the update interval has been reached
    error DistributeTooEarly();

    // Already participates in vesting
    error AlreadyLocked();

    // Vesting time is out of range
    error InvalidVestingTime();

    // Insufficient user balance of pool's tokens
    error InsufficientPoolBalance();

    // User not locked
    error UserNotLocked();

    // User funds are locked
    error UserLocked();

    // Too late
    error TooLate();

    // Withdraw amount is more than locked
    error WithdrawMoreThanLocked();
}

// SPDX-License-Identifier: BUSL-1.1
// Last deployed from commit: 5bae95ca244e96444fe80078195944f6637e72d8;
pragma solidity 0.8.17;

import "./Pool.sol";
import "./interfaces/IWrappedNativeToken.sol";

/**
 * @title Pool
 * @dev Contract allowing user to deposit to and borrow from a single pot
 * Depositors are rewarded with the interest rates collected from borrowers.
 * Rates are compounded every second and getters always return the current deposit and borrowing balance.
 * The interest rates calculation is delegated to the external calculator contract.
 */
contract WrappedNativeTokenPool is Pool {
    using TransferHelper for address payable;
    using TransferHelper for address;

    /**
     * Wraps and deposits amount attached to the transaction
     **/
    function depositNativeToken() public payable virtual {
        if(msg.value == 0) revert ZeroDepositAmount();

        _accumulateDepositInterest(msg.sender);

        if(totalSupplyCap != 0){
            if(_deposited[address(this)] + msg.value > totalSupplyCap) revert TotalSupplyCapBreached();
        }

        IWrappedNativeToken(tokenAddress).deposit{value : msg.value}();

        _mint(msg.sender, msg.value);
        _deposited[address(this)] += msg.value;
        _updateRates();

        if (address(poolRewarder) != address(0)) {
            poolRewarder.stakeFor(msg.value, msg.sender);
        }

        emit Deposit(msg.sender, msg.value, block.timestamp);
    }

    /**
     * Unwraps and withdraws selected amount from the user deposits
     * @dev _amount the amount to be withdrawn
     **/
    function withdrawNativeToken(uint256 _amount) external nonReentrant {
        if(_amount > IERC20(tokenAddress).balanceOf(address(this))) revert InsufficientPoolFunds();

        _accumulateDepositInterest(msg.sender);

        if(_amount > _deposited[address(this)]) revert BurnAmountExceedsBalance();
        // verified in "require" above
        unchecked {
            _deposited[address(this)] -= _amount;
        }
        _burn(msg.sender, _amount);

        _updateRates();

        IWrappedNativeToken(tokenAddress).withdraw(_amount);
        payable(msg.sender).safeTransferETH(_amount);

        if (address(poolRewarder) != address(0)) {
            poolRewarder.withdrawFor(_amount, msg.sender);
        }

        emit Withdrawal(msg.sender, _amount, block.timestamp);
    }

    /* ========== RECEIVE AVAX FUNCTION ========== */
    //needed for withdrawNativeToken
    receive() external payable {}
}

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

Contract Security Audit

Contract ABI

API
[{"inputs":[],"name":"BorrowersRegistryNotConfigured","type":"error"},{"inputs":[],"name":"BurnAmountExceedsAvailableForUser","type":"error"},{"inputs":[],"name":"BurnAmountExceedsBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"requested","type":"uint256"},{"internalType":"uint256","name":"allowance","type":"uint256"}],"name":"InsufficientAllowance","type":"error"},{"inputs":[],"name":"InsufficientPoolFunds","type":"error"},{"inputs":[],"name":"InsufficientSurplus","type":"error"},{"inputs":[],"name":"MaxPoolUtilisationBreached","type":"error"},{"inputs":[],"name":"MintToAddressZero","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"NotAContract","type":"error"},{"inputs":[],"name":"NotAuthorizedToBorrow","type":"error"},{"inputs":[],"name":"PoolFrozen","type":"error"},{"inputs":[],"name":"RepayingMoreThanWasBorrowed","type":"error"},{"inputs":[],"name":"SpenderZeroAddress","type":"error"},{"inputs":[],"name":"TotalSupplyCapBreached","type":"error"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"balance","type":"uint256"}],"name":"TransferAmountExceedsBalance","type":"error"},{"inputs":[],"name":"TransferToPoolAddress","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"ZeroDepositAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"registry","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"BorrowersRegistryChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"Borrowing","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"_of","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"DepositOnBehalfOf","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"InterestCollected","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"poolRewarder","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"PoolRewarderChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"calculator","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"RatesCalculatorChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"Repayment","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"distributor","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"VestingDistributorChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"Withdrawal","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"borrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"borrowIndex","outputs":[{"internalType":"contract IIndex","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"borrowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"borrowersRegistry","outputs":[{"internalType":"contract IBorrowersRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"checkRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"decimals","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"depositIndex","outputs":[{"internalType":"contract IIndex","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"depositNativeToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_of","type":"address"}],"name":"depositOnBehalf","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getBorrowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBorrowingRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDepositRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFullPoolStatus","outputs":[{"internalType":"uint256[5]","name":"","type":"uint256[5]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMaxPoolUtilisationForBorrowing","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IRatesCalculator","name":"ratesCalculator_","type":"address"},{"internalType":"contract IBorrowersRegistry","name":"borrowersRegistry_","type":"address"},{"internalType":"contract IIndex","name":"depositIndex_","type":"address"},{"internalType":"contract IIndex","name":"borrowIndex_","type":"address"},{"internalType":"address payable","name":"tokenAddress_","type":"address"},{"internalType":"contract IPoolRewarder","name":"poolRewarder_","type":"address"},{"internalType":"uint256","name":"_totalSupplyCap","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"_name","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolRewarder","outputs":[{"internalType":"contract IPoolRewarder","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ratesCalculator","outputs":[{"internalType":"contract IRatesCalculator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"account","type":"address"}],"name":"recoverSurplus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"repay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IBorrowersRegistry","name":"borrowersRegistry_","type":"address"}],"name":"setBorrowersRegistry","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IPoolRewarder","name":"_poolRewarder","type":"address"}],"name":"setPoolRewarder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IRatesCalculator","name":"ratesCalculator_","type":"address"}],"name":"setRatesCalculator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newTotalSupplyCap","type":"uint256"}],"name":"setTotalSupplyCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_distributor","type":"address"}],"name":"setVestingDistributor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"_symbol","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"tokenAddress","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalBorrowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupplyCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vestingDistributor","outputs":[{"internalType":"contract VestingDistributor","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawNativeToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

608060405234801561001057600080fd5b506135db806100206000396000f3fe6080604052600436106102765760003560e01c806370a082311161014f578063aa5af0fd116100c1578063d06dca891161007a578063d06dca891461076f578063dd62ed3e1461078f578063ee61bd6e146107d5578063f2fde38b146107f5578063f36b242514610815578063fc68f6611461082a57600080fd5b8063aa5af0fd146106c2578063b6b55f25146106e2578063b75c42bd14610702578063b790634e14610724578063bb102aea14610739578063c5ebeaec1461074f57600080fd5b80638c1a3811116101135780638c1a3811146105f55780638da5cb5b1461061557806395d89b41146106335780639d76ea5814610662578063a457c2d714610682578063a9059cbb146106a257600080fd5b806370a082311461058157806370d4cea0146105a1578063715018a6146105c157806379433d8b146105cd5780637b898939146105d557600080fd5b80632aeaa291116101e857806339509351116101ac57806339509351146104d15780634c19386c146104f15780636011163e1461050657806361215aa8146105265780636ca6d5d0146105415780636cf55ea21461056157600080fd5b80632aeaa291146104405780632e1a7d4d14610455578063313ce5671461047557806331d05b1114610491578063371fd8e6146104b157600080fd5b8063095ea7b31161023a578063095ea7b31461037b5780631457db34146103ab5780631460e390146103cb57806317e0f252146103eb57806318160ddd1461040b57806323b872dd1461042057600080fd5b80630572b0cc1461028257806306fdde03146102995780630790ef9a146102e857806307bbebdd146103085780630941cb3d1461034057600080fd5b3661027d57005b600080fd5b34801561028e57600080fd5b5061029761084a565b005b3480156102a557600080fd5b50604080518082019091526014815273088cad8e8c2a0e4d2dacaaee4c2e0e0cac88aa8960631b60208201525b6040516102df91906131d8565b60405180910390f35b3480156102f457600080fd5b50610297610303366004613220565b6108a9565b34801561031457600080fd5b5060a154610328906001600160a01b031681565b6040516001600160a01b0390911681526020016102df565b34801561034c57600080fd5b5061036d61035b366004613250565b609a6020526000908152604090205481565b6040519081526020016102df565b34801561038757600080fd5b5061039b61039636600461326d565b6109f1565b60405190151581526020016102df565b3480156103b757600080fd5b506102976103c6366004613250565b610a7f565b3480156103d757600080fd5b506102976103e6366004613299565b610b4b565b3480156103f757600080fd5b50610297610406366004613326565b610db7565b34801561041757600080fd5b5061036d611001565b34801561042c57600080fd5b5061039b61043b36600461333f565b611011565b34801561044c57600080fd5b5061036d61133d565b34801561046157600080fd5b50610297610470366004613326565b6113a9565b34801561048157600080fd5b50604051601281526020016102df565b34801561049d57600080fd5b506102976104ac366004613326565b6114e3565b3480156104bd57600080fd5b506102976104cc366004613326565b611512565b3480156104dd57600080fd5b5061039b6104ec36600461326d565b611604565b3480156104fd57600080fd5b5061036d6116c3565b34801561051257600080fd5b5061036d610521366004613250565b6116ca565b34801561053257600080fd5b50670c7d713b49da000061036d565b34801561054d57600080fd5b50609d54610328906001600160a01b031681565b34801561056d57600080fd5b5061029761057c366004613220565b611755565b34801561058d57600080fd5b5061036d61059c366004613250565b611a09565b3480156105ad57600080fd5b506102976105bc366004613250565b611a57565b34801561029757600080fd5b610297611b32565b3480156105e157600080fd5b50609e54610328906001600160a01b031681565b34801561060157600080fd5b50610297610610366004613250565b611cf2565b34801561062157600080fd5b506033546001600160a01b0316610328565b34801561063f57600080fd5b50604080518082019091526006815265088a0ae8aa8960d31b60208201526102d2565b34801561066e57600080fd5b5060a054610328906001600160a01b031681565b34801561068e57600080fd5b5061039b61069d36600461326d565b611db3565b3480156106ae57600080fd5b5061039b6106bd36600461326d565b611e9f565b3480156106ce57600080fd5b50609f54610328906001600160a01b031681565b3480156106ee57600080fd5b506102976106fd366004613326565b612111565b34801561070e57600080fd5b5061071761211e565b6040516102df9190613380565b34801561073057600080fd5b5061036d612175565b34801561074557600080fd5b5061036d60975481565b34801561075b57600080fd5b5061029761076a366004613326565b6121c2565b34801561077b57600080fd5b50609c54610328906001600160a01b031681565b34801561079b57600080fd5b5061036d6107aa3660046133b1565b6001600160a01b03918216600090815260986020908152604080832093909416825291909152205490565b3480156107e157600080fd5b50609b54610328906001600160a01b031681565b34801561080157600080fd5b50610297610810366004613250565b612446565b34801561082157600080fd5b5061036d6124de565b34801561083657600080fd5b50610297610845366004613250565b6124fa565b609d546040516311305c1f60e11b81523360048201526001600160a01b0390911690632260b83e90602401600060405180830381600087803b15801561088f57600080fd5b505af11580156108a3573d6000803e3d6000fd5b50505050565b6033546001600160a01b031633146108dc5760405162461bcd60e51b81526004016108d3906133df565b60405180910390fd5b6002606554036108fe5760405162461bcd60e51b81526004016108d390613414565b600260655560a0546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa15801561094c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610970919061344b565b9050600061097c611001565b6109846116c3565b61098e908461347a565b610998919061348d565b9050818411156109bb576040516316d5c93f60e21b815260040160405180910390fd5b838110156109dc576040516394290ab960e01b815260040160405180910390fd5b6109e683856125a5565b505060016065555050565b60006001600160a01b038316610a1a57604051633d6601c760e11b815260040160405180910390fd5b3360008181526098602090815260408083206001600160a01b03881680855290835292819020869055518581529192917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a35060015b92915050565b6033546001600160a01b03163314610aa95760405162461bcd60e51b81526004016108d3906133df565b6001600160a01b0381163b158015610ac957506001600160a01b03811615155b15610af657609d546040516322a2d07b60e21b81526001600160a01b0390911660048201526024016108d3565b609d80546001600160a01b0319166001600160a01b0383169081179091556040514281527f85796821ee1d670b0fdb986f256b5c1a29b9019038831c7f09df2061879cf9e5906020015b60405180910390a250565b600054610100900460ff16610b665760005460ff1615610b6a565b303b155b610bcd5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016108d3565b600054610100900460ff16158015610bef576000805461ffff19166101011790555b6001600160a01b0388163b15158015610c1157506001600160a01b0387163b15155b8015610c2657506001600160a01b0386163b15155b8015610c3b57506001600160a01b0385163b15155b8015610c6157506001600160a01b0383163b151580610c6157506001600160a01b038316155b610ca45760405162461bcd60e51b815260206004820152601460248201527357726f6e6720696e697420617267756d656e747360601b60448201526064016108d3565b609c80546001600160a01b03199081166001600160a01b038a811691909117909255609b805482168b8416179055609e80548216898416179055609f80548216888416179055609d8054821686841617905560a08054909116918616918217905560978390556040805163313ce56760e01b8152905163313ce567916004818101926020929091908290030181865afa158015610d45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d6991906134a0565b60a160146101000a81548160ff021916908360ff160217905550610d8b6125c0565b610d936125ef565b610d9b61261e565b8015610dad576000805461ff00191690555b5050505050505050565b600260655403610dd95760405162461bcd60e51b81526004016108d390613414565b600260655560a0546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015610e26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e4a919061344b565b811115610e6a576040516316d5c93f60e21b815260040160405180910390fd5b610e7333612803565b30600090815260996020526040902054811115610ea357604051630bba337f60e11b815260040160405180910390fd5b30600090815260996020526040902080548290039055610ec33382612934565b610ecb61261e565b60a054604051632e1a7d4d60e01b8152600481018390526001600160a01b0390911690632e1a7d4d90602401600060405180830381600087803b158015610f1157600080fd5b505af1158015610f25573d6000803e3d6000fd5b50610f3692503391508390506129f1565b609d546001600160a01b031615610fbe57609d54604051630d5dbdb360e21b8152600481018390523360248201526001600160a01b0390911690633576f6cc906044016020604051808303816000875af1158015610f98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fbc919061344b565b505b6040805182815242602082015233917fdf273cb619d95419a9cd0ec88123a0538c85064229baa6363788f743fff90deb91015b60405180910390a2506001606555565b600061100c30611a09565b905090565b60006002606554036110355760405162461bcd60e51b81526004016108d390613414565b60026065556001600160a01b03841660009081526098602090815260408083203384529091529020548211156110ae576001600160a01b03841660009081526098602090815260408083203384529091529081902054905163054365bb60e31b81526108d3918491600401918252602082015260400190565b6001600160a01b0383166110d557604051633a954ecd60e21b815260040160405180910390fd5b306001600160a01b038416036110fe5760405163ed728e5760e01b815260040160405180910390fd5b61110784612803565b60008061111386612ad0565b9150915080841115611142576040516350d2479d60e11b815260048101859052602481018290526044016108d3565b61114d868584612c17565b6001600160a01b0386166000908152609960205260408120805486929061117590849061348d565b90915550506001600160a01b0386166000908152609860209081526040808320338452909152812080548692906111ad90849061348d565b909155506111bc905085612803565b6001600160a01b038516600090815260996020526040812080548692906111e490849061347a565b9091555050609d546001600160a01b03161580159061120257508315155b156112f057609d54604051630d5dbdb360e21b8152600481018690526001600160a01b0388811660248301526000921690633576f6cc906044016020604051808303816000875af115801561125b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127f919061344b565b905080156112ee57609d546040516328ba35d960e11b8152600481018390526001600160a01b038881166024830152909116906351746bb290604401600060405180830381600087803b1580156112d557600080fd5b505af11580156112e9573d6000803e3d6000fd5b505050505b505b846001600160a01b0316866001600160a01b03166000805160206135868339815191528660405161132391815260200190565b60405180910390a360019250505060016065559392505050565b609d546040516246613160e11b81523360048201526000916001600160a01b031690628cc262906024015b602060405180830381865afa158015611385573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061100c919061344b565b6002606554036113cb5760405162461bcd60e51b81526004016108d390613414565b60026065556113d933612803565b336000908152609960205260409020546113f4908290612cd1565b60a0546040516370a0823160e01b81523060048201529192506001600160a01b0316906370a0823190602401602060405180830381865afa15801561143d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611461919061344b565b811115611481576040516316d5c93f60e21b815260040160405180910390fd5b306000908152609960205260409020548111156114b157604051630bba337f60e11b815260040160405180910390fd5b306000908152609960205260409020805482900390556114d13382612934565b6114d961261e565b610f3633826125a5565b6033546001600160a01b0316331461150d5760405162461bcd60e51b81526004016108d3906133df565b609755565b6002606554036115345760405162461bcd60e51b81526004016108d390613414565b600260655561154233612ce9565b336000908152609a602052604090205481111561157257604051630dcad43360e11b815260040160405180910390fd5b61157c3382612de7565b336000908152609a60205260408120805483929061159b90849061348d565b9091555050306000908152609a6020526040812080548392906115bf90849061348d565b909155506115cd905061261e565b6040805182815242602082015233917f24fcca58a997b1b2eff6db8107e860458544c09ddd3693b3b779e1df6c0d6c5d9101610ff1565b60006001600160a01b03831661162d57604051633d6601c760e11b815260040160405180910390fd5b3360009081526098602090815260408083206001600160a01b038716845290915281205461165c90849061347a565b3360008181526098602090815260408083206001600160a01b038a16808552908352928190208590555184815293945090927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a35060019392505050565b600061100c305b609f546001600160a01b038281166000818152609a602052604080822054905163966da88960e01b81526004810191909152602481019290925292919091169063966da889906044015b602060405180830381865afa158015611731573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a79919061344b565b6002606554036117775760405162461bcd60e51b81526004016108d390613414565b6002606555600082900361179e5760405163078e1d8560e01b815260040160405180910390fd5b6001600160a01b0381166117e35760405162461bcd60e51b815260206004820152600c60248201526b41646472657373207a65726f60a01b60448201526064016108d3565b306001600160a01b0382160361183b5760405162461bcd60e51b815260206004820181905260248201527f43616e6e6f74206465706f736974206f6e20626568616c66206f6620706f6f6c60448201526064016108d3565b60a0546040516370a0823160e01b81523360048201526118b29184916001600160a01b03909116906370a0823190602401602060405180830381865afa158015611889573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118ad919061344b565b612cd1565b91506118bd81612803565b6097541561190257609754306000908152609960205260409020546118e390849061347a565b111561190257604051633f27d61760e01b815260040160405180910390fd5b61190c3383612de7565b6119168183612dff565b306000908152609960205260408120805484929061193590849061347a565b90915550611943905061261e565b609d546001600160a01b0316156119bb57609d546040516328ba35d960e11b8152600481018490526001600160a01b038381166024830152909116906351746bb290604401600060405180830381600087803b1580156119a257600080fd5b505af11580156119b6573d6000803e3d6000fd5b505050505b604080518381524260208201526001600160a01b0383169133917fef0ada5ca19bede6a40b575865a6ce451938d26835b7215e6a5e03bb2c439212910160405180910390a350506001606555565b609e546001600160a01b0382811660008181526099602052604080822054905163966da88960e01b81526004810191909152602481019290925292919091169063966da88990604401611714565b6033546001600160a01b03163314611a815760405162461bcd60e51b81526004016108d3906133df565b6001600160a01b0381163b158015611aa157506001600160a01b03811615155b15611aca576040516322a2d07b60e21b81526001600160a01b03821660048201526024016108d3565b609b80546001600160a01b0319166001600160a01b03831690811790915515611af557611af561261e565b806001600160a01b03167fef1b7e9216e08b283cc613824ccb26ea505227777839a4f3c6810d64594e018242604051610b4091815260200190565b565b34600003611b535760405163078e1d8560e01b815260040160405180910390fd5b611b5c33612803565b60975415611ba15760975430600090815260996020526040902054611b8290349061347a565b1115611ba157604051633f27d61760e01b815260040160405180910390fd5b60a060009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015611bf157600080fd5b505af1158015611c05573d6000803e3d6000fd5b5050505050611c143334612dff565b3060009081526099602052604081208054349290611c3390849061347a565b90915550611c41905061261e565b609d546001600160a01b031615611cb657609d546040516328ba35d960e11b81523460048201523360248201526001600160a01b03909116906351746bb290604401600060405180830381600087803b158015611c9d57600080fd5b505af1158015611cb1573d6000803e3d6000fd5b505050505b6040805134815242602082015233917f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a15910160405180910390a2565b6033546001600160a01b03163314611d1c5760405162461bcd60e51b81526004016108d3906133df565b6001600160a01b0381163b158015611d3c57506001600160a01b03811615155b15611d65576040516322a2d07b60e21b81526001600160a01b03821660048201526024016108d3565b60a180546001600160a01b0319166001600160a01b0383169081179091556040514281527f8e6481d1924c9bb8cdfd9d6140f3e5570c34c6c580d915144728bbbf394eed0a90602001610b40565b60006001600160a01b038316611ddc57604051633d6601c760e11b815260040160405180910390fd5b3360009081526098602090815260408083206001600160a01b038716845290915290205482811015611e2b5760405163054365bb60e31b815260048101849052602481018290526044016108d3565b6000611e37848361348d565b3360008181526098602090815260408083206001600160a01b038b16808552908352928190208590555184815293945090927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3506001949350505050565b6000600260655403611ec35760405162461bcd60e51b81526004016108d390613414565b60026065556001600160a01b038316611eef57604051633a954ecd60e21b815260040160405180910390fd5b306001600160a01b03841603611f185760405163ed728e5760e01b815260040160405180910390fd5b33611f2281612803565b600080611f2e83612ad0565b9150915080851115611f5d576040516350d2479d60e11b815260048101869052602481018290526044016108d3565b611f68838684612c17565b6001600160a01b038316600090815260996020526040902080548690039055611f9086612803565b6001600160a01b03861660009081526099602052604081208054879290611fb890849061347a565b9091555050609d546001600160a01b031615801590611fd657508415155b156120c457609d54604051630d5dbdb360e21b8152600481018790526001600160a01b0385811660248301526000921690633576f6cc906044016020604051808303816000875af115801561202f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612053919061344b565b905080156120c257609d546040516328ba35d960e11b8152600481018390526001600160a01b038981166024830152909116906351746bb290604401600060405180830381600087803b1580156120a957600080fd5b505af11580156120bd573d6000803e3d6000fd5b505050505b505b856001600160a01b0316836001600160a01b0316600080516020613586833981519152876040516120f791815260200190565b60405180910390a360019350505050600160655592915050565b61211b8133611755565b50565b612126613196565b6040518060a00160405280612139611001565b8152602001612146612175565b81526020016121536124de565b81526020016121606116c3565b8152602001670c7d713b49da00009052919050565b609b546000906001600160a01b0316637cd083316121916116c3565b612199611001565b6040516001600160e01b031960e085901b16815260048101929092526024820152604401611368565b609c546001600160a01b03166121eb57604051631c038dab60e21b815260040160405180910390fd5b609c5460405163039ff21960e21b81523360048201526001600160a01b0390911690630e7fc86490602401602060405180830381865afa158015612233573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061225791906134c3565b61227457604051637582fa9b60e11b815260040160405180910390fd5b61227c611001565b60000361229c576040516316d5c93f60e21b815260040160405180910390fd5b6002606554036122be5760405162461bcd60e51b81526004016108d390613414565b600260655560a0546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa15801561230b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061232f919061344b565b81111561234f576040516316d5c93f60e21b815260040160405180910390fd5b61235833612ce9565b336000908152609a60205260408120805483929061237790849061347a565b9091555050306000908152609a60205260408120805483929061239b90849061347a565b909155506123ab905033826125a5565b6123b361261e565b6040805182815242602082015233917fd6b37be10b58108f696d9ed067fedad0bff7cb417ef4c28d2f8a25d6d83c98d5910160405180910390a26001606555670c7d713b49da0000612403611001565b61240b6116c3565b61241d90670de0b6b3a76400006134e5565b61242791906134fc565b111561211b576040516372b9ce3f60e11b815260040160405180910390fd5b6033546001600160a01b031633146124705760405162461bcd60e51b81526004016108d3906133df565b6001600160a01b0381166124d55760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016108d3565b61211b81612e86565b609b546000906001600160a01b031663df841eec6121916116c3565b6033546001600160a01b031633146125245760405162461bcd60e51b81526004016108d3906133df565b6001600160a01b0381163b612557576040516322a2d07b60e21b81526001600160a01b03821660048201526024016108d3565b609c80546001600160a01b0319166001600160a01b0383169081179091556040514281527f04dce7d074f7e287a2e6e3516c802271d58d5c14e0dede83a49719eb6b92046990602001610b40565b60a0546125bc906001600160a01b03168383612ed8565b5050565b600054610100900460ff166125e75760405162461bcd60e51b81526004016108d39061351e565b611b30613002565b600054610100900460ff166126165760405162461bcd60e51b81526004016108d39061351e565b611b30613032565b60006126286116c3565b90506000612634611001565b609b549091506001600160a01b03166126605760405163fd4851e960e01b815260040160405180910390fd5b609e54609b54604051637cd0833160e01b815260048101859052602481018490526001600160a01b03928316926334fcf437921690637cd0833190604401602060405180830381865afa1580156126bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126df919061344b565b6040518263ffffffff1660e01b81526004016126fd91815260200190565b600060405180830381600087803b15801561271757600080fd5b505af115801561272b573d6000803e3d6000fd5b5050609f54609b546040516337e107bb60e21b815260048101879052602481018690526001600160a01b0392831694506334fcf437935091169063df841eec90604401602060405180830381865afa15801561278b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127af919061344b565b6040518263ffffffff1660e01b81526004016127cd91815260200190565b600060405180830381600087803b1580156127e757600080fd5b505af11580156127fb573d6000803e3d6000fd5b505050505050565b6001600160a01b03811660009081526099602052604081205461282583611a09565b61282f919061348d565b905061283b8282612dff565b61284430611a09565b306000908152609960205260409081902091909155516001600160a01b038316907f9bbd517758fbae61197f1c1c04c8614064e89512dbaf4350dcdf76fcaa5e21619061289d9084904290918252602082015260400190565b60405180910390a2609e54604051637681d99b60e11b81526001600160a01b0384811660048301529091169063ed03b33690602401600060405180830381600087803b1580156128ec57600080fd5b505af1158015612900573d6000803e3d6000fd5b5050609e54604051637681d99b60e11b81523060048201526001600160a01b03909116925063ed03b33691506024016127cd565b6001600160a01b03821660009081526099602052604090205481111561296d57604051630bba337f60e11b815260040160405180910390fd5b60008061297984612ad0565b915091508083111561299e5760405163a06a83a160e01b815260040160405180910390fd5b6129a9848484612c17565b6001600160a01b03841660008181526099602090815260408083208054889003905551868152919291600080516020613586833981519152910160405180910390a350505050565b604080516000808252602082019092526001600160a01b038416908390604051612a1b9190613569565b60006040518083038185875af1925050503d8060008114612a58576040519150601f19603f3d011682016040523d82523d6000602084013e612a5d565b606091505b5050905080612acb5760405162461bcd60e51b815260206004820152603460248201527f5472616e7366657248656c7065723a3a736166655472616e736665724554483a60448201527308115512081d1c985b9cd9995c8819985a5b195960621b60648201526084016108d3565b505050565b60a15460009081906001600160a01b031615612bf85760a15460405163cbf9fe5f60e01b81526001600160a01b0385811660048301529091169063cbf9fe5f90602401602060405180830381865afa158015612b30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b54919061344b565b60a15460405163512edc6760e11b81526001600160a01b03868116600483015292945091169063a25db8ce90602401602060405180830381865afa158015612ba0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bc4919061344b565b612bce908361348d565b6001600160a01b038416600090815260996020526040902054612bf1919061348d565b9050915091565b506001600160a01b038216600090815260996020526040902054915091565b6001600160a01b038316600090815260996020526040812054612c3b90839061348d565b90508083118015612c56575060a1546001600160a01b031615155b156108a35760a1546001600160a01b03166349c1de3f85612c77848761348d565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b158015612cbd57600080fd5b505af1158015610dad573d6000803e3d6000fd5b6000818310612ce05781612ce2565b825b9392505050565b612cf2816116ca565b6001600160a01b0382166000908152609a6020526040902055612d14306116ca565b306000908152609a60205260409081902091909155609f549051637681d99b60e11b81526001600160a01b0383811660048301529091169063ed03b33690602401600060405180830381600087803b158015612d6f57600080fd5b505af1158015612d83573d6000803e3d6000fd5b5050609f54604051637681d99b60e11b81523060048201526001600160a01b03909116925063ed03b3369150602401600060405180830381600087803b158015612dcc57600080fd5b505af1158015612de0573d6000803e3d6000fd5b5050505050565b60a0546125bc906001600160a01b0316833084613060565b6001600160a01b038216612e26576040516346dbfb6d60e11b815260040160405180910390fd5b6001600160a01b03821660009081526099602052604081208054839290612e4e90849061347a565b90915550506040518181526001600160a01b038316906000906000805160206135868339815191529060200160405180910390a35050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1790529151600092839290871691612f349190613569565b6000604051808303816000865af19150503d8060008114612f71576040519150601f19603f3d011682016040523d82523d6000602084013e612f76565b606091505b5091509150818015612fa0575080511580612fa0575080806020019051810190612fa091906134c3565b612de05760405162461bcd60e51b815260206004820152602d60248201527f5472616e7366657248656c7065723a3a736166655472616e736665723a20747260448201526c185b9cd9995c8819985a5b1959609a1b60648201526084016108d3565b600054610100900460ff166130295760405162461bcd60e51b81526004016108d39061351e565b611b3033612e86565b600054610100900460ff166130595760405162461bcd60e51b81526004016108d39061351e565b6001606555565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17905291516000928392908816916130c49190613569565b6000604051808303816000865af19150503d8060008114613101576040519150601f19603f3d011682016040523d82523d6000602084013e613106565b606091505b509150915081801561313057508051158061313057508080602001905181019061313091906134c3565b6127fb5760405162461bcd60e51b815260206004820152603160248201527f5472616e7366657248656c7065723a3a7472616e7366657246726f6d3a207472604482015270185b9cd9995c919c9bdb4819985a5b1959607a1b60648201526084016108d3565b6040518060a001604052806005906020820280368337509192915050565b60005b838110156131cf5781810151838201526020016131b7565b50506000910152565b60208152600082518060208401526131f78160408501602087016131b4565b601f01601f19169190910160400192915050565b6001600160a01b038116811461211b57600080fd5b6000806040838503121561323357600080fd5b8235915060208301356132458161320b565b809150509250929050565b60006020828403121561326257600080fd5b8135612ce28161320b565b6000806040838503121561328057600080fd5b823561328b8161320b565b946020939093013593505050565b600080600080600080600060e0888a0312156132b457600080fd5b87356132bf8161320b565b965060208801356132cf8161320b565b955060408801356132df8161320b565b945060608801356132ef8161320b565b935060808801356132ff8161320b565b925060a088013561330f8161320b565b8092505060c0880135905092959891949750929550565b60006020828403121561333857600080fd5b5035919050565b60008060006060848603121561335457600080fd5b833561335f8161320b565b9250602084013561336f8161320b565b929592945050506040919091013590565b60a08101818360005b60058110156133a8578151835260209283019290910190600101613389565b50505092915050565b600080604083850312156133c457600080fd5b82356133cf8161320b565b915060208301356132458161320b565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60006020828403121561345d57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115610a7957610a79613464565b81810381811115610a7957610a79613464565b6000602082840312156134b257600080fd5b815160ff81168114612ce257600080fd5b6000602082840312156134d557600080fd5b81518015158114612ce257600080fd5b8082028115828204841417610a7957610a79613464565b60008261351957634e487b7160e01b600052601260045260246000fd5b500490565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6000825161357b8184602087016131b4565b919091019291505056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212207e716a0644aea20b402fd1493aa22ec09cc818ff80c3d347bd47f691670a8c8b64736f6c63430008110033

Deployed Bytecode

0x6080604052600436106102765760003560e01c806370a082311161014f578063aa5af0fd116100c1578063d06dca891161007a578063d06dca891461076f578063dd62ed3e1461078f578063ee61bd6e146107d5578063f2fde38b146107f5578063f36b242514610815578063fc68f6611461082a57600080fd5b8063aa5af0fd146106c2578063b6b55f25146106e2578063b75c42bd14610702578063b790634e14610724578063bb102aea14610739578063c5ebeaec1461074f57600080fd5b80638c1a3811116101135780638c1a3811146105f55780638da5cb5b1461061557806395d89b41146106335780639d76ea5814610662578063a457c2d714610682578063a9059cbb146106a257600080fd5b806370a082311461058157806370d4cea0146105a1578063715018a6146105c157806379433d8b146105cd5780637b898939146105d557600080fd5b80632aeaa291116101e857806339509351116101ac57806339509351146104d15780634c19386c146104f15780636011163e1461050657806361215aa8146105265780636ca6d5d0146105415780636cf55ea21461056157600080fd5b80632aeaa291146104405780632e1a7d4d14610455578063313ce5671461047557806331d05b1114610491578063371fd8e6146104b157600080fd5b8063095ea7b31161023a578063095ea7b31461037b5780631457db34146103ab5780631460e390146103cb57806317e0f252146103eb57806318160ddd1461040b57806323b872dd1461042057600080fd5b80630572b0cc1461028257806306fdde03146102995780630790ef9a146102e857806307bbebdd146103085780630941cb3d1461034057600080fd5b3661027d57005b600080fd5b34801561028e57600080fd5b5061029761084a565b005b3480156102a557600080fd5b50604080518082019091526014815273088cad8e8c2a0e4d2dacaaee4c2e0e0cac88aa8960631b60208201525b6040516102df91906131d8565b60405180910390f35b3480156102f457600080fd5b50610297610303366004613220565b6108a9565b34801561031457600080fd5b5060a154610328906001600160a01b031681565b6040516001600160a01b0390911681526020016102df565b34801561034c57600080fd5b5061036d61035b366004613250565b609a6020526000908152604090205481565b6040519081526020016102df565b34801561038757600080fd5b5061039b61039636600461326d565b6109f1565b60405190151581526020016102df565b3480156103b757600080fd5b506102976103c6366004613250565b610a7f565b3480156103d757600080fd5b506102976103e6366004613299565b610b4b565b3480156103f757600080fd5b50610297610406366004613326565b610db7565b34801561041757600080fd5b5061036d611001565b34801561042c57600080fd5b5061039b61043b36600461333f565b611011565b34801561044c57600080fd5b5061036d61133d565b34801561046157600080fd5b50610297610470366004613326565b6113a9565b34801561048157600080fd5b50604051601281526020016102df565b34801561049d57600080fd5b506102976104ac366004613326565b6114e3565b3480156104bd57600080fd5b506102976104cc366004613326565b611512565b3480156104dd57600080fd5b5061039b6104ec36600461326d565b611604565b3480156104fd57600080fd5b5061036d6116c3565b34801561051257600080fd5b5061036d610521366004613250565b6116ca565b34801561053257600080fd5b50670c7d713b49da000061036d565b34801561054d57600080fd5b50609d54610328906001600160a01b031681565b34801561056d57600080fd5b5061029761057c366004613220565b611755565b34801561058d57600080fd5b5061036d61059c366004613250565b611a09565b3480156105ad57600080fd5b506102976105bc366004613250565b611a57565b34801561029757600080fd5b610297611b32565b3480156105e157600080fd5b50609e54610328906001600160a01b031681565b34801561060157600080fd5b50610297610610366004613250565b611cf2565b34801561062157600080fd5b506033546001600160a01b0316610328565b34801561063f57600080fd5b50604080518082019091526006815265088a0ae8aa8960d31b60208201526102d2565b34801561066e57600080fd5b5060a054610328906001600160a01b031681565b34801561068e57600080fd5b5061039b61069d36600461326d565b611db3565b3480156106ae57600080fd5b5061039b6106bd36600461326d565b611e9f565b3480156106ce57600080fd5b50609f54610328906001600160a01b031681565b3480156106ee57600080fd5b506102976106fd366004613326565b612111565b34801561070e57600080fd5b5061071761211e565b6040516102df9190613380565b34801561073057600080fd5b5061036d612175565b34801561074557600080fd5b5061036d60975481565b34801561075b57600080fd5b5061029761076a366004613326565b6121c2565b34801561077b57600080fd5b50609c54610328906001600160a01b031681565b34801561079b57600080fd5b5061036d6107aa3660046133b1565b6001600160a01b03918216600090815260986020908152604080832093909416825291909152205490565b3480156107e157600080fd5b50609b54610328906001600160a01b031681565b34801561080157600080fd5b50610297610810366004613250565b612446565b34801561082157600080fd5b5061036d6124de565b34801561083657600080fd5b50610297610845366004613250565b6124fa565b609d546040516311305c1f60e11b81523360048201526001600160a01b0390911690632260b83e90602401600060405180830381600087803b15801561088f57600080fd5b505af11580156108a3573d6000803e3d6000fd5b50505050565b6033546001600160a01b031633146108dc5760405162461bcd60e51b81526004016108d3906133df565b60405180910390fd5b6002606554036108fe5760405162461bcd60e51b81526004016108d390613414565b600260655560a0546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa15801561094c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610970919061344b565b9050600061097c611001565b6109846116c3565b61098e908461347a565b610998919061348d565b9050818411156109bb576040516316d5c93f60e21b815260040160405180910390fd5b838110156109dc576040516394290ab960e01b815260040160405180910390fd5b6109e683856125a5565b505060016065555050565b60006001600160a01b038316610a1a57604051633d6601c760e11b815260040160405180910390fd5b3360008181526098602090815260408083206001600160a01b03881680855290835292819020869055518581529192917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a35060015b92915050565b6033546001600160a01b03163314610aa95760405162461bcd60e51b81526004016108d3906133df565b6001600160a01b0381163b158015610ac957506001600160a01b03811615155b15610af657609d546040516322a2d07b60e21b81526001600160a01b0390911660048201526024016108d3565b609d80546001600160a01b0319166001600160a01b0383169081179091556040514281527f85796821ee1d670b0fdb986f256b5c1a29b9019038831c7f09df2061879cf9e5906020015b60405180910390a250565b600054610100900460ff16610b665760005460ff1615610b6a565b303b155b610bcd5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016108d3565b600054610100900460ff16158015610bef576000805461ffff19166101011790555b6001600160a01b0388163b15158015610c1157506001600160a01b0387163b15155b8015610c2657506001600160a01b0386163b15155b8015610c3b57506001600160a01b0385163b15155b8015610c6157506001600160a01b0383163b151580610c6157506001600160a01b038316155b610ca45760405162461bcd60e51b815260206004820152601460248201527357726f6e6720696e697420617267756d656e747360601b60448201526064016108d3565b609c80546001600160a01b03199081166001600160a01b038a811691909117909255609b805482168b8416179055609e80548216898416179055609f80548216888416179055609d8054821686841617905560a08054909116918616918217905560978390556040805163313ce56760e01b8152905163313ce567916004818101926020929091908290030181865afa158015610d45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d6991906134a0565b60a160146101000a81548160ff021916908360ff160217905550610d8b6125c0565b610d936125ef565b610d9b61261e565b8015610dad576000805461ff00191690555b5050505050505050565b600260655403610dd95760405162461bcd60e51b81526004016108d390613414565b600260655560a0546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015610e26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e4a919061344b565b811115610e6a576040516316d5c93f60e21b815260040160405180910390fd5b610e7333612803565b30600090815260996020526040902054811115610ea357604051630bba337f60e11b815260040160405180910390fd5b30600090815260996020526040902080548290039055610ec33382612934565b610ecb61261e565b60a054604051632e1a7d4d60e01b8152600481018390526001600160a01b0390911690632e1a7d4d90602401600060405180830381600087803b158015610f1157600080fd5b505af1158015610f25573d6000803e3d6000fd5b50610f3692503391508390506129f1565b609d546001600160a01b031615610fbe57609d54604051630d5dbdb360e21b8152600481018390523360248201526001600160a01b0390911690633576f6cc906044016020604051808303816000875af1158015610f98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fbc919061344b565b505b6040805182815242602082015233917fdf273cb619d95419a9cd0ec88123a0538c85064229baa6363788f743fff90deb91015b60405180910390a2506001606555565b600061100c30611a09565b905090565b60006002606554036110355760405162461bcd60e51b81526004016108d390613414565b60026065556001600160a01b03841660009081526098602090815260408083203384529091529020548211156110ae576001600160a01b03841660009081526098602090815260408083203384529091529081902054905163054365bb60e31b81526108d3918491600401918252602082015260400190565b6001600160a01b0383166110d557604051633a954ecd60e21b815260040160405180910390fd5b306001600160a01b038416036110fe5760405163ed728e5760e01b815260040160405180910390fd5b61110784612803565b60008061111386612ad0565b9150915080841115611142576040516350d2479d60e11b815260048101859052602481018290526044016108d3565b61114d868584612c17565b6001600160a01b0386166000908152609960205260408120805486929061117590849061348d565b90915550506001600160a01b0386166000908152609860209081526040808320338452909152812080548692906111ad90849061348d565b909155506111bc905085612803565b6001600160a01b038516600090815260996020526040812080548692906111e490849061347a565b9091555050609d546001600160a01b03161580159061120257508315155b156112f057609d54604051630d5dbdb360e21b8152600481018690526001600160a01b0388811660248301526000921690633576f6cc906044016020604051808303816000875af115801561125b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127f919061344b565b905080156112ee57609d546040516328ba35d960e11b8152600481018390526001600160a01b038881166024830152909116906351746bb290604401600060405180830381600087803b1580156112d557600080fd5b505af11580156112e9573d6000803e3d6000fd5b505050505b505b846001600160a01b0316866001600160a01b03166000805160206135868339815191528660405161132391815260200190565b60405180910390a360019250505060016065559392505050565b609d546040516246613160e11b81523360048201526000916001600160a01b031690628cc262906024015b602060405180830381865afa158015611385573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061100c919061344b565b6002606554036113cb5760405162461bcd60e51b81526004016108d390613414565b60026065556113d933612803565b336000908152609960205260409020546113f4908290612cd1565b60a0546040516370a0823160e01b81523060048201529192506001600160a01b0316906370a0823190602401602060405180830381865afa15801561143d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611461919061344b565b811115611481576040516316d5c93f60e21b815260040160405180910390fd5b306000908152609960205260409020548111156114b157604051630bba337f60e11b815260040160405180910390fd5b306000908152609960205260409020805482900390556114d13382612934565b6114d961261e565b610f3633826125a5565b6033546001600160a01b0316331461150d5760405162461bcd60e51b81526004016108d3906133df565b609755565b6002606554036115345760405162461bcd60e51b81526004016108d390613414565b600260655561154233612ce9565b336000908152609a602052604090205481111561157257604051630dcad43360e11b815260040160405180910390fd5b61157c3382612de7565b336000908152609a60205260408120805483929061159b90849061348d565b9091555050306000908152609a6020526040812080548392906115bf90849061348d565b909155506115cd905061261e565b6040805182815242602082015233917f24fcca58a997b1b2eff6db8107e860458544c09ddd3693b3b779e1df6c0d6c5d9101610ff1565b60006001600160a01b03831661162d57604051633d6601c760e11b815260040160405180910390fd5b3360009081526098602090815260408083206001600160a01b038716845290915281205461165c90849061347a565b3360008181526098602090815260408083206001600160a01b038a16808552908352928190208590555184815293945090927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a35060019392505050565b600061100c305b609f546001600160a01b038281166000818152609a602052604080822054905163966da88960e01b81526004810191909152602481019290925292919091169063966da889906044015b602060405180830381865afa158015611731573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a79919061344b565b6002606554036117775760405162461bcd60e51b81526004016108d390613414565b6002606555600082900361179e5760405163078e1d8560e01b815260040160405180910390fd5b6001600160a01b0381166117e35760405162461bcd60e51b815260206004820152600c60248201526b41646472657373207a65726f60a01b60448201526064016108d3565b306001600160a01b0382160361183b5760405162461bcd60e51b815260206004820181905260248201527f43616e6e6f74206465706f736974206f6e20626568616c66206f6620706f6f6c60448201526064016108d3565b60a0546040516370a0823160e01b81523360048201526118b29184916001600160a01b03909116906370a0823190602401602060405180830381865afa158015611889573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118ad919061344b565b612cd1565b91506118bd81612803565b6097541561190257609754306000908152609960205260409020546118e390849061347a565b111561190257604051633f27d61760e01b815260040160405180910390fd5b61190c3383612de7565b6119168183612dff565b306000908152609960205260408120805484929061193590849061347a565b90915550611943905061261e565b609d546001600160a01b0316156119bb57609d546040516328ba35d960e11b8152600481018490526001600160a01b038381166024830152909116906351746bb290604401600060405180830381600087803b1580156119a257600080fd5b505af11580156119b6573d6000803e3d6000fd5b505050505b604080518381524260208201526001600160a01b0383169133917fef0ada5ca19bede6a40b575865a6ce451938d26835b7215e6a5e03bb2c439212910160405180910390a350506001606555565b609e546001600160a01b0382811660008181526099602052604080822054905163966da88960e01b81526004810191909152602481019290925292919091169063966da88990604401611714565b6033546001600160a01b03163314611a815760405162461bcd60e51b81526004016108d3906133df565b6001600160a01b0381163b158015611aa157506001600160a01b03811615155b15611aca576040516322a2d07b60e21b81526001600160a01b03821660048201526024016108d3565b609b80546001600160a01b0319166001600160a01b03831690811790915515611af557611af561261e565b806001600160a01b03167fef1b7e9216e08b283cc613824ccb26ea505227777839a4f3c6810d64594e018242604051610b4091815260200190565b565b34600003611b535760405163078e1d8560e01b815260040160405180910390fd5b611b5c33612803565b60975415611ba15760975430600090815260996020526040902054611b8290349061347a565b1115611ba157604051633f27d61760e01b815260040160405180910390fd5b60a060009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015611bf157600080fd5b505af1158015611c05573d6000803e3d6000fd5b5050505050611c143334612dff565b3060009081526099602052604081208054349290611c3390849061347a565b90915550611c41905061261e565b609d546001600160a01b031615611cb657609d546040516328ba35d960e11b81523460048201523360248201526001600160a01b03909116906351746bb290604401600060405180830381600087803b158015611c9d57600080fd5b505af1158015611cb1573d6000803e3d6000fd5b505050505b6040805134815242602082015233917f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a15910160405180910390a2565b6033546001600160a01b03163314611d1c5760405162461bcd60e51b81526004016108d3906133df565b6001600160a01b0381163b158015611d3c57506001600160a01b03811615155b15611d65576040516322a2d07b60e21b81526001600160a01b03821660048201526024016108d3565b60a180546001600160a01b0319166001600160a01b0383169081179091556040514281527f8e6481d1924c9bb8cdfd9d6140f3e5570c34c6c580d915144728bbbf394eed0a90602001610b40565b60006001600160a01b038316611ddc57604051633d6601c760e11b815260040160405180910390fd5b3360009081526098602090815260408083206001600160a01b038716845290915290205482811015611e2b5760405163054365bb60e31b815260048101849052602481018290526044016108d3565b6000611e37848361348d565b3360008181526098602090815260408083206001600160a01b038b16808552908352928190208590555184815293945090927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3506001949350505050565b6000600260655403611ec35760405162461bcd60e51b81526004016108d390613414565b60026065556001600160a01b038316611eef57604051633a954ecd60e21b815260040160405180910390fd5b306001600160a01b03841603611f185760405163ed728e5760e01b815260040160405180910390fd5b33611f2281612803565b600080611f2e83612ad0565b9150915080851115611f5d576040516350d2479d60e11b815260048101869052602481018290526044016108d3565b611f68838684612c17565b6001600160a01b038316600090815260996020526040902080548690039055611f9086612803565b6001600160a01b03861660009081526099602052604081208054879290611fb890849061347a565b9091555050609d546001600160a01b031615801590611fd657508415155b156120c457609d54604051630d5dbdb360e21b8152600481018790526001600160a01b0385811660248301526000921690633576f6cc906044016020604051808303816000875af115801561202f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612053919061344b565b905080156120c257609d546040516328ba35d960e11b8152600481018390526001600160a01b038981166024830152909116906351746bb290604401600060405180830381600087803b1580156120a957600080fd5b505af11580156120bd573d6000803e3d6000fd5b505050505b505b856001600160a01b0316836001600160a01b0316600080516020613586833981519152876040516120f791815260200190565b60405180910390a360019350505050600160655592915050565b61211b8133611755565b50565b612126613196565b6040518060a00160405280612139611001565b8152602001612146612175565b81526020016121536124de565b81526020016121606116c3565b8152602001670c7d713b49da00009052919050565b609b546000906001600160a01b0316637cd083316121916116c3565b612199611001565b6040516001600160e01b031960e085901b16815260048101929092526024820152604401611368565b609c546001600160a01b03166121eb57604051631c038dab60e21b815260040160405180910390fd5b609c5460405163039ff21960e21b81523360048201526001600160a01b0390911690630e7fc86490602401602060405180830381865afa158015612233573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061225791906134c3565b61227457604051637582fa9b60e11b815260040160405180910390fd5b61227c611001565b60000361229c576040516316d5c93f60e21b815260040160405180910390fd5b6002606554036122be5760405162461bcd60e51b81526004016108d390613414565b600260655560a0546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa15801561230b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061232f919061344b565b81111561234f576040516316d5c93f60e21b815260040160405180910390fd5b61235833612ce9565b336000908152609a60205260408120805483929061237790849061347a565b9091555050306000908152609a60205260408120805483929061239b90849061347a565b909155506123ab905033826125a5565b6123b361261e565b6040805182815242602082015233917fd6b37be10b58108f696d9ed067fedad0bff7cb417ef4c28d2f8a25d6d83c98d5910160405180910390a26001606555670c7d713b49da0000612403611001565b61240b6116c3565b61241d90670de0b6b3a76400006134e5565b61242791906134fc565b111561211b576040516372b9ce3f60e11b815260040160405180910390fd5b6033546001600160a01b031633146124705760405162461bcd60e51b81526004016108d3906133df565b6001600160a01b0381166124d55760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016108d3565b61211b81612e86565b609b546000906001600160a01b031663df841eec6121916116c3565b6033546001600160a01b031633146125245760405162461bcd60e51b81526004016108d3906133df565b6001600160a01b0381163b612557576040516322a2d07b60e21b81526001600160a01b03821660048201526024016108d3565b609c80546001600160a01b0319166001600160a01b0383169081179091556040514281527f04dce7d074f7e287a2e6e3516c802271d58d5c14e0dede83a49719eb6b92046990602001610b40565b60a0546125bc906001600160a01b03168383612ed8565b5050565b600054610100900460ff166125e75760405162461bcd60e51b81526004016108d39061351e565b611b30613002565b600054610100900460ff166126165760405162461bcd60e51b81526004016108d39061351e565b611b30613032565b60006126286116c3565b90506000612634611001565b609b549091506001600160a01b03166126605760405163fd4851e960e01b815260040160405180910390fd5b609e54609b54604051637cd0833160e01b815260048101859052602481018490526001600160a01b03928316926334fcf437921690637cd0833190604401602060405180830381865afa1580156126bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126df919061344b565b6040518263ffffffff1660e01b81526004016126fd91815260200190565b600060405180830381600087803b15801561271757600080fd5b505af115801561272b573d6000803e3d6000fd5b5050609f54609b546040516337e107bb60e21b815260048101879052602481018690526001600160a01b0392831694506334fcf437935091169063df841eec90604401602060405180830381865afa15801561278b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127af919061344b565b6040518263ffffffff1660e01b81526004016127cd91815260200190565b600060405180830381600087803b1580156127e757600080fd5b505af11580156127fb573d6000803e3d6000fd5b505050505050565b6001600160a01b03811660009081526099602052604081205461282583611a09565b61282f919061348d565b905061283b8282612dff565b61284430611a09565b306000908152609960205260409081902091909155516001600160a01b038316907f9bbd517758fbae61197f1c1c04c8614064e89512dbaf4350dcdf76fcaa5e21619061289d9084904290918252602082015260400190565b60405180910390a2609e54604051637681d99b60e11b81526001600160a01b0384811660048301529091169063ed03b33690602401600060405180830381600087803b1580156128ec57600080fd5b505af1158015612900573d6000803e3d6000fd5b5050609e54604051637681d99b60e11b81523060048201526001600160a01b03909116925063ed03b33691506024016127cd565b6001600160a01b03821660009081526099602052604090205481111561296d57604051630bba337f60e11b815260040160405180910390fd5b60008061297984612ad0565b915091508083111561299e5760405163a06a83a160e01b815260040160405180910390fd5b6129a9848484612c17565b6001600160a01b03841660008181526099602090815260408083208054889003905551868152919291600080516020613586833981519152910160405180910390a350505050565b604080516000808252602082019092526001600160a01b038416908390604051612a1b9190613569565b60006040518083038185875af1925050503d8060008114612a58576040519150601f19603f3d011682016040523d82523d6000602084013e612a5d565b606091505b5050905080612acb5760405162461bcd60e51b815260206004820152603460248201527f5472616e7366657248656c7065723a3a736166655472616e736665724554483a60448201527308115512081d1c985b9cd9995c8819985a5b195960621b60648201526084016108d3565b505050565b60a15460009081906001600160a01b031615612bf85760a15460405163cbf9fe5f60e01b81526001600160a01b0385811660048301529091169063cbf9fe5f90602401602060405180830381865afa158015612b30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b54919061344b565b60a15460405163512edc6760e11b81526001600160a01b03868116600483015292945091169063a25db8ce90602401602060405180830381865afa158015612ba0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bc4919061344b565b612bce908361348d565b6001600160a01b038416600090815260996020526040902054612bf1919061348d565b9050915091565b506001600160a01b038216600090815260996020526040902054915091565b6001600160a01b038316600090815260996020526040812054612c3b90839061348d565b90508083118015612c56575060a1546001600160a01b031615155b156108a35760a1546001600160a01b03166349c1de3f85612c77848761348d565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b158015612cbd57600080fd5b505af1158015610dad573d6000803e3d6000fd5b6000818310612ce05781612ce2565b825b9392505050565b612cf2816116ca565b6001600160a01b0382166000908152609a6020526040902055612d14306116ca565b306000908152609a60205260409081902091909155609f549051637681d99b60e11b81526001600160a01b0383811660048301529091169063ed03b33690602401600060405180830381600087803b158015612d6f57600080fd5b505af1158015612d83573d6000803e3d6000fd5b5050609f54604051637681d99b60e11b81523060048201526001600160a01b03909116925063ed03b3369150602401600060405180830381600087803b158015612dcc57600080fd5b505af1158015612de0573d6000803e3d6000fd5b5050505050565b60a0546125bc906001600160a01b0316833084613060565b6001600160a01b038216612e26576040516346dbfb6d60e11b815260040160405180910390fd5b6001600160a01b03821660009081526099602052604081208054839290612e4e90849061347a565b90915550506040518181526001600160a01b038316906000906000805160206135868339815191529060200160405180910390a35050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1790529151600092839290871691612f349190613569565b6000604051808303816000865af19150503d8060008114612f71576040519150601f19603f3d011682016040523d82523d6000602084013e612f76565b606091505b5091509150818015612fa0575080511580612fa0575080806020019051810190612fa091906134c3565b612de05760405162461bcd60e51b815260206004820152602d60248201527f5472616e7366657248656c7065723a3a736166655472616e736665723a20747260448201526c185b9cd9995c8819985a5b1959609a1b60648201526084016108d3565b600054610100900460ff166130295760405162461bcd60e51b81526004016108d39061351e565b611b3033612e86565b600054610100900460ff166130595760405162461bcd60e51b81526004016108d39061351e565b6001606555565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17905291516000928392908816916130c49190613569565b6000604051808303816000865af19150503d8060008114613101576040519150601f19603f3d011682016040523d82523d6000602084013e613106565b606091505b509150915081801561313057508051158061313057508080602001905181019061313091906134c3565b6127fb5760405162461bcd60e51b815260206004820152603160248201527f5472616e7366657248656c7065723a3a7472616e7366657246726f6d3a207472604482015270185b9cd9995c919c9bdb4819985a5b1959607a1b60648201526084016108d3565b6040518060a001604052806005906020820280368337509192915050565b60005b838110156131cf5781810151838201526020016131b7565b50506000910152565b60208152600082518060208401526131f78160408501602087016131b4565b601f01601f19169190910160400192915050565b6001600160a01b038116811461211b57600080fd5b6000806040838503121561323357600080fd5b8235915060208301356132458161320b565b809150509250929050565b60006020828403121561326257600080fd5b8135612ce28161320b565b6000806040838503121561328057600080fd5b823561328b8161320b565b946020939093013593505050565b600080600080600080600060e0888a0312156132b457600080fd5b87356132bf8161320b565b965060208801356132cf8161320b565b955060408801356132df8161320b565b945060608801356132ef8161320b565b935060808801356132ff8161320b565b925060a088013561330f8161320b565b8092505060c0880135905092959891949750929550565b60006020828403121561333857600080fd5b5035919050565b60008060006060848603121561335457600080fd5b833561335f8161320b565b9250602084013561336f8161320b565b929592945050506040919091013590565b60a08101818360005b60058110156133a8578151835260209283019290910190600101613389565b50505092915050565b600080604083850312156133c457600080fd5b82356133cf8161320b565b915060208301356132458161320b565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60006020828403121561345d57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115610a7957610a79613464565b81810381811115610a7957610a79613464565b6000602082840312156134b257600080fd5b815160ff81168114612ce257600080fd5b6000602082840312156134d557600080fd5b81518015158114612ce257600080fd5b8082028115828204841417610a7957610a79613464565b60008261351957634e487b7160e01b600052601260045260246000fd5b500490565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6000825161357b8184602087016131b4565b919091019291505056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212207e716a0644aea20b402fd1493aa22ec09cc818ff80c3d347bd47f691670a8c8b64736f6c63430008110033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

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.