Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0x4BFAEdB339c847830F69b07f2e12a3242af4BBA0
Balance 0 ETH
Nonce 1
Code Size 5365 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

5365 bytes
0x608060405234801561001057600080fd5b50600436106101005760003560e01c80638da5cb5b11610097578063c4d66de811610066578063c4d66de814610220578063d933ac6714610233578063e30c397814610246578063fc4d33f91461025957600080fd5b80638da5cb5b146101d3578063adc9772e146101eb578063aed6d5c0146101fe578063b2a6df741461020d57600080fd5b806361252fd1116100d357806361252fd11461016f5780636e96dfd71461018457806370a082311461019757806372f702f3146101c057600080fd5b806318160ddd146101055780632e1a7d4d1461011c578063337fbfa814610131578063415985c114610144575b600080fd5b6035545b6040519081526020015b60405180910390f35b61012f61012a36600461128e565b610261565b005b61012f61013f3660046112bc565b6103b1565b603954610157906001600160a01b031681565b6040516001600160a01b039091168152602001610113565b610177610455565b60405161011391906112d9565b61012f6101923660046112bc565b610466565b6101096101a53660046112bc565b6001600160a01b031660009081526036602052604090205490565b603454610157906001600160a01b031681565b6000546101579061010090046001600160a01b031681565b61012f6101f9366004611326565b610593565b60405160018152602001610113565b61012f61021b3660046112bc565b6106e7565b61012f61022e3660046112bc565b61079f565b61012f6102413660046112bc565b610866565b600154610157906001600160a01b031681565b61012f610962565b61026a81610a78565b60395460408051630a63bfd560e11b815290516000926001600160a01b0316916314c77faa9160048083019260209291908290030181865afa1580156102b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102d89190611352565b604051632af3854960e01b81523060048201529091506000906001600160a01b03831690632af3854990602401602060405180830381865afa158015610322573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610346919061136f565b905080156103ac5760395460405163098f82e760e21b81523360048201526001600160a01b039091169063263e0b9c90602401600060405180830381600087803b15801561039357600080fd5b505af11580156103a7573d6000803e3d6000fd5b505050505b505050565b60005461010090046001600160a01b031633146103e95760405162461bcd60e51b81526004016103e090611391565b60405180910390fd5b6103f4603782610bbe565b15610439576040516001600160a01b03821681527f202daff40f5262ad5e95940c6c7a62bc0117d839570a20c66268dc0983ef6143906020015b60405180910390a150565b604051630242c2a560e51b815260040160405180910390fd5b50565b60606104616037610bdc565b905090565b60005461010090046001600160a01b031633146104955760405162461bcd60e51b81526004016103e090611391565b6001600160a01b038116158015906104bb57506001546001600160a01b03828116911614155b6105415760405162461bcd60e51b815260206004820152604b60248201527f5f73657450656e64696e674f776e65723a204e6577206f77656e722063616e2060448201527f6e6f74206265207a65726f206164647265737320616e64206f776e657220686160648201526a73206265656e207365742160a81b608482015260a4016103e0565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907fb3d55174552271a4f1aaf36b72f50381e892171636b3fb5447fe00e995e7a37b90600090a35050565b61059d8282610bf0565b60395460408051630a63bfd560e11b815290516000926001600160a01b0316916314c77faa9160048083019260209291908290030181865afa1580156105e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061060b9190611352565b604051632af3854960e01b81523060048201529091506000906001600160a01b03831690632af3854990602401602060405180830381865afa158015610655573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610679919061136f565b905080156106e15760395460405163098f82e760e21b81526001600160a01b0386811660048301529091169063263e0b9c90602401600060405180830381600087803b1580156106c857600080fd5b505af11580156106dc573d6000803e3d6000fd5b505050505b50505050565b60005461010090046001600160a01b031633146107165760405162461bcd60e51b81526004016103e090611391565b6001600160a01b03811661073d57604051633f03113560e21b815260040160405180910390fd5b610748603782610d56565b15610786576040516001600160a01b03821681527fafd92645c06c0f746b45815ad30af48dfbac17647e860d7be5e8bcaded9498a99060200161042e565b604051630217a53560e21b815260040160405180910390fd5b60005460ff16156108095760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016103e0565b6001600160a01b03811661082f57604051625f83fb60e41b815260040160405180910390fd5b610837610d6b565b603480546001600160a01b0319166001600160a01b03929092169190911790556000805460ff19166001179055565b60005461010090046001600160a01b031633146108955760405162461bcd60e51b81526004016103e090611391565b806001600160a01b031663eb5bf95d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108f7919061136f565b6109145760405163d83931ad60e01b815260040160405180910390fd5b603980546001600160a01b0319166001600160a01b0383169081179091556040519081527f69df209622c88250230a5fe484d1fe30a9fea87c4aa276f20ac505761cac54929060200161042e565b6001546001600160a01b031633146109ca5760405162461bcd60e51b815260206004820152602560248201527f5f6163636570744f776e65723a204f6e6c7920666f722070656e64696e67206f604482015264776e65722160d81b60648201526084016103e0565b60008054600180546001600160a01b03818116610100818102610100600160a81b03198716178088556001600160a01b031990941690945560405194849004821695909493909204169184917f70aea8d848e8a90fb7661b227dc522eb6395c3dac71b63cb59edd5c9899b236491a36001546040516001600160a01b03918216918316907fb3d55174552271a4f1aaf36b72f50381e892171636b3fb5447fe00e995e7a37b90600090a35050565b336000610a856037610db3565b905060005b81811015610b0557610a9d603782610dbd565b60405163632447c960e01b81526001600160a01b038581166004830152919091169063632447c990602401600060405180830381600087803b158015610ae257600080fd5b505af1158015610af6573d6000803e3d6000fd5b50505050806001019050610a8a565b5082610b2457604051636602e2a160e11b815260040160405180910390fd5b82603554610b3291906113e9565b60355533600090815260366020526040902054610b509084906113e9565b33600081815260366020526040902091909155603454610b7c916001600160a01b039091169085610dc9565b336000818152603660205260408082205490519092869290917f92ccf450a286a957af52509bc1c9939d1a6a481783e142e41e2499f0bb66ebc69190a4505050565b6000610bd3836001600160a01b038416610e2c565b90505b92915050565b60606000610be983610f1f565b9392505050565b816000610bfd6037610db3565b905060005b81811015610c7d57610c15603782610dbd565b60405163632447c960e01b81526001600160a01b038581166004830152919091169063632447c990602401600060405180830381600087803b158015610c5a57600080fd5b505af1158015610c6e573d6000803e3d6000fd5b50505050806001019050610c02565b5082610c9b576040516206d0c960e51b815260040160405180910390fd5b82603554610ca99190611400565b6035556001600160a01b038416600090815260366020526040902054610cd0908490611400565b6001600160a01b03808616600090815260366020526040902091909155603454610cfd9116333086610f7b565b6001600160a01b0384166000818152603660209081526040918290205491513381529192869290917f6c86f3fd5118b3aa8bb4f389a617046de0a3d3d477de1a1673d227f802f616dc910160405180910390a450505050565b6000610bd3836001600160a01b038416610fb3565b60008054610100600160a81b0319163361010081029190911782556040519091907f70aea8d848e8a90fb7661b227dc522eb6395c3dac71b63cb59edd5c9899b2364908290a3565b6000610bd6825490565b6000610bd38383611002565b6040516001600160a01b0383166024820152604481018290526103ac90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261102c565b60008181526001830160205260408120548015610f15576000610e506001836113e9565b8554909150600090610e64906001906113e9565b9050818114610ec9576000866000018281548110610e8457610e84611418565b9060005260206000200154905080876000018481548110610ea757610ea7611418565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610eda57610eda61142e565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610bd6565b6000915050610bd6565b606081600001805480602002602001604051908101604052809291908181526020018280548015610f6f57602002820191906000526020600020905b815481526020019060010190808311610f5b575b50505050509050919050565b6040516001600160a01b03808516602483015283166044820152606481018290526106e19085906323b872dd60e01b90608401610df5565b6000818152600183016020526040812054610ffa57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610bd6565b506000610bd6565b600082600001828154811061101957611019611418565b9060005260206000200154905092915050565b6000611081826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166111019092919063ffffffff16565b90508051600014806110a25750808060200190518101906110a2919061136f565b6103ac5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016103e0565b60606111108484600085611118565b949350505050565b6060824710156111795760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016103e0565b600080866001600160a01b031685876040516111959190611470565b60006040518083038185875af1925050503d80600081146111d2576040519150601f19603f3d011682016040523d82523d6000602084013e6111d7565b606091505b50915091506111e8878383876111f3565b979650505050505050565b6060831561125f578251611258576001600160a01b0385163b6112585760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016103e0565b5081611110565b61111083838151156112745781518083602001fd5b8060405162461bcd60e51b81526004016103e0919061148c565b6000602082840312156112a057600080fd5b5035919050565b6001600160a01b038116811461045257600080fd5b6000602082840312156112ce57600080fd5b8135610be9816112a7565b6020808252825182820181905260009190848201906040850190845b8181101561131a5783516001600160a01b0316835292840192918401916001016112f5565b50909695505050505050565b6000806040838503121561133957600080fd5b8235611344816112a7565b946020939093013593505050565b60006020828403121561136457600080fd5b8151610be9816112a7565b60006020828403121561138157600080fd5b81518015158114610be957600080fd5b60208082526022908201527f6f6e6c794f776e65723a2063616c6c6572206973206e6f7420746865206f776e60408201526132b960f11b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b6000828210156113fb576113fb6113d3565b500390565b60008219821115611413576114136113d3565b500190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b60005b8381101561145f578181015183820152602001611447565b838111156106e15750506000910152565b60008251611482818460208701611444565b9190910192915050565b60208152600082518060208401526114ab816040850160208701611444565b601f01601f1916919091016040019291505056fea2646970667358221220492414a81ee0015756f01ef535b0dee2677352097ff6582f146baf25bdce536864736f6c634300080a0033

Verified Source Code Full Match

Compiler: v0.8.10+commit.fc410830 EVM: london Optimization: Yes (200 runs)
IERC20Upgradeable.sol 78 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
IERC20PermitUpgradeable.sol 60 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.0;

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

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

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}
SafeERC20Upgradeable.sol 143 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20Upgradeable.sol";
import "../extensions/IERC20PermitUpgradeable.sol";
import "../../../utils/AddressUpgradeable.sol";

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

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20Upgradeable token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20Upgradeable token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

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

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     */
    function forceApprove(IERC20Upgradeable token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
     * Revert on invalid signature.
     */
    function safePermit(
        IERC20PermitUpgradeable token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

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

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

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20Upgradeable token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return
            success && (returndata.length == 0 || abi.decode(returndata, (bool))) && AddressUpgradeable.isContract(address(token));
    }
}
AddressUpgradeable.sol 244 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.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
     *
     * Furthermore, `isContract` will also return true if the target contract within
     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
     * which only has an effect at the end of a transaction.
     * ====
     *
     * [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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

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

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

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

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

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

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

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

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}
EnumerableSetUpgradeable.sol 378 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.

pragma solidity ^0.8.0;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```solidity
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 *
 * [WARNING]
 * ====
 * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
 * unusable.
 * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
 *
 * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
 * array of EnumerableSet.
 * ====
 */
library EnumerableSetUpgradeable {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;
        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping(bytes32 => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            if (lastIndex != toDeleteIndex) {
                bytes32 lastValue = set._values[lastIndex];

                // Move the last value to the index where the value to delete is
                set._values[toDeleteIndex] = lastValue;
                // Update the index for the moved value
                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
            }

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set) private view returns (bytes32[] memory) {
        return set._values;
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
        bytes32[] memory store = _values(set._inner);
        bytes32[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(AddressSet storage set) internal view returns (address[] memory) {
        bytes32[] memory store = _values(set._inner);
        address[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner);
        uint256[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }
}
Errors.sol 71 lines
//SPDX-License-Identifier: MIT
pragma solidity 0.8.10;

error BaseStakingPool_addRewardDistributor__RewardDistributorIsZeroAddress();
error BaseStakingPool_addRewardDistributor__RewardDistributorAlreadyExist();
error BaseStakingPool_initialize__StakingTokenIsZeroAddress();
error BaseStakingPool_removeRewardDistributor__RewardDistributorDoesNotExist();
error BaseStakingPool_stake__StakeAmountIsZero();
error BaseStakingPool_withdraw__WithdrawAmountIsZero();

error BLPStakingPool_setRewardDistributorManager__InvalidRewardDistributorManager();

error BLPReward_initialize__StakingTokenIsZeroAddress();
error BLPReward_initialize__RewardTokenIsZeroAddress();
error BLPReward_initialize__TreasuryIsZeroAddress();
error BLPReward_setTreasury__TreasuryIsZeroAddress();
error BLPReward_setTreasury__SameTreasuryAddress();

error EligibilityManager_addBLPStakingPoolInternal__InvalidStakingPool(
    address stakingPool
);
error EligibilityManager_addBLPStakingPoolInternal__StakingPoolAlreadyExist(
    address stakingPool
);
error EligibilityManager_addValidSupplyInternal__InvalidSupply(address iToken);
error EligibilityManager_addValidSupplyInternal__ValidSupplyAlreadyExist(
    address iToken
);
error EligibilityManager_initialize__InvalidController();
error EligibilityManager_removeValidSupplyInternal__ValidSupplyDoesNotExist(
    address iToken
);
error EligibilityManager_removeBLPStakingPoolInternal__StakingPoolDoesNotExist(
    address stakingPool
);

// Modifier error
error RewardDistributorManager__NotController();
// Function errors
error RewardDistributorManager_addRewardDistributorInternal__InvalidRewardDistributor();
error RewardDistributorManager_addRewardDistributorInternal__RewardDistributorAlreadyExist(
    address rewardDistributor
);
error RewardDistributorManager_initialize__InvalidController();
error RewardDistributorManager_removeRewardDistributorInternal__RewardDistributorDoesNotExist(
    address rewardDistributor
);
error RewardDistributorManager_setEligibilityManager_InvalidEligibilityManager();
error RewardDistributorManager_updateEligibleBalance__InvalidEligibility();

error RewardDistributor__CallerIsNotRewardManager();
error RewardDistributor__ContractPaused();
error RewardDistributor_initialize__InvalidController();
error RewardDistributor_initialize__InvalidRewardDistributorManager();
error RewardDistributor_rescueTokens__CallerIsNotTreasury();
error RewardDistributor_setRewardToken__InvalidRewardToken();
error RewardDistributor_setTreasury__InvalidTreasury();
error RewardDistributor_setDistributionBorrowSpeedsInternal__ArrayLengthMismatch();
error RewardDistributor_setDistributionSupplySpeedsInternal__ArrayLengthMismatch();
error RewardDistributor_setDistributionBorrowSpeed__TokenHasNotBeenListed(
    address iToken
);
error RewardDistributor_setDistributionSupplySpeed__TokenHasNotBeenListed(
    address iToken
);
error RewardDistributor_updateDistributionState__TokenHasNotBeenListed(
    address iToken
);
error RewardDistributor_updateReward__TokenHasNotBeenListed(address iToken);
error RewardDistributor_updateReward__AccountIsZeroAddress();
error RewardDistributor_setBountyRatio__RatioTooHigh();
IBLPReward.sol 6 lines
//SPDX-License-Identifier: MIT
pragma solidity 0.8.10;

interface IBLPReward {
    function updateReward(address _account) external;
}
IEligibilityManager.sol 8 lines
//SPDX-License-Identifier: MIT
pragma solidity 0.8.10;

interface IEligibilityManager {
    function isEligibilityManager() external pure returns (bool);
    function isEligible(address _account) external returns (bool, bool);
    function hasBLPStakingPool(address _stakingPool) external view returns (bool);
}
IRewardDistributorManager.sol 37 lines
//SPDX-License-Identifier: MIT
pragma solidity 0.8.10;
import "./IEligibilityManager.sol";
interface IRewardDistributorManager {
    function isRewardDistributorManager() external pure returns (bool);

    function eligibilityManager() external view returns (IEligibilityManager);

    function _addRecipient(
        address _iToken,
        uint256 _distributionFactor
    ) external;

    function _setEligibilityManager(address _newEligibilityManager) external;

    function eligibleTotalSupply(
        address iToken
    ) external view returns (uint256);

    function eligibleTotalBorrow(
        address iToken
    ) external view returns (uint256);

    function eligibleSupply(
        address iToken,
        address account
    ) external view returns (uint256);

    function eligibleBorrow(
        address iToken,
        address account
    ) external view returns (uint256);

    function updateEligibleBalance(address _account) external;

    function updateEligibleBalances(address[] memory _accounts) external;
}
Initializable.sol 35 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.10;

/**
 * @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 a proxied contract can't have 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 {UpgradeableProxy-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.
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     */
    bool private _initialized;

    /**
     * @dev Modifier to protect an initializer function from being invoked twice.
     */
    modifier initializer() {
        require(
            !_initialized,
            "Initializable: contract is already initialized"
        );

        _;

        _initialized = true;
    }
}
Ownable.sol 91 lines
//SPDX-License-Identifier: MIT
pragma solidity 0.8.10;

/**
 * @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 {_setPendingOwner} and {_acceptOwner}.
 */
contract Ownable {
    /**
     * @dev Returns the address of the current owner.
     */
    address payable public owner;

    /**
     * @dev Returns the address of the current pending owner.
     */
    address payable public pendingOwner;

    event NewOwner(address indexed previousOwner, address indexed newOwner);
    event NewPendingOwner(
        address indexed oldPendingOwner,
        address indexed newPendingOwner
    );

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner == msg.sender, "onlyOwner: caller is not the owner");
        _;
    }

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    function __Ownable_init() internal {
        owner = payable(msg.sender);
        emit NewOwner(address(0), msg.sender);
    }

    /**
     * @notice Base on the inputing parameter `newPendingOwner` to check the exact error reason.
     * @dev Transfer contract control to a new owner. The newPendingOwner must call `_acceptOwner` to finish the transfer.
     * @param newPendingOwner New pending owner.
     */
    function _setPendingOwner(
        address payable newPendingOwner
    ) external onlyOwner {
        require(
            newPendingOwner != address(0) && newPendingOwner != pendingOwner,
            "_setPendingOwner: New owenr can not be zero address and owner has been set!"
        );

        // Gets current owner.
        address oldPendingOwner = pendingOwner;

        // Sets new pending owner.
        pendingOwner = newPendingOwner;

        emit NewPendingOwner(oldPendingOwner, newPendingOwner);
    }

    /**
     * @dev Accepts the admin rights, but only for pendingOwenr.
     */
    function _acceptOwner() external {
        require(
            msg.sender == pendingOwner,
            "_acceptOwner: Only for pending owner!"
        );

        // Gets current values for events.
        address oldOwner = owner;
        address oldPendingOwner = pendingOwner;

        // Set the new contract owner.
        owner = pendingOwner;

        // Clear the pendingOwner.
        pendingOwner = payable(address(0));

        emit NewOwner(oldOwner, owner);
        emit NewPendingOwner(oldPendingOwner, pendingOwner);
    }

    uint256[50] private __gap;
}
BLPStakingPool.sol 53 lines
//SPDX-License-Identifier: MIT
pragma solidity 0.8.10;



import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";

import "./BaseStakingPool.sol";
import "../Interfaces/Errors.sol";
import "../Interfaces/IRewardDistributorManager.sol";
import "../Interfaces/IEligibilityManager.sol";
import "../Libraries/Initializable.sol";

contract BLPStakingPool is Initializable, BaseStakingPool {
    IRewardDistributorManager public rewardDistributorManager;

    event NewRewardDistributorManager(address newRewardDistributorManager);

    constructor(
        IERC20Upgradeable _stakingToken
    ) BaseStakingPool(_stakingToken) {}

    function _setRewardDistributorManager(
        IRewardDistributorManager _rewardDistributorManager
    ) external onlyOwner {
        if (!_rewardDistributorManager.isRewardDistributorManager()) {
            revert BLPStakingPool_setRewardDistributorManager__InvalidRewardDistributorManager();
        }

        rewardDistributorManager = _rewardDistributorManager;
        emit NewRewardDistributorManager(address(_rewardDistributorManager));
    }

    function stake(address _recipient, uint256 _amount) public virtual override {
        super.stake(_recipient, _amount);

        IEligibilityManager _eligibilityManager = rewardDistributorManager.eligibilityManager();
        bool _hasBLPStakingPool = _eligibilityManager.hasBLPStakingPool(address(this));
        if (_hasBLPStakingPool) {
            rewardDistributorManager.updateEligibleBalance(_recipient);
        }
    }

    function withdraw(uint256 _amount) public virtual override {
        super.withdraw(_amount);

        IEligibilityManager _eligibilityManager = rewardDistributorManager.eligibilityManager();
        bool _hasBLPStakingPool = _eligibilityManager.hasBLPStakingPool(address(this));
        if (_hasBLPStakingPool) {
            rewardDistributorManager.updateEligibleBalance(msg.sender);
        }
    }
}
BaseStakingPool.sol 123 lines
//SPDX-License-Identifier: MIT
pragma solidity 0.8.10;

import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol";
import "../Interfaces/Errors.sol";
import "../Interfaces/IBLPReward.sol";
import "../Libraries/Initializable.sol";
import "../Libraries/Ownable.sol";


contract BaseStakingPool is Initializable, Ownable {
    using SafeERC20Upgradeable for IERC20Upgradeable;
    using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;

    IERC20Upgradeable public stakingToken;
    uint256 private _totalSupply;
    mapping(address => uint256) private _balances;
    EnumerableSetUpgradeable.AddressSet internal _rewardDistributors;

    event AddRewardDistributor(address _newRewardDistributor);
    event RemoveRewardDistributor(address _oldRewardDistributor);
    event Staked(address spender, address indexed recipient, uint256 indexed stakeAmount, uint256 indexed stakedAmount);
    event Withdrawn(address indexed user, uint256 indexed stakeAmount, uint256 indexed stakedAmount);

    modifier updateReward(address _account) {
        uint256 _length = _rewardDistributors.length();
        for (uint256 _i; _i < _length; ) {
            IBLPReward(_rewardDistributors.at(_i)).updateReward(_account);

            unchecked {
                ++_i;
            }
        }
        _;
    }

    constructor(IERC20Upgradeable _stakingToken) {
        initialize(_stakingToken);
    }

    /*********************************/
    /******** Security Check *********/
    /*********************************/

    /**
     * @notice Ensure this is a Staking Pool contract.
     */
    function isStakingPool() external pure returns (bool) {
        return true;
    }

    function initialize(IERC20Upgradeable _stakingToken) public virtual initializer {
        if (address(_stakingToken) == address(0)) {
            revert BaseStakingPool_initialize__StakingTokenIsZeroAddress();
        }

        __Ownable_init();

        stakingToken = _stakingToken;
    }

    function _addRewardDistributor(
        address _newRewardDistributor
    ) external onlyOwner {
        if (_newRewardDistributor == address(0)) {
            revert BaseStakingPool_addRewardDistributor__RewardDistributorIsZeroAddress();
        }

        if (_rewardDistributors.add(_newRewardDistributor)) {
            emit AddRewardDistributor(_newRewardDistributor);
        } else {
            revert BaseStakingPool_addRewardDistributor__RewardDistributorAlreadyExist();
        }
    }

    function _removeRewardDistributor(
        address _oldRewardDistributor
    ) external onlyOwner {
        if (_rewardDistributors.remove(_oldRewardDistributor)) {
            emit RemoveRewardDistributor(_oldRewardDistributor);
        } else {
            revert BaseStakingPool_removeRewardDistributor__RewardDistributorDoesNotExist();
        }
    }

    function getRewardDistributors() external view returns (address[] memory) {
        return _rewardDistributors.values();
    }

    function totalSupply() public view returns (uint256) {
        return _totalSupply;
    }

    function balanceOf(address account) public view returns (uint256) {
        return _balances[account];
    }

    function stake(address _recipient, uint256 amount) public virtual updateReward(_recipient) {
        if (amount == 0) {
            revert BaseStakingPool_stake__StakeAmountIsZero();
        }

        _totalSupply = _totalSupply + amount;
        _balances[_recipient] = _balances[_recipient] + amount;
        stakingToken.safeTransferFrom(msg.sender, address(this), amount);

        emit Staked(msg.sender, _recipient, amount, _balances[_recipient]);
    }

    function withdraw(uint256 amount) public virtual updateReward(msg.sender) {
        if (amount == 0) {
            revert BaseStakingPool_withdraw__WithdrawAmountIsZero();
        }

        _totalSupply = _totalSupply - amount;
        _balances[msg.sender] = _balances[msg.sender] - amount;
        stakingToken.safeTransfer(msg.sender, amount);

        emit Withdrawn(msg.sender, amount, _balances[msg.sender]);
    }
}

Read Contract

balanceOf 0x70a08231 → uint256
getRewardDistributors 0x61252fd1 → address[]
isStakingPool 0xaed6d5c0 → bool
owner 0x8da5cb5b → address
pendingOwner 0xe30c3978 → address
rewardDistributorManager 0x415985c1 → address
stakingToken 0x72f702f3 → address
totalSupply 0x18160ddd → uint256

Write Contract 8 functions

These functions modify contract state and require a wallet transaction to execute.

_acceptOwner 0xfc4d33f9
No parameters
_addRewardDistributor 0xb2a6df74
address _newRewardDistributor
_removeRewardDistributor 0x337fbfa8
address _oldRewardDistributor
_setPendingOwner 0x6e96dfd7
address newPendingOwner
_setRewardDistributorManager 0xd933ac67
address _rewardDistributorManager
initialize 0xc4d66de8
address _stakingToken
stake 0xadc9772e
address _recipient
uint256 _amount
withdraw 0x2e1a7d4d
uint256 _amount

Recent Transactions

No transactions found for this address