Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00
Cross-Chain Transactions
Loading...
Loading
Contract Name:
EligibilityDataProvider
Compiler Version
v0.8.12+commit.f00d7308
Optimization Enabled:
Yes with 999999 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.12;
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {ILendingPool} from "../../interfaces/ILendingPool.sol";
import {IMultiFeeDistribution} from "../../interfaces/IMultiFeeDistribution.sol";
import {ChefIncentivesController} from "../staking/ChefIncentivesController.sol";
import {IPriceProvider} from "../../interfaces/IPriceProvider.sol";
import {IMiddleFeeDistribution} from "../../interfaces/IMiddleFeeDistribution.sol";
import {LockedBalance, Balances} from "../../interfaces/LockedBalance.sol";
/// @title Eligible Deposit Provider
/// @notice This contract is created to provide eligibility data for the users
/// including Riz.
/// @author Radiant Labs
contract EligibilityDataProvider is OwnableUpgradeable {
/********************** Common Info ***********************/
uint256 private constant _PRECISION = 10 ** 18;
uint256 private constant _DECIMALS_8_PRECISION = 10 ** 8;
/// @notice RATIO BASE equal to 100%
uint256 public constant RATIO_DIVISOR = 10000;
/// @notice Initial required ratio of TVL to get reward; in bips
uint256 public constant INITIAL_REQUIRED_DEPOSIT_RATIO = 500;
/// @notice Initial ratio of the required price to still allow without disqualification; in bips
uint256 public constant INITIAL_PRICE_TOLERANCE_RATIO = 9000;
/// @notice Minimum required ratio of TVL to get reward; in bips
uint256 public constant MIN_PRICE_TOLERANCE_RATIO = 8000;
/// @notice Address of Lending Pool
ILendingPool public lendingPool;
/// @notice Address of CIC
ChefIncentivesController public chef;
/// @notice Address of Middle fee distribution
IMiddleFeeDistribution public middleFeeDistribution;
/// @notice RDNT + LP price provider
IPriceProvider public priceProvider;
/// @notice Required ratio of TVL to get reward; in bips
uint256 public requiredDepositRatio;
/// @notice Ratio of the required price to still allow without disqualification; in bips
uint256 public priceToleranceRatio;
/// @notice RDNT-ETH LP token
address public lpToken;
/********************** Eligible info ***********************/
/// @notice Last eligible status of the user
mapping(address => bool) public lastEligibleStatus;
/// @notice Disqualified time of the user
mapping(address => uint256) public disqualifiedTime;
/// @notice Legacy Mapping - DO NOT REMOVE!
mapping(address => uint256) private obsoleteMapping1; // WAS: `eligibleDeposits`
/// @notice Legacy Mapping - DO NOT REMOVE!
mapping(address => mapping(address => uint256)) public obsoleteMapping2; // WAS: `userDeposits`
/// @notice Addresses of lending pool to be considered in `requiredUsdValue(user)` calculation
ILendingPool[] internal _eligibleRizLendingPools;
/********************** Events ***********************/
/// @notice Emitted when CIC is set
event ChefIncentivesControllerUpdated(ChefIncentivesController indexed _chef);
/// @notice Emitted when LP token is set
event LPTokenUpdated(address indexed _lpToken);
/// @notice Emitted when required TVL ratio is updated
event RequiredDepositRatioUpdated(uint256 indexed requiredDepositRatio);
/// @notice Emitted when price tolerance ratio is updated
event PriceToleranceRatioUpdated(uint256 indexed priceToleranceRatio);
/// @notice Emitted when DQ time is set
event DqTimeUpdated(address indexed _user, uint256 _time);
/// @notice Emitted when eligible lending pools are updated
event EligibleRizLendingPoolsUpdated(ILendingPool[] eligibleRizLendingPools);
/********************** Errors ***********************/
error AddressZero();
error LPTokenSet();
error InvalidRatio();
error OnlyCIC();
error MissingEligibleLendingPools();
constructor() {
_disableInitializers();
}
/**
* @notice Constructor
* @param _lendingPool Address of lending pool.
* @param _middleFeeDistribution MiddleFeeDistribution address.
* @param _priceProvider PriceProvider address.
*/
function initialize(
ILendingPool _lendingPool,
IMiddleFeeDistribution _middleFeeDistribution,
IPriceProvider _priceProvider
) public initializer {
if (address(_lendingPool) == address(0)) revert AddressZero();
if (address(_middleFeeDistribution) == address(0)) revert AddressZero();
if (address(_priceProvider) == address(0)) revert AddressZero();
lendingPool = _lendingPool;
middleFeeDistribution = _middleFeeDistribution;
priceProvider = _priceProvider;
requiredDepositRatio = INITIAL_REQUIRED_DEPOSIT_RATIO;
priceToleranceRatio = INITIAL_PRICE_TOLERANCE_RATIO;
__Ownable_init();
}
/********************** Setters ***********************/
/**
* @notice Set CIC
* @param _chef address.
*/
function setChefIncentivesController(ChefIncentivesController _chef) external onlyOwner {
if (address(_chef) == address(0)) revert AddressZero();
chef = _chef;
emit ChefIncentivesControllerUpdated(_chef);
}
/**
* @notice Set LP token
*/
function setLPToken(address _lpToken) external onlyOwner {
if (_lpToken == address(0)) revert AddressZero();
if (lpToken != address(0)) revert LPTokenSet();
lpToken = _lpToken;
emit LPTokenUpdated(_lpToken);
}
/**
* @notice Sets required tvl ratio. Can only be called by the owner.
* @param _requiredDepositRatio Ratio in bips.
*/
function setRequiredDepositRatio(uint256 _requiredDepositRatio) external onlyOwner {
if (_requiredDepositRatio > RATIO_DIVISOR) revert InvalidRatio();
requiredDepositRatio = _requiredDepositRatio;
emit RequiredDepositRatioUpdated(_requiredDepositRatio);
}
/**
* @notice Sets price tolerance ratio. Can only be called by the owner.
* @param _priceToleranceRatio Ratio in bips.
*/
function setPriceToleranceRatio(uint256 _priceToleranceRatio) external onlyOwner {
if (_priceToleranceRatio < MIN_PRICE_TOLERANCE_RATIO || _priceToleranceRatio > RATIO_DIVISOR)
revert InvalidRatio();
priceToleranceRatio = _priceToleranceRatio;
emit PriceToleranceRatioUpdated(_priceToleranceRatio);
}
/**
* @notice Sets DQ time of the user
* @dev Only callable by CIC
* @param _user's address
* @param _time for DQ
*/
function setDqTime(address _user, uint256 _time) external {
if (msg.sender != address(chef)) revert OnlyCIC();
disqualifiedTime[_user] = _time;
emit DqTimeUpdated(_user, _time);
}
/**
* @notice Sets eligible lending pools that should be considered in `requiredUsdValue(user)` calculation
* @param pools Array of eligible lending pools
*/
function setEligibleRizLendingPools(ILendingPool[] calldata pools) external onlyOwner {
uint256 len = pools.length;
if (len == 0) revert MissingEligibleLendingPools();
for (uint i = 0; i < len; i++) {
if (address(pools[i]) == address(0)) revert AddressZero();
}
delete _eligibleRizLendingPools;
_eligibleRizLendingPools = pools;
emit EligibleRizLendingPoolsUpdated(_eligibleRizLendingPools);
}
/********************** View functions ***********************/
/**
* @notice Returns eligible lending pools
*/
function getEligibleRizLendingPools() external view returns (ILendingPool[] memory) {
return _eligibleRizLendingPools;
}
/**
* @notice Returns locked RDNT and LP token value in eth
* @param user's address
*/
function lockedUsdValue(address user) public view returns (uint256) {
IMultiFeeDistribution multiFeeDistribution = IMultiFeeDistribution(
middleFeeDistribution.getMultiFeeDistributionAddress()
);
Balances memory _balances = multiFeeDistribution.getBalances(user);
return _lockedUsdValue(_balances.locked);
}
/**
* @notice Returns USD value required to be locked
* @param user's address
* @return required USD value in 8 decimal precision.
*/
function requiredUsdValue(address user) public view returns (uint256 required) {
// Core lending pool associated priceOracle returns USD value in 8 decimals
(uint256 sumTotalCollateralUSD, , , , , ) = lendingPool.getUserAccountData(user);
uint256 len = _eligibleRizLendingPools.length;
if (len > 0) {
for (uint i = 0; i < len; ) {
// Riz lending pool associated priceOracle returns USD value in 18 decimals
(uint256 collateralUSD18Decimals, , , , , ) = _eligibleRizLendingPools[i].getUserAccountData(user);
uint256 collateralUSD = (collateralUSD18Decimals * _DECIMALS_8_PRECISION) / _PRECISION;
sumTotalCollateralUSD += collateralUSD;
unchecked {
++i;
}
}
}
required = (sumTotalCollateralUSD * requiredDepositRatio) / RATIO_DIVISOR;
}
/**
* @notice Returns if the user is eligible to receive rewards
* @param _user's address
*/
function isEligibleForRewards(address _user) public view returns (bool) {
uint256 lockedValue = lockedUsdValue(_user);
uint256 requiredValue = (requiredUsdValue(_user) * priceToleranceRatio) / RATIO_DIVISOR;
return requiredValue != 0 && lockedValue >= requiredValue;
}
/**
* @notice Returns DQ time of the user
* @param _user's address
*/
function getDqTime(address _user) public view returns (uint256) {
return disqualifiedTime[_user];
}
/**
* @notice Returns last eligible time of the user
* @dev If user is still eligible, it will return future time
* CAUTION: this function only works perfect when the array
* is ordered by lock time. This is assured when _stake happens.
* @param user's address
* @return lastEligibleTimestamp of the user. Returns 0 if user is not eligible.
*/
function lastEligibleTime(address user) public view returns (uint256 lastEligibleTimestamp) {
if (!isEligibleForRewards(user)) {
return 0;
}
uint256 requiredValue = requiredUsdValue(user);
IMultiFeeDistribution multiFeeDistribution = IMultiFeeDistribution(
middleFeeDistribution.getMultiFeeDistributionAddress()
);
LockedBalance[] memory lpLockData = multiFeeDistribution.lockInfo(user);
uint256 lockedLP;
for (uint256 i = lpLockData.length; i > 0; ) {
LockedBalance memory currentLockData = lpLockData[i - 1];
lockedLP += currentLockData.amount;
if (_lockedUsdValue(lockedLP) >= requiredValue) {
return currentLockData.unlockTime;
}
unchecked {
i--;
}
}
}
/********************** Operate functions ***********************/
/**
* @notice Refresh token amount for eligibility
* @param user The address of the user
* @return currentEligibility The current eligibility status of the user
*/
function refresh(address user) external returns (bool currentEligibility) {
if (msg.sender != address(chef)) revert OnlyCIC();
if (user == address(0)) revert AddressZero();
updatePrice();
currentEligibility = isEligibleForRewards(user);
if (currentEligibility && disqualifiedTime[user] != 0) {
disqualifiedTime[user] = 0;
}
lastEligibleStatus[user] = currentEligibility;
}
/**
* @notice Update token price
*/
function updatePrice() public {
priceProvider.update();
}
/********************** Internal functions ***********************/
/**
* @notice Returns locked RDNT and LP token value in USD
* @param lockedLP is locked lp amount
*/
function _lockedUsdValue(uint256 lockedLP) internal view returns (uint256) {
uint256 lpPrice = priceProvider.getLpTokenPriceUsd();
return (lockedLP * lpPrice) / 10 ** 18;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (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 Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling 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);
}
/**
* @dev 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.9.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
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.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* 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 prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized != type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
function __Pausable_init() internal onlyInitializing {
__Pausable_init_unchained();
}
function __Pausable_init_unchained() internal onlyInitializing {
_paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
/**
* @dev 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.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);
}
}
}// 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;
}
/**
* @dev 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 (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 IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// 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 IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @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(IERC20 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(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
/**
* @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(IERC20 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(IERC20 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(IERC20 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(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
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(IERC20 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))) && Address.isContract(address(token));
}
}// 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 Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* 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);
}
}
}// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.12;
pragma experimental ABIEncoderV2;
interface IEligibilityDataProvider {
function refresh(address user) external returns (bool currentEligibility);
function updatePrice() external;
function requiredEthValue(address user) external view returns (uint256 required);
function isEligibleForRewards(address _user) external view returns (bool isEligible);
function lastEligibleTime(address user) external view returns (uint256 lastEligibleTimestamp);
function lockedUsdValue(address user) external view returns (uint256);
function requiredUsdValue(address user) external view returns (uint256 required);
function lastEligibleStatus(address user) external view returns (bool);
function rewardEligibleAmount(address token) external view returns (uint256);
function setDqTime(address _user, uint256 _time) external;
function getDqTime(address _user) external view returns (uint256);
function autoprune() external returns (uint256 processed);
function requiredDepositRatio() external view returns (uint256);
function RATIO_DIVISOR() external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.12;
import "./LockedBalance.sol";
interface IFeeDistribution {
struct RewardData {
address token;
uint256 amount;
}
function addReward(address rewardsToken) external;
function removeReward(address _rewardToken) external;
}// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.12;
pragma experimental ABIEncoderV2;
import {ILendingPoolAddressesProvider} from "./ILendingPoolAddressesProvider.sol";
import {DataTypes} from "../lending/libraries/types/DataTypes.sol";
interface ILendingPool {
/**
* @dev Emitted on deposit()
* @param reserve The address of the underlying asset of the reserve
* @param user The address initiating the deposit
* @param onBehalfOf The beneficiary of the deposit, receiving the aTokens
* @param amount The amount deposited
* @param referral The referral code used
**/
event Deposit(
address indexed reserve,
address user,
address indexed onBehalfOf,
uint256 amount,
uint16 indexed referral
);
/**
* @dev Emitted on withdraw()
* @param reserve The address of the underlyng asset being withdrawn
* @param user The address initiating the withdrawal, owner of aTokens
* @param to Address that will receive the underlying
* @param amount The amount to be withdrawn
**/
event Withdraw(address indexed reserve, address indexed user, address indexed to, uint256 amount);
/**
* @dev Emitted on borrow() and flashLoan() when debt needs to be opened
* @param reserve The address of the underlying asset being borrowed
* @param user The address of the user initiating the borrow(), receiving the funds on borrow() or just
* initiator of the transaction on flashLoan()
* @param onBehalfOf The address that will be getting the debt
* @param amount The amount borrowed out
* @param borrowRateMode The rate mode: 1 for Stable, 2 for Variable
* @param borrowRate The numeric rate at which the user has borrowed
* @param referral The referral code used
**/
event Borrow(
address indexed reserve,
address user,
address indexed onBehalfOf,
uint256 amount,
uint256 borrowRateMode,
uint256 borrowRate,
uint16 indexed referral
);
/**
* @dev Emitted on repay()
* @param reserve The address of the underlying asset of the reserve
* @param user The beneficiary of the repayment, getting his debt reduced
* @param repayer The address of the user initiating the repay(), providing the funds
* @param amount The amount repaid
**/
event Repay(address indexed reserve, address indexed user, address indexed repayer, uint256 amount);
/**
* @dev Emitted on swapBorrowRateMode()
* @param reserve The address of the underlying asset of the reserve
* @param user The address of the user swapping his rate mode
* @param rateMode The rate mode that the user wants to swap to
**/
event Swap(address indexed reserve, address indexed user, uint256 rateMode);
/**
* @dev Emitted on setUserUseReserveAsCollateral()
* @param reserve The address of the underlying asset of the reserve
* @param user The address of the user enabling the usage as collateral
**/
event ReserveUsedAsCollateralEnabled(address indexed reserve, address indexed user);
/**
* @dev Emitted on setUserUseReserveAsCollateral()
* @param reserve The address of the underlying asset of the reserve
* @param user The address of the user enabling the usage as collateral
**/
event ReserveUsedAsCollateralDisabled(address indexed reserve, address indexed user);
/**
* @dev Emitted on rebalanceStableBorrowRate()
* @param reserve The address of the underlying asset of the reserve
* @param user The address of the user for which the rebalance has been executed
**/
event RebalanceStableBorrowRate(address indexed reserve, address indexed user);
/**
* @dev Emitted on flashLoan()
* @param target The address of the flash loan receiver contract
* @param initiator The address initiating the flash loan
* @param asset The address of the asset being flash borrowed
* @param amount The amount flash borrowed
* @param premium The fee flash borrowed
* @param referralCode The referral code used
**/
event FlashLoan(
address indexed target,
address indexed initiator,
address indexed asset,
uint256 amount,
uint256 premium,
uint16 referralCode
);
/**
* @dev Emitted when the pause is triggered.
*/
event Paused();
/**
* @dev Emitted when the pause is lifted.
*/
event Unpaused();
/**
* @dev Emitted when a borrower is liquidated. This event is emitted by the LendingPool via
* LendingPoolCollateral manager using a DELEGATECALL
* This allows to have the events in the generated ABI for LendingPool.
* @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation
* @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation
* @param user The address of the borrower getting liquidated
* @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover
* @param liquidatedCollateralAmount The amount of collateral received by the liiquidator
* @param liquidator The address of the liquidator
* @param receiveAToken `true` if the liquidators wants to receive the collateral aTokens, `false` if he wants
* to receive the underlying collateral asset directly
**/
event LiquidationCall(
address indexed collateralAsset,
address indexed debtAsset,
address indexed user,
uint256 debtToCover,
uint256 liquidatedCollateralAmount,
address liquidator,
bool receiveAToken
);
/**
* @dev Emitted when the state of a reserve is updated. NOTE: This event is actually declared
* in the ReserveLogic library and emitted in the updateInterestRates() function. Since the function is internal,
* the event will actually be fired by the LendingPool contract. The event is therefore replicated here so it
* gets added to the LendingPool ABI
* @param reserve The address of the underlying asset of the reserve
* @param liquidityRate The new liquidity rate
* @param stableBorrowRate The new stable borrow rate
* @param variableBorrowRate The new variable borrow rate
* @param liquidityIndex The new liquidity index
* @param variableBorrowIndex The new variable borrow index
**/
event ReserveDataUpdated(
address indexed reserve,
uint256 liquidityRate,
uint256 stableBorrowRate,
uint256 variableBorrowRate,
uint256 liquidityIndex,
uint256 variableBorrowIndex
);
function initialize(ILendingPoolAddressesProvider provider) external;
/**
* @dev Deposits an `amount` of underlying asset into the reserve, receiving in return overlying aTokens.
* - E.g. User deposits 100 USDC and gets in return 100 aUSDC
* @param asset The address of the underlying asset to deposit
* @param amount The amount to be deposited
* @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user
* wants to receive them on his own wallet, or a different address if the beneficiary of aTokens
* is a different wallet
* @param referralCode Code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
**/
function deposit(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external;
function depositWithAutoDLP(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external;
/**
* @dev Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned
* E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC
* @param asset The address of the underlying asset to withdraw
* @param amount The underlying amount to be withdrawn
* - Send the value type(uint256).max in order to withdraw the whole aToken balance
* @param to Address that will receive the underlying, same as msg.sender if the user
* wants to receive it on his own wallet, or a different address if the beneficiary is a
* different wallet
* @return The final amount withdrawn
**/
function withdraw(address asset, uint256 amount, address to) external returns (uint256);
/**
* @dev Allows users to borrow a specific `amount` of the reserve underlying asset, provided that the borrower
* already deposited enough collateral, or he was given enough allowance by a credit delegator on the
* corresponding debt token (StableDebtToken or VariableDebtToken)
* - E.g. User borrows 100 USDC passing as `onBehalfOf` his own address, receiving the 100 USDC in his wallet
* and 100 stable/variable debt tokens, depending on the `interestRateMode`
* @param asset The address of the underlying asset to borrow
* @param amount The amount to be borrowed
* @param interestRateMode The interest rate mode at which the user wants to borrow: 1 for Stable, 2 for Variable
* @param referralCode Code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
* @param onBehalfOf Address of the user who will receive the debt. Should be the address of the borrower itself
* calling the function if he wants to borrow against his own collateral, or the address of the credit delegator
* if he has been given credit delegation allowance
**/
function borrow(
address asset,
uint256 amount,
uint256 interestRateMode,
uint16 referralCode,
address onBehalfOf
) external;
/**
* @notice Repays a borrowed `amount` on a specific reserve, burning the equivalent debt tokens owned
* - E.g. User repays 100 USDC, burning 100 variable/stable debt tokens of the `onBehalfOf` address
* @param asset The address of the borrowed underlying asset previously borrowed
* @param amount The amount to repay
* - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode`
* @param rateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable
* @param onBehalfOf Address of the user who will get his debt reduced/removed. Should be the address of the
* user calling the function if he wants to reduce/remove his own debt, or the address of any other
* other borrower whose debt should be removed
* @return The final amount repaid
**/
function repay(address asset, uint256 amount, uint256 rateMode, address onBehalfOf) external returns (uint256);
/**
* @dev Allows a borrower to swap his debt between stable and variable mode, or viceversa
* @param asset The address of the underlying asset borrowed
* @param rateMode The rate mode that the user wants to swap to
**/
function swapBorrowRateMode(address asset, uint256 rateMode) external;
/**
* @dev Rebalances the stable interest rate of a user to the current stable rate defined on the reserve.
* - Users can be rebalanced if the following conditions are satisfied:
* 1. Usage ratio is above 95%
* 2. the current deposit APY is below REBALANCE_UP_THRESHOLD * maxVariableBorrowRate, which means that too much has been
* borrowed at a stable rate and depositors are not earning enough
* @param asset The address of the underlying asset borrowed
* @param user The address of the user to be rebalanced
**/
function rebalanceStableBorrowRate(address asset, address user) external;
/**
* @dev Allows depositors to enable/disable a specific deposited asset as collateral
* @param asset The address of the underlying asset deposited
* @param useAsCollateral `true` if the user wants to use the deposit as collateral, `false` otherwise
**/
function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) external;
/**
* @dev Function to liquidate a non-healthy position collateral-wise, with Health Factor below 1
* - The caller (liquidator) covers `debtToCover` amount of debt of the user getting liquidated, and receives
* a proportionally amount of the `collateralAsset` plus a bonus to cover market risk
* @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation
* @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation
* @param user The address of the borrower getting liquidated
* @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover
* @param receiveAToken `true` if the liquidators wants to receive the collateral aTokens, `false` if he wants
* to receive the underlying collateral asset directly
**/
function liquidationCall(
address collateralAsset,
address debtAsset,
address user,
uint256 debtToCover,
bool receiveAToken
) external;
/**
* @dev Allows smartcontracts to access the liquidity of the pool within one transaction,
* as long as the amount taken plus a fee is returned.
* IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept into consideration.
* For further details please visit https://developers.aave.com
* @param receiverAddress The address of the contract receiving the funds, implementing the IFlashLoanReceiver interface
* @param assets The addresses of the assets being flash-borrowed
* @param amounts The amounts amounts being flash-borrowed
* @param modes Types of the debt to open if the flash loan is not returned:
* 0 -> Don't open any debt, just revert if funds can't be transferred from the receiver
* 1 -> Open debt at stable rate for the value of the amount flash-borrowed to the `onBehalfOf` address
* 2 -> Open debt at variable rate for the value of the amount flash-borrowed to the `onBehalfOf` address
* @param onBehalfOf The address that will receive the debt in the case of using on `modes` 1 or 2
* @param params Variadic packed params to pass to the receiver as extra information
* @param referralCode Code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
**/
function flashLoan(
address receiverAddress,
address[] calldata assets,
uint256[] calldata amounts,
uint256[] calldata modes,
address onBehalfOf,
bytes calldata params,
uint16 referralCode
) external;
/**
* @dev Returns the user account data across all the reserves
* @param user The address of the user
* @return totalCollateral the total collateral in USD to 8 decimals of the user
* @return totalDebt the total debt in USD to 8 decimals of the user
* @return availableBorrows the borrowing power left of the user
* @return currentLiquidationThreshold the liquidation threshold of the user
* @return ltv the loan to value of the user
* @return healthFactor the current health factor of the user
**/
function getUserAccountData(
address user
)
external
view
returns (
uint256 totalCollateral,
uint256 totalDebt,
uint256 availableBorrows,
uint256 currentLiquidationThreshold,
uint256 ltv,
uint256 healthFactor
);
function initReserve(
address reserve,
address aTokenAddress,
address stableDebtAddress,
address variableDebtAddress,
address interestRateStrategyAddress
) external;
function setReserveInterestRateStrategyAddress(address reserve, address rateStrategyAddress) external;
function setConfiguration(address reserve, uint256 configuration) external;
/**
* @dev Returns the configuration of the reserve
* @param asset The address of the underlying asset of the reserve
* @return The configuration of the reserve
**/
function getConfiguration(address asset) external view returns (DataTypes.ReserveConfigurationMap memory);
/**
* @dev Returns the configuration of the user across all the reserves
* @param user The user address
* @return The configuration of the user
**/
function getUserConfiguration(address user) external view returns (DataTypes.UserConfigurationMap memory);
/**
* @dev Returns the normalized income normalized income of the reserve
* @param asset The address of the underlying asset of the reserve
* @return The reserve's normalized income
*/
function getReserveNormalizedIncome(address asset) external view returns (uint256);
/**
* @dev Returns the normalized variable debt per unit of asset
* @param asset The address of the underlying asset of the reserve
* @return The reserve normalized variable debt
*/
function getReserveNormalizedVariableDebt(address asset) external view returns (uint256);
/**
* @dev Returns the state and configuration of the reserve
* @param asset The address of the underlying asset of the reserve
* @return The state of the reserve
**/
function getReserveData(address asset) external view returns (DataTypes.ReserveData memory);
function finalizeTransfer(
address asset,
address from,
address to,
uint256 amount,
uint256 balanceFromAfter,
uint256 balanceToBefore
) external;
function getReservesList() external view returns (address[] memory);
function getAddressesProvider() external view returns (ILendingPoolAddressesProvider);
function setPause(bool val) external;
function paused() external view returns (bool);
}// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.12;
/**
* @title LendingPoolAddressesProvider contract
* @dev Main registry of addresses part of or connected to the protocol, including permissioned roles
* - Acting also as factory of proxies and admin of those, so with right to change its implementations
* - Owned by the Aave Governance
* @author Aave
**/
interface ILendingPoolAddressesProvider {
event MarketIdSet(string newMarketId);
event LendingPoolUpdated(address indexed newAddress);
event ConfigurationAdminUpdated(address indexed newAddress);
event EmergencyAdminUpdated(address indexed newAddress);
event LendingPoolConfiguratorUpdated(address indexed newAddress);
event LendingPoolCollateralManagerUpdated(address indexed newAddress);
event PriceOracleUpdated(address indexed newAddress);
event LendingRateOracleUpdated(address indexed newAddress);
event ProxyCreated(bytes32 id, address indexed newAddress);
event AddressSet(bytes32 id, address indexed newAddress, bool hasProxy);
function getMarketId() external view returns (string memory);
function setMarketId(string calldata marketId) external;
function setAddress(bytes32 id, address newAddress) external;
function setAddressAsProxy(bytes32 id, address impl) external;
function getAddress(bytes32 id) external view returns (address);
function getLendingPool() external view returns (address);
function setLendingPoolImpl(address pool) external;
function getLendingPoolConfigurator() external view returns (address);
function setLendingPoolConfiguratorImpl(address configurator) external;
function getLendingPoolCollateralManager() external view returns (address);
function setLendingPoolCollateralManager(address manager) external;
function getPoolAdmin() external view returns (address);
function setPoolAdmin(address admin) external;
function getEmergencyAdmin() external view returns (address);
function setEmergencyAdmin(address admin) external;
function getPriceOracle() external view returns (address);
function setPriceOracle(address priceOracle) external;
function getLendingRateOracle() external view returns (address);
function setLendingRateOracle(address lendingRateOracle) external;
function getLiquidationFeeTo() external view returns (address);
function setLiquidationFeeTo(address liquidationFeeTo) external;
}// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.12;
pragma experimental ABIEncoderV2;
interface ILeverager {
function wethToZap(address user) external view returns (uint256);
function zapWETHWithBorrow(uint256 amount, address borrower) external returns (uint256 liquidity);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.12;
import "./LockedBalance.sol";
import {IFeeDistribution} from "./IMultiFeeDistribution.sol";
interface IMiddleFeeDistribution is IFeeDistribution {
function forwardReward(address[] memory _rewardTokens) external;
function getRdntTokenAddress() external view returns (address);
function getMultiFeeDistributionAddress() external view returns (address);
function operationExpenseRatio() external view returns (uint256);
function operationExpenses() external view returns (address);
function isRewardToken(address) external view returns (bool);
}// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.12;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IMintableToken is IERC20 {
function mint(address _receiver, uint256 _amount) external returns (bool);
function burn(uint256 _amount) external returns (bool);
function setMinter(address _minter) external returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.12;
import "./LockedBalance.sol";
import "./IFeeDistribution.sol";
import "./IMintableToken.sol";
interface IMultiFeeDistribution is IFeeDistribution {
function exit(bool claimRewards) external;
function stake(uint256 amount, address onBehalfOf, uint256 typeIndex) external;
function rdntToken() external view returns (IMintableToken);
function getPriceProvider() external view returns (address);
function lockInfo(address user) external view returns (LockedBalance[] memory);
function autocompoundDisabled(address user) external view returns (bool);
function defaultLockIndex(address _user) external view returns (uint256);
function autoRelockDisabled(address user) external view returns (bool);
function totalBalance(address user) external view returns (uint256);
function lockedBalance(address user) external view returns (uint256);
function lockedBalances(
address user
) external view returns (uint256, uint256, uint256, uint256, LockedBalance[] memory);
function getBalances(address _user) external view returns (Balances memory);
function zapVestingToLp(address _address) external returns (uint256);
function claimableRewards(address account) external view returns (IFeeDistribution.RewardData[] memory rewards);
function setDefaultRelockTypeIndex(uint256 _index) external;
function daoTreasury() external view returns (address);
function stakingToken() external view returns (address);
function userSlippage(address) external view returns (uint256);
function claimFromConverter(address) external;
function vestTokens(address user, uint256 amount, bool withPenalty) external;
}
interface IMFDPlus is IMultiFeeDistribution {
function getLastClaimTime(address _user) external returns (uint256);
function claimBounty(address _user, bool _execute) external returns (bool issueBaseBounty);
function claimCompound(address _user, bool _execute, uint256 _slippage) external returns (uint256 bountyAmt);
function setAutocompound(bool state, uint256 slippage) external;
function setUserSlippage(uint256 slippage) external;
function toggleAutocompound() external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.12;
interface IOnwardIncentivesController {
function handleAction(address _token, address _user, uint256 _balance, uint256 _totalSupply) external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.12;
interface IPriceProvider {
function getTokenPrice() external view returns (uint256);
function getTokenPriceUsd() external view returns (uint256);
function getLpTokenPrice() external view returns (uint256);
function getLpTokenPriceUsd() external view returns (uint256);
function decimals() external view returns (uint256);
function update() external;
function baseAssetChainlinkAdapter() external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.12;
struct LockedBalance {
uint256 amount;
uint256 unlockTime;
uint256 multiplier;
uint256 duration;
}
struct EarnedBalance {
uint256 amount;
uint256 unlockTime;
uint256 penalty;
}
struct Reward {
uint256 periodFinish;
uint256 rewardPerSecond;
uint256 lastUpdateTime;
uint256 rewardPerTokenStored;
// tracks already-added balances to handle accrued interest in aToken rewards
// for the stakingToken this value is unused and will always be 0
uint256 balance;
}
struct Balances {
uint256 total; // sum of earnings and lockings; no use when LP and RDNT is different
uint256 unlocked; // RDNT token
uint256 locked; // LP token or RDNT token
uint256 lockedWithMultiplier; // Multiplied locked amount
uint256 earned; // RDNT token
}// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.12;
library DataTypes {
// refer to the whitepaper, section 1.1 basic concepts for a formal description of these properties.
struct ReserveData {
//stores the reserve configuration
ReserveConfigurationMap configuration;
//the liquidity index. Expressed in ray
uint128 liquidityIndex;
//variable borrow index. Expressed in ray
uint128 variableBorrowIndex;
//the current supply rate. Expressed in ray
uint128 currentLiquidityRate;
//the current variable borrow rate. Expressed in ray
uint128 currentVariableBorrowRate;
//the current stable borrow rate. Expressed in ray
uint128 currentStableBorrowRate;
uint40 lastUpdateTimestamp;
//tokens addresses
address aTokenAddress;
address stableDebtTokenAddress;
address variableDebtTokenAddress;
//address of the interest rate strategy
address interestRateStrategyAddress;
//the id of the reserve. Represents the position in the list of the active reserves
uint8 id;
}
struct ReserveConfigurationMap {
//bit 0-15: LTV
//bit 16-31: Liq. threshold
//bit 32-47: Liq. bonus
//bit 48-55: Decimals
//bit 56: Reserve is active
//bit 57: reserve is frozen
//bit 58: borrowing is enabled
//bit 59: stable rate borrowing enabled
//bit 60-63: reserved
//bit 64-79: reserve factor
///@custom:borrow-and-supply-caps
//bit 80-115 borrow cap in whole tokens, borrowCap == 0 => no cap
//bit 116-151 supply cap in whole tokens, supplyCap == 0 => no cap
uint256 data;
}
struct UserConfigurationMap {
uint256 data;
}
enum InterestRateMode {
NONE,
STABLE,
VARIABLE
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.12;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
/// @title RecoverERC20 contract
/// @author Radiant Devs
/// @dev All function calls are currently implemented without side effects
contract RecoverERC20 {
using SafeERC20 for IERC20;
/// @notice Emitted when ERC20 token is recovered
event Recovered(address indexed token, uint256 amount);
/**
* @notice Added to support recovering LP Rewards from other systems such as BAL to be distributed to holders
*/
function _recoverERC20(address tokenAddress, uint256 tokenAmount) internal {
IERC20(tokenAddress).safeTransfer(msg.sender, tokenAmount);
emit Recovered(tokenAddress, tokenAmount);
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.12;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import {RecoverERC20} from "../libraries/RecoverERC20.sol";
import {IMultiFeeDistribution} from "../../interfaces/IMultiFeeDistribution.sol";
import {IEligibilityDataProvider} from "../../interfaces/IEligibilityDataProvider.sol";
import {IOnwardIncentivesController} from "../../interfaces/IOnwardIncentivesController.sol";
import {IMiddleFeeDistribution} from "../../interfaces/IMiddleFeeDistribution.sol";
import {ILeverager} from "../../interfaces/ILeverager.sol";
/// @title ChefIncentivesController Contract
/// @author Radiant
/// based on the Sushi MasterChef
/// https://github.com/sushiswap/sushiswap/blob/master/contracts/MasterChef.sol
contract ChefIncentivesController is Initializable, PausableUpgradeable, OwnableUpgradeable, RecoverERC20 {
using SafeERC20 for IERC20;
// Info of each user.
// reward = user.`amount` * pool.`accRewardPerShare` - `rewardDebt`
struct UserInfo {
uint256 amount;
uint256 rewardDebt;
uint256 enterTime; // legacy value, kept to retain storage structure of userInfo array.
uint256 lastClaimTime;
}
// Info of each pool.
struct PoolInfo {
uint256 totalSupply;
uint256 allocPoint; // How many allocation points assigned to this pool.
uint256 lastRewardTime; // Last second that reward distribution occurs.
uint256 accRewardPerShare; // Accumulated rewards per share, times ACC_REWARD_PRECISION. See below.
IOnwardIncentivesController onwardIncentives;
}
// Info about token emissions for a given time period.
struct EmissionPoint {
uint128 startTimeOffset;
uint128 rewardsPerSecond;
}
// Info about ending time of reward emissions
struct EndingTime {
uint256 estimatedTime;
uint256 lastUpdatedTime;
uint256 updateCadence;
}
/********************** Events ***********************/
// Emitted when rewardPerSecond is updated
event RewardsPerSecondUpdated(uint256 indexed rewardsPerSecond, bool persist);
event BalanceUpdated(address indexed token, address indexed user, uint256 balance, uint256 totalSupply);
event EmissionScheduleAppended(uint256[] startTimeOffsets, uint256[] rewardsPerSeconds);
event ChefReserveLow(uint256 indexed _balance);
event Disqualified(address indexed user);
event OnwardIncentivesUpdated(address indexed _token, IOnwardIncentivesController _incentives);
event BountyManagerUpdated(address indexed _bountyManager);
event EligibilityEnabledUpdated(bool indexed _newVal);
event BatchAllocPointsUpdated(address[] _tokens, uint256[] _allocPoints);
event AuthorizedContractUpdated(address _contract, bool _authorized);
event EndingTimeUpdateCadence(uint256 indexed _lapse);
event RewardDeposit(uint256 indexed _amount);
/********************** Errors ***********************/
error AddressZero();
error UnknownPool();
error PoolExists();
error AlreadyStarted();
error NotAllowed();
error ArrayLengthMismatch();
error NotAscending();
error ExceedsMaxInt();
error InvalidStart();
error InvalidRToken();
error InsufficientPermission();
error AuthorizationAlreadySet();
error NotMFD();
error BountyOnly();
error NotEligible();
error CadenceTooLong();
error NotRTokenOrMfd();
error OutOfRewards();
error NothingToVest();
error DuplicateSchedule();
// multiplier for reward calc
uint256 private constant ACC_REWARD_PRECISION = 1e12;
// Data about the future reward rates. emissionSchedule stored in chronological order,
// whenever the duration since the start timestamp exceeds the next timestamp offset a new
// reward rate is applied.
EmissionPoint[] public emissionSchedule;
// If true, keep this new reward rate indefinitely
// If false, keep this reward rate until the next scheduled block offset, then return to the schedule.
bool public persistRewardsPerSecond;
/********************** Emission Info ***********************/
// Array of tokens for reward
address[] public registeredTokens;
// Current reward per second
uint256 public rewardsPerSecond;
// last RPS, used during refill after reserve empty
uint256 public lastRPS;
// Index in emission schedule which the last rewardsPerSeconds was used
// only used for scheduled rewards
uint256 public emissionScheduleIndex;
// Info of each pool.
mapping(address => PoolInfo) public poolInfo;
mapping(address => bool) private validRTokens;
// Total allocation points. Must be the sum of all allocation points in all pools.
uint256 public totalAllocPoint;
// token => user => Info of each user that stakes LP tokens.
mapping(address => mapping(address => UserInfo)) public userInfo;
// user => base claimable balance
mapping(address => uint256) public userBaseClaimable;
// MFD, bounties, AC, middlefee
mapping(address => bool) public eligibilityExempt;
// The block number when reward mining starts.
uint256 public startTime;
// Option for eligibility
bool public eligibilityEnabled;
// Address for PoolConfigurator
address public poolConfigurator;
// Amount of deposited rewards
uint256 public depositedRewards;
// Amount of accumulated rewards
uint256 public accountedRewards;
// Timestamp when all pools updated
uint256 public lastAllPoolUpdate;
// Middle Fee Distribution contract
IMiddleFeeDistribution public rewardMinter;
// Eligiblity Data Provider contract
IEligibilityDataProvider public eligibleDataProvider;
// Bounty Manager contract
address public bountyManager;
// Info of reward emission end time
EndingTime public endingTime;
// Contracts that are authorized to handle r/vdToken actions without triggering elgiibility checks
mapping(address => bool) public authorizedContracts;
/**
* @notice Initializer
* @param _poolConfigurator Pool configurator address
* @param _eligibleDataProvider Eligibility Data provider address
* @param _rewardMinter Middle fee distribution contract
* @param _rewardsPerSecond RPS
*/
function initialize(
address _poolConfigurator,
IEligibilityDataProvider _eligibleDataProvider,
IMiddleFeeDistribution _rewardMinter,
uint256 _rewardsPerSecond
) public initializer {
if (_poolConfigurator == address(0)) revert AddressZero();
if (address(_eligibleDataProvider) == address(0)) revert AddressZero();
if (address(_rewardMinter) == address(0)) revert AddressZero();
__Ownable_init();
__Pausable_init();
poolConfigurator = _poolConfigurator;
eligibleDataProvider = _eligibleDataProvider;
rewardMinter = _rewardMinter;
rewardsPerSecond = _rewardsPerSecond;
persistRewardsPerSecond = true;
eligibilityEnabled = true;
}
/**
* @dev Returns length of reward pools.
*/
function poolLength() public view returns (uint256) {
return registeredTokens.length;
}
/**
* @dev Returns address of MFD.
* @return mfd contract address
*/
function _getMfd() internal view returns (IMultiFeeDistribution mfd) {
address multiFeeDistribution = rewardMinter.getMultiFeeDistributionAddress();
mfd = IMultiFeeDistribution(multiFeeDistribution);
}
/**
* @notice Sets incentive controllers for custom token.
* @param _token for reward pool
* @param _incentives incentives contract address
*/
function setOnwardIncentives(address _token, IOnwardIncentivesController _incentives) external onlyOwner {
PoolInfo storage pool = poolInfo[_token];
if (pool.lastRewardTime == 0) revert UnknownPool();
pool.onwardIncentives = _incentives;
emit OnwardIncentivesUpdated(_token, _incentives);
}
/**
* @dev Updates bounty manager contract.
* @param _bountyManager Bounty Manager contract.
*/
function setBountyManager(address _bountyManager) external onlyOwner {
bountyManager = _bountyManager;
emit BountyManagerUpdated(_bountyManager);
}
/**
* @dev Enable/Disable eligibility
* @param _newVal New value.
*/
function setEligibilityEnabled(bool _newVal) external onlyOwner {
eligibilityEnabled = _newVal;
emit EligibilityEnabledUpdated(_newVal);
}
/********************** Pool Setup + Admin ***********************/
/**
* @dev Starts RDNT emission.
*/
function start() public onlyOwner {
if (startTime != 0) revert AlreadyStarted();
startTime = block.timestamp;
}
/**
* @dev Add a new lp to the pool. Can only be called by the poolConfigurator.
* @param _token for reward pool
* @param _allocPoint allocation point of the pool
*/
function addPool(address _token, uint256 _allocPoint) external {
if (msg.sender != poolConfigurator && msg.sender != owner()) revert NotAllowed();
if (poolInfo[_token].lastRewardTime != 0) revert PoolExists();
_updateEmissions();
totalAllocPoint = totalAllocPoint + _allocPoint;
registeredTokens.push(_token);
PoolInfo storage pool = poolInfo[_token];
pool.allocPoint = _allocPoint;
pool.lastRewardTime = block.timestamp;
pool.onwardIncentives = IOnwardIncentivesController(address(0));
validRTokens[_token] = true;
}
/**
* @dev Update the given pool's allocation point. Can only be called by the owner.
* @param _tokens for reward pools
* @param _allocPoints allocation points of the pools
*/
function batchUpdateAllocPoint(address[] calldata _tokens, uint256[] calldata _allocPoints) external onlyOwner {
if (_tokens.length != _allocPoints.length) revert ArrayLengthMismatch();
_massUpdatePools();
uint256 _totalAllocPoint = totalAllocPoint;
uint256 length = _tokens.length;
for (uint256 i; i < length; ) {
PoolInfo storage pool = poolInfo[_tokens[i]];
if (pool.lastRewardTime == 0) revert UnknownPool();
_totalAllocPoint = _totalAllocPoint - pool.allocPoint + _allocPoints[i];
pool.allocPoint = _allocPoints[i];
unchecked {
i++;
}
}
totalAllocPoint = _totalAllocPoint;
emit BatchAllocPointsUpdated(_tokens, _allocPoints);
}
/**
* @notice Sets the reward per second to be distributed. Can only be called by the owner.
* @dev Its decimals count is ACC_REWARD_PRECISION
* @param _rewardsPerSecond The amount of reward to be distributed per second.
* @param _persist true if RPS is fixed, otherwise RPS is by emission schedule.
*/
function setRewardsPerSecond(uint256 _rewardsPerSecond, bool _persist) external onlyOwner {
_massUpdatePools();
rewardsPerSecond = _rewardsPerSecond;
persistRewardsPerSecond = _persist;
emit RewardsPerSecondUpdated(_rewardsPerSecond, _persist);
}
/**
* @dev Updates RPS.
*/
function setScheduledRewardsPerSecond() internal {
if (!persistRewardsPerSecond) {
uint256 length = emissionSchedule.length;
uint256 i = emissionScheduleIndex;
uint128 offset = uint128(block.timestamp - startTime);
for (; i < length && offset >= emissionSchedule[i].startTimeOffset; ) {
unchecked {
i++;
}
}
if (i > emissionScheduleIndex) {
emissionScheduleIndex = i;
_massUpdatePools();
rewardsPerSecond = uint256(emissionSchedule[i - 1].rewardsPerSecond);
}
}
}
/**
* @notice Ensure that the specified time offset hasn't been registered already.
* @param _startTimeOffset time offset
* @return true if the specified time offset is already registered
*/
function _checkDuplicateSchedule(uint256 _startTimeOffset) internal view returns (bool) {
uint256 length = emissionSchedule.length;
for (uint256 i = 0; i < length; ) {
if (emissionSchedule[i].startTimeOffset == _startTimeOffset) {
return true;
}
unchecked {
i++;
}
}
return false;
}
/**
* @notice Updates RDNT emission schedule.
* @dev This appends the new offsets and RPS.
* @param _startTimeOffsets Offsets array.
* @param _rewardsPerSecond RPS array.
*/
function setEmissionSchedule(
uint256[] calldata _startTimeOffsets,
uint256[] calldata _rewardsPerSecond
) external onlyOwner {
uint256 length = _startTimeOffsets.length;
if (length <= 0 || length != _rewardsPerSecond.length) revert ArrayLengthMismatch();
for (uint256 i = 0; i < length; ) {
if (i > 0) {
if (_startTimeOffsets[i - 1] > _startTimeOffsets[i]) revert NotAscending();
}
if (_startTimeOffsets[i] > type(uint128).max) revert ExceedsMaxInt();
if (_rewardsPerSecond[i] > type(uint128).max) revert ExceedsMaxInt();
if (_checkDuplicateSchedule(_startTimeOffsets[i])) revert DuplicateSchedule();
if (startTime > 0) {
if (_startTimeOffsets[i] < block.timestamp - startTime) revert InvalidStart();
}
emissionSchedule.push(
EmissionPoint({
startTimeOffset: uint128(_startTimeOffsets[i]),
rewardsPerSecond: uint128(_rewardsPerSecond[i])
})
);
unchecked {
i++;
}
}
emit EmissionScheduleAppended(_startTimeOffsets, _rewardsPerSecond);
}
/**
* @notice Recover tokens in this contract. Callable by owner.
* @param tokenAddress Token address for recover
* @param tokenAmount Amount to recover
*/
function recoverERC20(address tokenAddress, uint256 tokenAmount) external onlyOwner {
_recoverERC20(tokenAddress, tokenAmount);
}
/********************** Pool State Changers ***********************/
/**
* @dev Update emission params of CIC.
*/
function _updateEmissions() internal {
if (block.timestamp > endRewardTime()) {
_massUpdatePools();
lastRPS = rewardsPerSecond;
rewardsPerSecond = 0;
return;
}
setScheduledRewardsPerSecond();
}
/**
* @dev Update reward variables for all pools.
*/
function _massUpdatePools() internal {
uint256 totalAP = totalAllocPoint;
uint256 length = poolLength();
for (uint256 i; i < length; ) {
_updatePool(poolInfo[registeredTokens[i]], totalAP);
unchecked {
i++;
}
}
lastAllPoolUpdate = block.timestamp;
}
/**
* @dev Update reward variables of the given pool to be up-to-date.
* @param pool pool info
* @param _totalAllocPoint allocation point of the pool
*/
function _updatePool(PoolInfo storage pool, uint256 _totalAllocPoint) internal {
uint256 timestamp = block.timestamp;
uint256 endReward = endRewardTime();
if (endReward <= timestamp) {
timestamp = endReward;
}
if (timestamp <= pool.lastRewardTime) {
return;
}
(uint256 reward, uint256 newAccRewardPerShare) = _newRewards(pool, _totalAllocPoint);
accountedRewards = accountedRewards + reward;
pool.accRewardPerShare = pool.accRewardPerShare + newAccRewardPerShare;
pool.lastRewardTime = timestamp;
}
/********************** Emission Calc + Transfer ***********************/
/**
* @notice Pending rewards of a user.
* @param _user address for claim
* @param _tokens array of reward-bearing tokens
* @return claimable rewards array
*/
function pendingRewards(address _user, address[] memory _tokens) public view returns (uint256[] memory) {
uint256[] memory claimable = new uint256[](_tokens.length);
uint256 length = _tokens.length;
for (uint256 i; i < length; ) {
address token = _tokens[i];
PoolInfo storage pool = poolInfo[token];
UserInfo storage user = userInfo[token][_user];
uint256 accRewardPerShare = pool.accRewardPerShare;
if (block.timestamp > pool.lastRewardTime) {
(, uint256 newAccRewardPerShare) = _newRewards(pool, totalAllocPoint);
accRewardPerShare = accRewardPerShare + newAccRewardPerShare;
}
claimable[i] = (user.amount * accRewardPerShare) / ACC_REWARD_PRECISION - user.rewardDebt;
unchecked {
i++;
}
}
return claimable;
}
/**
* @notice Claim rewards. They are vested into MFD.
* @param _user address for claim
* @param _tokens array of reward-bearing tokens
*/
function claim(address _user, address[] memory _tokens) public whenNotPaused {
if (eligibilityEnabled) {
checkAndProcessEligibility(_user, true, true);
}
_updateEmissions();
uint256 currentTimestamp = block.timestamp;
uint256 pending = userBaseClaimable[_user];
userBaseClaimable[_user] = 0;
uint256 _totalAllocPoint = totalAllocPoint;
uint256 length = _tokens.length;
for (uint256 i; i < length; ) {
if (!validRTokens[_tokens[i]]) revert InvalidRToken();
PoolInfo storage pool = poolInfo[_tokens[i]];
if (pool.lastRewardTime == 0) revert UnknownPool();
_updatePool(pool, _totalAllocPoint);
UserInfo storage user = userInfo[_tokens[i]][_user];
uint256 rewardDebt = (user.amount * pool.accRewardPerShare) / ACC_REWARD_PRECISION;
pending = pending + rewardDebt - user.rewardDebt;
user.rewardDebt = rewardDebt;
user.lastClaimTime = currentTimestamp;
unchecked {
i++;
}
}
_vestTokens(_user, pending);
eligibleDataProvider.updatePrice();
if (endRewardTime() < currentTimestamp + 5 days) {
address rdntToken = rewardMinter.getRdntTokenAddress();
emit ChefReserveLow(IERC20(rdntToken).balanceOf(address(this)));
}
}
/**
* @notice Vest tokens to MFD.
* @param _user address to receive
* @param _amount to vest
*/
function _vestTokens(address _user, uint256 _amount) internal {
if (_amount == 0) revert NothingToVest();
IMultiFeeDistribution mfd = _getMfd();
_sendRadiant(address(mfd), _amount);
mfd.vestTokens(_user, _amount, true);
}
/**
* @notice Exempt a contract from eligibility check.
* @dev Can be called by owner or authorized contracts
* @param _contract address to exempt
* @param _value flag for exempt
*/
function setEligibilityExempt(address _contract, bool _value) public {
if (msg.sender != owner() && !authorizedContracts[msg.sender]) revert InsufficientPermission();
eligibilityExempt[_contract] = _value;
}
/**
* @notice Updates whether the provided address is authorized to call setEligibilityExempt(), only callable by owner.
* @param _address address of the user or contract whose authorization level is being changed
*/
function setContractAuthorization(address _address, bool _authorize) external onlyOwner {
if (authorizedContracts[_address] == _authorize) revert AuthorizationAlreadySet();
authorizedContracts[_address] = _authorize;
emit AuthorizedContractUpdated(_address, _authorize);
}
/********************** Eligibility + Disqualification ***********************/
/**
* @notice `after` Hook for deposit and borrow update.
* @dev important! eligible status can be updated here
* @param _user address
* @param _balance balance of token
* @param _totalSupply total supply of the token
*/
function handleActionAfter(address _user, uint256 _balance, uint256 _totalSupply) external {
if (!validRTokens[msg.sender] && msg.sender != address(_getMfd())) revert NotRTokenOrMfd();
if (_user == address(rewardMinter) || _user == address(_getMfd()) || eligibilityExempt[_user]) {
return;
}
if (eligibilityEnabled) {
bool lastEligibleStatus = eligibleDataProvider.lastEligibleStatus(_user);
bool isCurrentlyEligible = eligibleDataProvider.refresh(_user);
if (isCurrentlyEligible) {
if (lastEligibleStatus) {
_handleActionAfterForToken(msg.sender, _user, _balance, _totalSupply);
} else {
_updateRegisteredBalance(_user);
}
} else {
_processEligibility(_user, isCurrentlyEligible, true);
}
} else {
_handleActionAfterForToken(msg.sender, _user, _balance, _totalSupply);
}
}
/**
* @notice `after` Hook for deposit and borrow update.
* @dev important! eligible status can be updated here
* @param _token address
* @param _user address
* @param _balance new amount
* @param _totalSupply total supply of the token
*/
function _handleActionAfterForToken(
address _token,
address _user,
uint256 _balance,
uint256 _totalSupply
) internal {
PoolInfo storage pool = poolInfo[_token];
if (pool.lastRewardTime == 0) revert UnknownPool();
// Although we would want the pools to be as up to date as possible when users
// transfer rTokens or dTokens, updating all pools on every r-/d-Token interaction would be too gas intensive.
// _updateEmissions();
_updatePool(pool, totalAllocPoint);
UserInfo storage user = userInfo[_token][_user];
uint256 amount = user.amount;
uint256 accRewardPerShare = pool.accRewardPerShare;
if (amount != 0) {
uint256 pending = (amount * accRewardPerShare) / ACC_REWARD_PRECISION - user.rewardDebt;
if (pending != 0) {
userBaseClaimable[_user] = userBaseClaimable[_user] + pending;
}
}
pool.totalSupply = pool.totalSupply - user.amount;
user.amount = _balance;
user.rewardDebt = (_balance * accRewardPerShare) / ACC_REWARD_PRECISION;
pool.totalSupply = pool.totalSupply + _balance;
if (pool.onwardIncentives != IOnwardIncentivesController(address(0))) {
pool.onwardIncentives.handleAction(_token, _user, _balance, _totalSupply);
}
emit BalanceUpdated(_token, _user, _balance, _totalSupply);
}
/**
* @notice `before` Hook for deposit and borrow update.
* @param _user address
*/
function handleActionBefore(address _user) external {}
/**
* @notice Hook for lock update.
* @dev Called by the locking contracts before locking or unlocking happens
* @param _user address
*/
function beforeLockUpdate(address _user) external {}
/**
* @notice Hook for lock update.
* @dev Called by the locking contracts after locking or unlocking happens
* @param _user address
*/
function afterLockUpdate(address _user) external {
if (msg.sender != address(_getMfd())) revert NotMFD();
if (eligibilityEnabled) {
bool isCurrentlyEligible = eligibleDataProvider.refresh(_user);
if (isCurrentlyEligible) {
_updateRegisteredBalance(_user);
} else {
_processEligibility(_user, isCurrentlyEligible, true);
}
}
}
/**
* @notice Update balance if there are any unregistered.
* @param _user address of the user whose balances will be updated
*/
function _updateRegisteredBalance(address _user) internal {
uint256 length = poolLength();
for (uint256 i; i < length; ) {
uint256 newBal = IERC20(registeredTokens[i]).balanceOf(_user);
uint256 registeredBal = userInfo[registeredTokens[i]][_user].amount;
if (newBal != 0 && newBal != registeredBal) {
_handleActionAfterForToken(
registeredTokens[i],
_user,
newBal,
poolInfo[registeredTokens[i]].totalSupply + newBal - registeredBal
);
}
unchecked {
i++;
}
}
}
/********************** Eligibility + Disqualification ***********************/
/**
* @dev Returns true if `_user` has some reward eligible tokens.
* @param _user address of recipient
*/
function hasEligibleDeposits(address _user) internal view returns (bool hasDeposits) {
uint256 length = poolLength();
for (uint256 i; i < length; ) {
if (userInfo[registeredTokens[i]][_user].amount != 0) {
hasDeposits = true;
break;
}
unchecked {
i++;
}
}
}
/**
* @dev Stop emissions if there's any new DQ.
* @param _user address of recipient
* @param _isEligible user's eligible status
* @param _execute true if it's actual execution
* @return issueBaseBounty true for base bounty
*/
function _processEligibility(
address _user,
bool _isEligible,
bool _execute
) internal returns (bool issueBaseBounty) {
bool hasEligDeposits = hasEligibleDeposits(_user);
uint256 lastDqTime = eligibleDataProvider.getDqTime(_user);
bool alreadyDqd = lastDqTime != 0;
if (!_isEligible && hasEligDeposits && !alreadyDqd) {
issueBaseBounty = true;
}
if (_execute && issueBaseBounty) {
stopEmissionsFor(_user);
emit Disqualified(_user);
}
}
/**
* @notice Check eligibility of the user
* @dev Stop emissions if there's any DQ.
* @param _user address of recipient
* @param _execute true if it's actual execution
* @param _refresh true if needs to refresh user's eligible status
* @return issueBaseBounty true for base bounty
*/
function checkAndProcessEligibility(
address _user,
bool _execute,
bool _refresh
) internal returns (bool issueBaseBounty) {
bool isEligible;
if (_refresh && _execute) {
isEligible = eligibleDataProvider.refresh(_user);
} else {
isEligible = eligibleDataProvider.isEligibleForRewards(_user);
}
issueBaseBounty = _processEligibility(_user, isEligible, _execute);
}
/**
* @notice Claim bounty
* @param _user address of recipient
* @param _execute true if it's actual execution
* @return issueBaseBounty true for base bounty
*/
function claimBounty(address _user, bool _execute) public returns (bool issueBaseBounty) {
if (msg.sender != address(bountyManager)) revert BountyOnly();
issueBaseBounty = checkAndProcessEligibility(_user, _execute, true);
}
/**
* @dev Stop RDNT emissions for specific users
* @param _user address of recipient
*/
function stopEmissionsFor(address _user) internal {
if (!eligibilityEnabled) revert NotEligible();
// lastEligibleStatus will be fresh from refresh before this call
uint256 length = poolLength();
for (uint256 i; i < length; ) {
address token = registeredTokens[i];
PoolInfo storage pool = poolInfo[token];
UserInfo storage user = userInfo[token][_user];
if (user.amount != 0) {
_handleActionAfterForToken(token, _user, 0, pool.totalSupply - user.amount);
}
unchecked {
i++;
}
}
eligibleDataProvider.setDqTime(_user, block.timestamp);
}
/**
* @dev Send RNDT rewards to user.
* @param _user address of recipient
* @param _amount of RDNT
*/
function _sendRadiant(address _user, uint256 _amount) internal {
if (_amount == 0) {
return;
}
address rdntToken = rewardMinter.getRdntTokenAddress();
uint256 chefReserve = IERC20(rdntToken).balanceOf(address(this));
if (_amount > chefReserve) {
revert OutOfRewards();
} else {
IERC20(rdntToken).safeTransfer(_user, _amount);
}
}
/********************** RDNT Reserve Management ***********************/
/**
* @notice Ending reward distribution time.
*/
function endRewardTime() public returns (uint256) {
uint256 unclaimedRewards = availableRewards();
uint256 extra = 0;
uint256 length = poolLength();
for (uint256 i; i < length; ) {
PoolInfo storage pool = poolInfo[registeredTokens[i]];
if (pool.lastRewardTime > lastAllPoolUpdate) {
extra +=
((pool.lastRewardTime - lastAllPoolUpdate) * pool.allocPoint * rewardsPerSecond) /
totalAllocPoint;
}
unchecked {
i++;
}
}
endingTime.lastUpdatedTime = block.timestamp;
if (rewardsPerSecond == 0) {
endingTime.estimatedTime = type(uint256).max;
} else {
endingTime.estimatedTime = (unclaimedRewards + extra) / rewardsPerSecond + lastAllPoolUpdate;
}
return endingTime.estimatedTime;
}
/**
* @notice Updates cadence duration of ending time.
* @dev Only callable by owner.
* @param _lapse new cadence
*/
function setEndingTimeUpdateCadence(uint256 _lapse) external onlyOwner {
if (_lapse > 1 weeks) revert CadenceTooLong();
endingTime.updateCadence = _lapse;
emit EndingTimeUpdateCadence(_lapse);
}
/**
* @notice Add new rewards.
* @dev Only callable by owner.
* @param _amount new deposit amount
*/
function registerRewardDeposit(uint256 _amount) external onlyOwner {
depositedRewards = depositedRewards + _amount;
_massUpdatePools();
if (rewardsPerSecond == 0 && lastRPS > 0) {
rewardsPerSecond = lastRPS;
}
emit RewardDeposit(_amount);
}
/**
* @notice Available reward amount for future distribution.
* @dev This value is equal to `depositedRewards` - `accountedRewards`.
* @return amount available
*/
function availableRewards() internal view returns (uint256 amount) {
return depositedRewards - accountedRewards;
}
/**
* @notice Claim rewards entitled to all registered tokens.
* @param _user address of the user
*/
function claimAll(address _user) external {
claim(_user, registeredTokens);
}
/**
* @notice Sum of all pending RDNT rewards.
* @param _user address of the user
* @return pending reward amount
*/
function allPendingRewards(address _user) public view returns (uint256 pending) {
pending = userBaseClaimable[_user];
uint256[] memory claimable = pendingRewards(_user, registeredTokens);
uint256 length = claimable.length;
for (uint256 i; i < length; ) {
pending += claimable[i];
unchecked {
i++;
}
}
}
/**
* @notice Pause the claim operations.
*/
function pause() external onlyOwner {
_pause();
}
/**
* @notice Unpause the claim operations.
*/
function unpause() external onlyOwner {
_unpause();
}
/**
* @dev Returns new rewards since last reward time.
* @param pool pool info
* @param _totalAllocPoint allocation point of the pool
*/
function _newRewards(
PoolInfo memory pool,
uint256 _totalAllocPoint
) internal view returns (uint256 newReward, uint256 newAccRewardPerShare) {
uint256 lpSupply = pool.totalSupply;
if (lpSupply > 0) {
uint256 duration = block.timestamp - pool.lastRewardTime;
uint256 rawReward = duration * rewardsPerSecond;
uint256 rewards = availableRewards();
if (rewards < rawReward) {
rawReward = rewards;
}
newReward = (rawReward * pool.allocPoint) / _totalAllocPoint;
newAccRewardPerShare = (newReward * ACC_REWARD_PRECISION) / lpSupply;
}
}
}{
"optimizer": {
"enabled": true,
"runs": 999999,
"details": {
"yul": true
}
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"metadata": {
"useLiteralContent": true
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AddressZero","type":"error"},{"inputs":[],"name":"InvalidRatio","type":"error"},{"inputs":[],"name":"LPTokenSet","type":"error"},{"inputs":[],"name":"MissingEligibleLendingPools","type":"error"},{"inputs":[],"name":"OnlyCIC","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract ChefIncentivesController","name":"_chef","type":"address"}],"name":"ChefIncentivesControllerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":false,"internalType":"uint256","name":"_time","type":"uint256"}],"name":"DqTimeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract ILendingPool[]","name":"eligibleRizLendingPools","type":"address[]"}],"name":"EligibleRizLendingPoolsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_lpToken","type":"address"}],"name":"LPTokenUpdated","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":"uint256","name":"priceToleranceRatio","type":"uint256"}],"name":"PriceToleranceRatioUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requiredDepositRatio","type":"uint256"}],"name":"RequiredDepositRatioUpdated","type":"event"},{"inputs":[],"name":"INITIAL_PRICE_TOLERANCE_RATIO","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INITIAL_REQUIRED_DEPOSIT_RATIO","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_PRICE_TOLERANCE_RATIO","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RATIO_DIVISOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chef","outputs":[{"internalType":"contract ChefIncentivesController","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"disqualifiedTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getDqTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getEligibleRizLendingPools","outputs":[{"internalType":"contract ILendingPool[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ILendingPool","name":"_lendingPool","type":"address"},{"internalType":"contract IMiddleFeeDistribution","name":"_middleFeeDistribution","type":"address"},{"internalType":"contract IPriceProvider","name":"_priceProvider","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"isEligibleForRewards","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lastEligibleStatus","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"lastEligibleTime","outputs":[{"internalType":"uint256","name":"lastEligibleTimestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lendingPool","outputs":[{"internalType":"contract ILendingPool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"lockedUsdValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lpToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"middleFeeDistribution","outputs":[{"internalType":"contract IMiddleFeeDistribution","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"obsoleteMapping2","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceProvider","outputs":[{"internalType":"contract IPriceProvider","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceToleranceRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"refresh","outputs":[{"internalType":"bool","name":"currentEligibility","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"requiredDepositRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"requiredUsdValue","outputs":[{"internalType":"uint256","name":"required","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ChefIncentivesController","name":"_chef","type":"address"}],"name":"setChefIncentivesController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_time","type":"uint256"}],"name":"setDqTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ILendingPool[]","name":"pools","type":"address[]"}],"name":"setEligibleRizLendingPools","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_lpToken","type":"address"}],"name":"setLPToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_priceToleranceRatio","type":"uint256"}],"name":"setPriceToleranceRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requiredDepositRatio","type":"uint256"}],"name":"setRequiredDepositRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updatePrice","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
608060405234801561001057600080fd5b5061001961001e565b6100dd565b600054610100900460ff161561008a5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff908116146100db576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b611ecc806100ec6000396000f3fe608060405234801561001057600080fd5b50600436106101f05760003560e01c80638da5cb5b1161010f578063c0c53b8b116100a2578063e38fdc3611610071578063e38fdc36146104b1578063f2fde38b146104c4578063f4640c93146104d7578063ff408ae0146104ea57600080fd5b8063c0c53b8b1461046f578063d52874da14610482578063dbbbbc631461048b578063e2c75ca01461049e57600080fd5b8063a59a9973116100de578063a59a997314610413578063ad34250c14610433578063b888879e1461043c578063bae1b24c1461045c57600080fd5b80638da5cb5b146103c3578063a0cfb9ff146103e1578063a26ad44014610401578063a294c5021461040a57600080fd5b80635fcbd285116101875780636a7e9f33116101565780636a7e9f33146103695780636d9077cb146103725780636f21a17914610385578063715018a6146103bb57600080fd5b80635fcbd2851461031b578063660186e61461033b578063673a7e281461034e5780636a678a9c1461035657600080fd5b806351b74d98116101c357806351b74d9814610297578063563014e5146102d05780635de20b42146102e35780635e9016f41461030657600080fd5b80630afb0409146101f55780631fc8bc5d1461021d57806321cc01c91461026257806334419f2014610282575b600080fd5b6102086102033660046118da565b6104f3565b60405190151581526020015b60405180910390f35b60665461023d9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610214565b60675461023d9073ffffffffffffffffffffffffffffffffffffffff1681565b61028a610658565b60405161021491906118f7565b6102c26102a5366004611951565b606f60209081526000928352604080842090915290825290205481565b604051908152602001610214565b6102c26102de3660046118da565b6106c7565b6102086102f13660046118da565b606c6020526000908152604090205460ff1681565b61031961031436600461198a565b6108cf565b005b606b5461023d9073ffffffffffffffffffffffffffffffffffffffff1681565b6102086103493660046118da565b6109fa565b610319610a46565b6103196103643660046118da565b610aca565b6102c261271081565b6102c26103803660046118da565b610bde565b6102c26103933660046118da565b73ffffffffffffffffffffffffffffffffffffffff166000908152606d602052604090205490565b610319610d17565b60335473ffffffffffffffffffffffffffffffffffffffff1661023d565b6102c26103ef3660046118da565b606d6020526000908152604090205481565b6102c26101f481565b6102c2611f4081565b60655461023d9073ffffffffffffffffffffffffffffffffffffffff1681565b6102c261232881565b60685461023d9073ffffffffffffffffffffffffffffffffffffffff1681565b61031961046a3660046119ff565b610d2b565b61031961047d366004611a18565b610dae565b6102c260695481565b6103196104993660046118da565b61109c565b6103196104ac366004611a63565b611160565b6102c26104bf3660046118da565b611217565b6103196104d23660046118da565b6113e3565b6103196104e53660046119ff565b61149a565b6102c2606a5481565b60665460009073ffffffffffffffffffffffffffffffffffffffff163314610547576040517fe50d1fc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216610594576040517f9fabe1c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61059c610a46565b6105a5826109fa565b90508080156105d8575073ffffffffffffffffffffffffffffffffffffffff82166000908152606d602052604090205415155b156106045773ffffffffffffffffffffffffffffffffffffffff82166000908152606d60205260408120555b73ffffffffffffffffffffffffffffffffffffffff919091166000908152606c6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001682151517905590565b606060708054806020026020016040519081016040528092919081815260200182805480156106bd57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610692575b5050505050905090565b60006106d2826109fa565b6106de57506000919050565b60006106e983611217565b90506000606760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663cd57ed6c6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561075a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061077e9190611a8f565b6040517f6bd3b87c00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681166004830152919250600091831690636bd3b87c90602401600060405180830381865afa1580156107f0573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526108369190810190611b53565b80519091506000905b80156108c557600083610853600184611c63565b8151811061086357610863611c7a565b6020026020010151905080600001518361087d9190611ca9565b92508561088984611511565b1061089d5760200151979650505050505050565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0161083f565b5050505050919050565b6108d76115cb565b808061090f576040517f1e3b188d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b818110156109a357600084848381811061092e5761092e611c7a565b905060200201602081019061094391906118da565b73ffffffffffffffffffffffffffffffffffffffff161415610991576040517f9fabe1c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8061099b81611cc1565b915050610912565b506109b0607060006117fd565b6109bc6070848461181b565b507f420e89154023f9446f715f82a1b62633c0d2bd65e9bee3dde81e38691929848860706040516109ed9190611cfa565b60405180910390a1505050565b600080610a0683610bde565b90506000612710606a54610a1986611217565b610a239190611d4b565b610a2d9190611d88565b90508015801590610a3e5750808210155b949350505050565b606860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a2e620456040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610ab057600080fd5b505af1158015610ac4573d6000803e3d6000fd5b50505050565b610ad26115cb565b73ffffffffffffffffffffffffffffffffffffffff8116610b1f576040517f9fabe1c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606b5473ffffffffffffffffffffffffffffffffffffffff1615610b6f576040517f322815a400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517ff9d1c90c609623055381582a51735b38df3243eb09629a9170b15c2ab6bc073990600090a250565b600080606760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663cd57ed6c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c4e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c729190611a8f565b6040517fc84aae1700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff858116600483015291925060009183169063c84aae179060240160a060405180830381865afa158015610ce4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d089190611dc3565b9050610a3e8160400151611511565b610d1f6115cb565b610d29600061164c565b565b610d336115cb565b611f40811080610d44575061271081115b15610d7b576040517f648564d300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606a81905560405181907f05ace3111616a9d7bc7b769e0162c37e277aa5cdcd34699f9a0e3d7577d0db5490600090a250565b600054610100900460ff1615808015610dce5750600054600160ff909116105b80610de85750303b158015610de8575060005460ff166001145b610e79576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015610ed757600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b73ffffffffffffffffffffffffffffffffffffffff8416610f24576040517f9fabe1c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8316610f71576040517f9fabe1c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216610fbe576040517f9fabe1c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6065805473ffffffffffffffffffffffffffffffffffffffff8087167fffffffffffffffffffffffff0000000000000000000000000000000000000000928316179092556067805486841690831617905560688054928516929091169190911790556101f4606955612328606a556110346116c3565b8015610ac457600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150505050565b6110a46115cb565b73ffffffffffffffffffffffffffffffffffffffff81166110f1576040517f9fabe1c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f3edc4c109bdc9b34f00f24744f770e8de831fd903d0fc75d4d990d5d81b75b9890600090a250565b60665473ffffffffffffffffffffffffffffffffffffffff1633146111b1576040517fe50d1fc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82166000818152606d602052604090819020839055517f1e85ba2a5b06819d522e519e6ebf963f35ad4a709dc2a541ed39ad80f4b3a3be9061120b9084815260200190565b60405180910390a25050565b6065546040517fbf92857c00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152600092839291169063bf92857c9060240160c060405180830381865afa15801561128b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112af9190611e33565b505060705493945050821591506113c890505760005b818110156113c6576000607082815481106112e2576112e2611c7a565b6000918252602090912001546040517fbf92857c00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff88811660048301529091169063bf92857c9060240160c060405180830381865afa15801561135b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061137f9190611e33565b505050505090506000670de0b6b3a76400006305f5e100836113a19190611d4b565b6113ab9190611d88565b90506113b78186611ca9565b945082600101925050506112c5565b505b612710606954836113d99190611d4b565b610a3e9190611d88565b6113eb6115cb565b73ffffffffffffffffffffffffffffffffffffffff811661148e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610e70565b6114978161164c565b50565b6114a26115cb565b6127108111156114de576040517f648564d300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606981905560405181907f063aaf80a21dd5cad9d8adcdc5a53acaa3c2de05dc44c7e2f68783a87460d7fe90600090a250565b600080606860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636e9a05c56040518163ffffffff1660e01b8152600401602060405180830381865afa158015611581573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a59190611e7d565b9050670de0b6b3a76400006115ba8285611d4b565b6115c49190611d88565b9392505050565b60335473ffffffffffffffffffffffffffffffffffffffff163314610d29576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610e70565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff1661175a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610e70565b610d29600054610100900460ff166117f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610e70565b610d293361164c565b508054600082559060005260206000209081019061149791906118a3565b828054828255906000526020600020908101928215611893579160200282015b828111156118935781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84351617825560209092019160019091019061183b565b5061189f9291506118a3565b5090565b5b8082111561189f57600081556001016118a4565b73ffffffffffffffffffffffffffffffffffffffff8116811461149757600080fd5b6000602082840312156118ec57600080fd5b81356115c4816118b8565b6020808252825182820181905260009190848201906040850190845b8181101561194557835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101611913565b50909695505050505050565b6000806040838503121561196457600080fd5b823561196f816118b8565b9150602083013561197f816118b8565b809150509250929050565b6000806020838503121561199d57600080fd5b823567ffffffffffffffff808211156119b557600080fd5b818501915085601f8301126119c957600080fd5b8135818111156119d857600080fd5b8660208260051b85010111156119ed57600080fd5b60209290920196919550909350505050565b600060208284031215611a1157600080fd5b5035919050565b600080600060608486031215611a2d57600080fd5b8335611a38816118b8565b92506020840135611a48816118b8565b91506040840135611a58816118b8565b809150509250925092565b60008060408385031215611a7657600080fd5b8235611a81816118b8565b946020939093013593505050565b600060208284031215611aa157600080fd5b81516115c4816118b8565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516080810167ffffffffffffffff81118282101715611afe57611afe611aac565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611b4b57611b4b611aac565b604052919050565b60006020808385031215611b6657600080fd5b825167ffffffffffffffff80821115611b7e57600080fd5b818501915085601f830112611b9257600080fd5b815181811115611ba457611ba4611aac565b611bb2848260051b01611b04565b818152848101925060079190911b830184019087821115611bd257600080fd5b928401925b81841015611c295760808489031215611bf05760008081fd5b611bf8611adb565b8451815285850151868201526040808601519082015260608086015190820152835260809093019291840191611bd7565b979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015611c7557611c75611c34565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008219821115611cbc57611cbc611c34565b500190565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415611cf357611cf3611c34565b5060010190565b6020808252825482820181905260008481528281209092916040850190845b8181101561194557835473ffffffffffffffffffffffffffffffffffffffff1683526001938401939285019201611d19565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615611d8357611d83611c34565b500290565b600082611dbe577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b600060a08284031215611dd557600080fd5b60405160a0810181811067ffffffffffffffff82111715611df857611df8611aac565b806040525082518152602083015160208201526040830151604082015260608301516060820152608083015160808201528091505092915050565b60008060008060008060c08789031215611e4c57600080fd5b865195506020870151945060408701519350606087015192506080870151915060a087015190509295509295509295565b600060208284031215611e8f57600080fd5b505191905056fea264697066735822122094c68fcb50207c633c38814a519b6d9f316ac963c27ad7d4f7a927bb0c33c88364736f6c634300080c0033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101f05760003560e01c80638da5cb5b1161010f578063c0c53b8b116100a2578063e38fdc3611610071578063e38fdc36146104b1578063f2fde38b146104c4578063f4640c93146104d7578063ff408ae0146104ea57600080fd5b8063c0c53b8b1461046f578063d52874da14610482578063dbbbbc631461048b578063e2c75ca01461049e57600080fd5b8063a59a9973116100de578063a59a997314610413578063ad34250c14610433578063b888879e1461043c578063bae1b24c1461045c57600080fd5b80638da5cb5b146103c3578063a0cfb9ff146103e1578063a26ad44014610401578063a294c5021461040a57600080fd5b80635fcbd285116101875780636a7e9f33116101565780636a7e9f33146103695780636d9077cb146103725780636f21a17914610385578063715018a6146103bb57600080fd5b80635fcbd2851461031b578063660186e61461033b578063673a7e281461034e5780636a678a9c1461035657600080fd5b806351b74d98116101c357806351b74d9814610297578063563014e5146102d05780635de20b42146102e35780635e9016f41461030657600080fd5b80630afb0409146101f55780631fc8bc5d1461021d57806321cc01c91461026257806334419f2014610282575b600080fd5b6102086102033660046118da565b6104f3565b60405190151581526020015b60405180910390f35b60665461023d9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610214565b60675461023d9073ffffffffffffffffffffffffffffffffffffffff1681565b61028a610658565b60405161021491906118f7565b6102c26102a5366004611951565b606f60209081526000928352604080842090915290825290205481565b604051908152602001610214565b6102c26102de3660046118da565b6106c7565b6102086102f13660046118da565b606c6020526000908152604090205460ff1681565b61031961031436600461198a565b6108cf565b005b606b5461023d9073ffffffffffffffffffffffffffffffffffffffff1681565b6102086103493660046118da565b6109fa565b610319610a46565b6103196103643660046118da565b610aca565b6102c261271081565b6102c26103803660046118da565b610bde565b6102c26103933660046118da565b73ffffffffffffffffffffffffffffffffffffffff166000908152606d602052604090205490565b610319610d17565b60335473ffffffffffffffffffffffffffffffffffffffff1661023d565b6102c26103ef3660046118da565b606d6020526000908152604090205481565b6102c26101f481565b6102c2611f4081565b60655461023d9073ffffffffffffffffffffffffffffffffffffffff1681565b6102c261232881565b60685461023d9073ffffffffffffffffffffffffffffffffffffffff1681565b61031961046a3660046119ff565b610d2b565b61031961047d366004611a18565b610dae565b6102c260695481565b6103196104993660046118da565b61109c565b6103196104ac366004611a63565b611160565b6102c26104bf3660046118da565b611217565b6103196104d23660046118da565b6113e3565b6103196104e53660046119ff565b61149a565b6102c2606a5481565b60665460009073ffffffffffffffffffffffffffffffffffffffff163314610547576040517fe50d1fc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216610594576040517f9fabe1c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61059c610a46565b6105a5826109fa565b90508080156105d8575073ffffffffffffffffffffffffffffffffffffffff82166000908152606d602052604090205415155b156106045773ffffffffffffffffffffffffffffffffffffffff82166000908152606d60205260408120555b73ffffffffffffffffffffffffffffffffffffffff919091166000908152606c6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001682151517905590565b606060708054806020026020016040519081016040528092919081815260200182805480156106bd57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610692575b5050505050905090565b60006106d2826109fa565b6106de57506000919050565b60006106e983611217565b90506000606760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663cd57ed6c6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561075a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061077e9190611a8f565b6040517f6bd3b87c00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681166004830152919250600091831690636bd3b87c90602401600060405180830381865afa1580156107f0573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526108369190810190611b53565b80519091506000905b80156108c557600083610853600184611c63565b8151811061086357610863611c7a565b6020026020010151905080600001518361087d9190611ca9565b92508561088984611511565b1061089d5760200151979650505050505050565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0161083f565b5050505050919050565b6108d76115cb565b808061090f576040517f1e3b188d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b818110156109a357600084848381811061092e5761092e611c7a565b905060200201602081019061094391906118da565b73ffffffffffffffffffffffffffffffffffffffff161415610991576040517f9fabe1c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8061099b81611cc1565b915050610912565b506109b0607060006117fd565b6109bc6070848461181b565b507f420e89154023f9446f715f82a1b62633c0d2bd65e9bee3dde81e38691929848860706040516109ed9190611cfa565b60405180910390a1505050565b600080610a0683610bde565b90506000612710606a54610a1986611217565b610a239190611d4b565b610a2d9190611d88565b90508015801590610a3e5750808210155b949350505050565b606860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a2e620456040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610ab057600080fd5b505af1158015610ac4573d6000803e3d6000fd5b50505050565b610ad26115cb565b73ffffffffffffffffffffffffffffffffffffffff8116610b1f576040517f9fabe1c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606b5473ffffffffffffffffffffffffffffffffffffffff1615610b6f576040517f322815a400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517ff9d1c90c609623055381582a51735b38df3243eb09629a9170b15c2ab6bc073990600090a250565b600080606760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663cd57ed6c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c4e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c729190611a8f565b6040517fc84aae1700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff858116600483015291925060009183169063c84aae179060240160a060405180830381865afa158015610ce4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d089190611dc3565b9050610a3e8160400151611511565b610d1f6115cb565b610d29600061164c565b565b610d336115cb565b611f40811080610d44575061271081115b15610d7b576040517f648564d300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606a81905560405181907f05ace3111616a9d7bc7b769e0162c37e277aa5cdcd34699f9a0e3d7577d0db5490600090a250565b600054610100900460ff1615808015610dce5750600054600160ff909116105b80610de85750303b158015610de8575060005460ff166001145b610e79576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015610ed757600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b73ffffffffffffffffffffffffffffffffffffffff8416610f24576040517f9fabe1c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8316610f71576040517f9fabe1c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216610fbe576040517f9fabe1c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6065805473ffffffffffffffffffffffffffffffffffffffff8087167fffffffffffffffffffffffff0000000000000000000000000000000000000000928316179092556067805486841690831617905560688054928516929091169190911790556101f4606955612328606a556110346116c3565b8015610ac457600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150505050565b6110a46115cb565b73ffffffffffffffffffffffffffffffffffffffff81166110f1576040517f9fabe1c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f3edc4c109bdc9b34f00f24744f770e8de831fd903d0fc75d4d990d5d81b75b9890600090a250565b60665473ffffffffffffffffffffffffffffffffffffffff1633146111b1576040517fe50d1fc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82166000818152606d602052604090819020839055517f1e85ba2a5b06819d522e519e6ebf963f35ad4a709dc2a541ed39ad80f4b3a3be9061120b9084815260200190565b60405180910390a25050565b6065546040517fbf92857c00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152600092839291169063bf92857c9060240160c060405180830381865afa15801561128b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112af9190611e33565b505060705493945050821591506113c890505760005b818110156113c6576000607082815481106112e2576112e2611c7a565b6000918252602090912001546040517fbf92857c00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff88811660048301529091169063bf92857c9060240160c060405180830381865afa15801561135b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061137f9190611e33565b505050505090506000670de0b6b3a76400006305f5e100836113a19190611d4b565b6113ab9190611d88565b90506113b78186611ca9565b945082600101925050506112c5565b505b612710606954836113d99190611d4b565b610a3e9190611d88565b6113eb6115cb565b73ffffffffffffffffffffffffffffffffffffffff811661148e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610e70565b6114978161164c565b50565b6114a26115cb565b6127108111156114de576040517f648564d300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606981905560405181907f063aaf80a21dd5cad9d8adcdc5a53acaa3c2de05dc44c7e2f68783a87460d7fe90600090a250565b600080606860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636e9a05c56040518163ffffffff1660e01b8152600401602060405180830381865afa158015611581573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a59190611e7d565b9050670de0b6b3a76400006115ba8285611d4b565b6115c49190611d88565b9392505050565b60335473ffffffffffffffffffffffffffffffffffffffff163314610d29576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610e70565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff1661175a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610e70565b610d29600054610100900460ff166117f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610e70565b610d293361164c565b508054600082559060005260206000209081019061149791906118a3565b828054828255906000526020600020908101928215611893579160200282015b828111156118935781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84351617825560209092019160019091019061183b565b5061189f9291506118a3565b5090565b5b8082111561189f57600081556001016118a4565b73ffffffffffffffffffffffffffffffffffffffff8116811461149757600080fd5b6000602082840312156118ec57600080fd5b81356115c4816118b8565b6020808252825182820181905260009190848201906040850190845b8181101561194557835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101611913565b50909695505050505050565b6000806040838503121561196457600080fd5b823561196f816118b8565b9150602083013561197f816118b8565b809150509250929050565b6000806020838503121561199d57600080fd5b823567ffffffffffffffff808211156119b557600080fd5b818501915085601f8301126119c957600080fd5b8135818111156119d857600080fd5b8660208260051b85010111156119ed57600080fd5b60209290920196919550909350505050565b600060208284031215611a1157600080fd5b5035919050565b600080600060608486031215611a2d57600080fd5b8335611a38816118b8565b92506020840135611a48816118b8565b91506040840135611a58816118b8565b809150509250925092565b60008060408385031215611a7657600080fd5b8235611a81816118b8565b946020939093013593505050565b600060208284031215611aa157600080fd5b81516115c4816118b8565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516080810167ffffffffffffffff81118282101715611afe57611afe611aac565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611b4b57611b4b611aac565b604052919050565b60006020808385031215611b6657600080fd5b825167ffffffffffffffff80821115611b7e57600080fd5b818501915085601f830112611b9257600080fd5b815181811115611ba457611ba4611aac565b611bb2848260051b01611b04565b818152848101925060079190911b830184019087821115611bd257600080fd5b928401925b81841015611c295760808489031215611bf05760008081fd5b611bf8611adb565b8451815285850151868201526040808601519082015260608086015190820152835260809093019291840191611bd7565b979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015611c7557611c75611c34565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008219821115611cbc57611cbc611c34565b500190565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415611cf357611cf3611c34565b5060010190565b6020808252825482820181905260008481528281209092916040850190845b8181101561194557835473ffffffffffffffffffffffffffffffffffffffff1683526001938401939285019201611d19565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615611d8357611d83611c34565b500290565b600082611dbe577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b600060a08284031215611dd557600080fd5b60405160a0810181811067ffffffffffffffff82111715611df857611df8611aac565b806040525082518152602083015160208201526040830151604082015260608301516060820152608083015160808201528091505092915050565b60008060008060008060c08789031215611e4c57600080fd5b865195506020870151945060408701519350606087015192506080870151915060a087015190509295509295509295565b600060208284031215611e8f57600080fd5b505191905056fea264697066735822122094c68fcb50207c633c38814a519b6d9f316ac963c27ad7d4f7a927bb0c33c88364736f6c634300080c0033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
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.