Source Code
Overview
ETH Balance
ETH Value
$0.00| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 21590310 | 175 days ago | 0 ETH | ||||
| 21590310 | 175 days ago | 0 ETH | ||||
| 21590310 | 175 days ago | 0 ETH | ||||
| 21590310 | 175 days ago | 0 ETH | ||||
| 21590310 | 175 days ago | 0 ETH | ||||
| 21590310 | 175 days ago | 0 ETH | ||||
| 21590310 | 175 days ago | 0 ETH | ||||
| 21590310 | 175 days ago | 0 ETH | ||||
| 21590310 | 175 days ago | 0 ETH | ||||
| 21590310 | 175 days ago | 0 ETH | ||||
| 21590310 | 175 days ago | 0 ETH | ||||
| 21590310 | 175 days ago | 0 ETH | ||||
| 21590310 | 175 days ago | 0 ETH | ||||
| 21590310 | 175 days ago | 0 ETH | ||||
| 21590310 | 175 days ago | 0 ETH | ||||
| 21281386 | 184 days ago | 0 ETH | ||||
| 21281386 | 184 days ago | 0 ETH | ||||
| 21281386 | 184 days ago | 0 ETH | ||||
| 21281386 | 184 days ago | 0 ETH | ||||
| 21281386 | 184 days ago | 0 ETH | ||||
| 21281386 | 184 days ago | 0 ETH | ||||
| 21281386 | 184 days ago | 0 ETH | ||||
| 21281386 | 184 days ago | 0 ETH | ||||
| 21281386 | 184 days ago | 0 ETH | ||||
| 21281386 | 184 days ago | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
Oracle
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 500 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.8.23;
import {Ownable} from "../../../contracts/dependencies/openzeppelin/contracts/Ownable.sol";
import {IERC20} from "../../../contracts/dependencies/openzeppelin/contracts/IERC20.sol";
import {IOracle} from "../../../contracts/interfaces/IOracle.sol";
import {IChainlinkAggregator} from "../../../contracts/interfaces/base/IChainlinkAggregator.sol";
import {SafeERC20} from "../../../contracts/dependencies/openzeppelin/contracts/SafeERC20.sol";
import {ATokenNonRebasing} from
"../../../contracts/protocol/tokenization/ERC20/ATokenNonRebasing.sol";
import {Errors} from "../../../contracts/protocol/libraries/helpers/Errors.sol";
import {ILendingPoolConfigurator} from "../../../contracts/interfaces/ILendingPoolConfigurator.sol";
import {ILendingPoolAddressesProvider} from
"../../../contracts/interfaces/ILendingPoolAddressesProvider.sol";
/**
* @title Oracle
* @author Conclave
* @notice Proxy smart contract to get the price of an asset from a price source, with Chainlink Aggregator
* smart contracts as primary option.
* @dev The contract has the following features:
* - Abstract aToken price to underlying asset price adjusted to the asset/share conversion ratio.
* - If the returned price by a Chainlink aggregator is <= 0, the call is forwarded to a `fallbackOracle`.
* - Owned by the Astera Governance system, allowed to add sources for assets, replace them
* and change the `fallbackOracle`.
* @dev ATTENTION: All aggregators (main and fallback) are expected to return prices in BASE_CURRENCY with the
* same BASE_CURRENCY_UNIT unit.
*/
contract Oracle is IOracle, Ownable {
using SafeERC20 for IERC20;
/// @dev Mapping of asset addresses to their corresponding Chainlink aggregator contracts.
mapping(address => IChainlinkAggregator) private _assetsSources;
/// @dev Mapping of asset addresses to their corresponding Chainlink timeout values.
mapping(address => uint256) private _assetToTimeout;
/// @dev The fallback oracle used when Chainlink data is invalid.
IOracle private _fallbackOracle;
ILendingPoolConfigurator private _lendingpoolConfigurator;
ILendingPoolAddressesProvider private _lendingpoolAddressesProvider;
/**
* @dev The base currency address used for price quotes.
* @notice If `USD` returns `0x0`, if `ETH` returns `WETH` address.
*/
address public immutable BASE_CURRENCY;
/// @dev The unit of the base currency used for price normalization. MUST BE USD IF USING cdxUSD.
uint256 public immutable BASE_CURRENCY_UNIT;
/// @dev The address of the cdxUSD token.
address public constant CDX_USD = address(0xC0D3700000987C99b3C9009069E4f8413fD22330);
/**
* @notice Initializes the Oracle contract.
* @param assets The addresses of the assets.
* @param sources The address of the source of each asset.
* @param timeouts The timeout values for each Chainlink price feed.
* @param fallbackOracle The address of the fallback oracle to use if the data of an
* aggregator is not consistent.
* @param baseCurrency The base currency used for the price quotes. If USD is used, base currency is 0x0.
* @param baseCurrencyUnit The unit of the base currency.
* @param lendingpoolAddressesProvider The address of the lending pool addresses provider.
*/
constructor(
address[] memory assets,
address[] memory sources,
uint256[] memory timeouts,
address fallbackOracle,
address baseCurrency,
uint256 baseCurrencyUnit,
address lendingpoolAddressesProvider
) Ownable(msg.sender) {
_setFallbackOracle(fallbackOracle);
_setAssetsSources(assets, sources, timeouts);
BASE_CURRENCY = baseCurrency;
BASE_CURRENCY_UNIT = baseCurrencyUnit;
_lendingpoolAddressesProvider = ILendingPoolAddressesProvider(lendingpoolAddressesProvider);
_lendingpoolConfigurator =
ILendingPoolConfigurator(_lendingpoolAddressesProvider.getLendingPoolConfigurator());
emit BaseCurrencySet(baseCurrency, baseCurrencyUnit);
}
/**
* @notice External function called by the Astera Governance to set or replace sources of assets.
* @param assets The addresses of the assets.
* @param sources The address of the source of each asset.
* @param timeouts The chainlink timeout of each asset.
*/
function setAssetSources(
address[] calldata assets,
address[] calldata sources,
uint256[] calldata timeouts
) external onlyOwner {
_setAssetsSources(assets, sources, timeouts);
}
/**
* @notice Sets the fallback oracle.
* @dev Only callable by the Astera Governance.
* @param fallbackOracle The address of the fallback oracle.
*/
function setFallbackOracle(address fallbackOracle) external onlyOwner {
_setFallbackOracle(fallbackOracle);
}
/**
* @notice Internal function to set the sources for each asset.
* @param assets The addresses of the assets.
* @param sources The address of the source of each asset.
* @param timeouts The chainlink timeout of each asset.
*/
function _setAssetsSources(
address[] memory assets,
address[] memory sources,
uint256[] memory timeouts
) internal {
uint256 assetsLength = assets.length;
require(assetsLength == sources.length, Errors.O_INCONSISTENT_PARAMS_LENGTH);
require(assetsLength == timeouts.length, Errors.O_INCONSISTENT_PARAMS_LENGTH);
for (uint256 i = 0; i < assetsLength; i++) {
address asset = assets[i];
address source = sources[i];
uint256 timeout = timeouts[i];
_assetsSources[asset] = IChainlinkAggregator(source);
_assetToTimeout[asset] = timeout == 0 ? type(uint256).max : timeout;
emit AssetSourceUpdated(asset, source, timeout);
}
}
/**
* @notice Internal function to set the fallback oracle.
* @param fallbackOracle The address of the fallback oracle.
*/
function _setFallbackOracle(address fallbackOracle) internal {
_fallbackOracle = IOracle(fallbackOracle);
emit FallbackOracleUpdated(fallbackOracle);
}
/**
* @notice Gets an asset price by address.
* @dev If the asset is an aToken, it will get the price of the underlying asset and convert it to shares.
* @param asset The asset address.
* @return The price of the asset.
*/
function getAssetPrice(address asset) public view override returns (uint256) {
address underlying;
// Check if `asset` is an aToken.
if (_lendingpoolConfigurator.getIsAToken(asset)) {
underlying = ATokenNonRebasing(asset).UNDERLYING_ASSET_ADDRESS();
} else {
underlying = asset;
}
IChainlinkAggregator source = _assetsSources[underlying];
uint256 finalPrice;
// If the asset is the base currency or cdxUSD and the caller is the lending pool, return the unit
// of the base currency.
// Since the lending pool is used as a primary market for cdxUSD, this allows the lending pool to get the price
// of cdxUSD at 1$ but minipools and other contracts to still get the price of cdxUSD from the aggregator.
if (
underlying == BASE_CURRENCY
|| (asset == CDX_USD && msg.sender == _lendingpoolAddressesProvider.getLendingPool())
) {
finalPrice = BASE_CURRENCY_UNIT;
} else if (address(source) == address(0)) {
finalPrice = _fallbackOracle.getAssetPrice(underlying);
} else {
(uint80 roundId, int256 price, uint256 startedAt, uint256 timestamp,) =
IChainlinkAggregator(source).latestRoundData();
// Chainlink integrity checks.
if (
roundId == 0 || timestamp == 0 || timestamp > block.timestamp || price <= 0
|| startedAt == 0 || block.timestamp - timestamp > _assetToTimeout[underlying]
) {
require(address(_fallbackOracle) != address(0), Errors.O_PRICE_FEED_INCONSISTENCY);
finalPrice = _fallbackOracle.getAssetPrice(underlying);
} else {
finalPrice = uint256(price);
}
}
// If "asset" is an aToken then convert the price from share to asset.
if (asset != underlying) {
return ATokenNonRebasing(asset).convertToAssets(finalPrice);
} else {
return finalPrice;
}
}
/**
* @notice Gets a list of prices from a list of assets addresses.
* @param assets The list of assets addresses.
* @return An array containing the prices of the given assets.
*/
function getAssetsPrices(address[] calldata assets) external view returns (uint256[] memory) {
uint256[] memory prices = new uint256[](assets.length);
for (uint256 i = 0; i < assets.length; i++) {
prices[i] = getAssetPrice(assets[i]);
}
return prices;
}
/**
* @notice Gets the address of the source for an asset address.
* @param asset The address of the asset.
* @return address The address of the source.
*/
function getSourceOfAsset(address asset) external view returns (address) {
return address(_assetsSources[asset]);
}
/**
* @notice Gets the timeout for an asset.
* @param asset The address of the asset.
* @return uint256 The timeout for the asset.
*/
function getAssetTimeout(address asset) external view returns (uint256) {
return _assetToTimeout[asset];
}
/**
* @notice Gets the address of the fallback oracle.
* @return address The address of the fallback oracle.
*/
function getFallbackOracle() external view returns (address) {
return address(_fallbackOracle);
}
/**
* @notice Gets the address of the lending pool configurator.
* @return address The address of the lending pool configurator.
*/
function getLendingpoolConfigurator() external view returns (address) {
return address(_lendingpoolConfigurator);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
/**
* @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.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != msg.sender) {
revert OwnableUnauthorizedAccount(msg.sender);
}
}
/**
* @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 {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_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);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @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 value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` 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 value) external returns (bool);
}// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.8.0;
/**
* @title IOracle interface.
* @author Conclave
*/
interface IOracle {
// Events
/**
* @dev Emitted when the base currency is set
* @param baseCurrency The address of the base currency
* @param baseCurrencyUnit The unit of the base currency
*/
event BaseCurrencySet(address indexed baseCurrency, uint256 baseCurrencyUnit);
/**
* @dev Emitted when an asset source is updated
* @param asset The address of the asset
* @param source The address of the price source
*/
event AssetSourceUpdated(address indexed asset, address indexed source, uint256 timeout);
/**
* @dev Emitted when the fallback oracle is updated
* @param fallbackOracle The address of the new fallback oracle
*/
event FallbackOracleUpdated(address indexed fallbackOracle);
// Setters
function setAssetSources(
address[] calldata assets,
address[] calldata sources,
uint256[] calldata timeouts
) external;
function setFallbackOracle(address fallbackOracle) external;
// Getters
function getAssetPrice(address asset) external view returns (uint256);
function getAssetsPrices(address[] calldata assets) external view returns (uint256[] memory);
function getSourceOfAsset(address asset) external view returns (address);
function getAssetTimeout(address asset) external view returns (uint256);
function getFallbackOracle() external view returns (address);
function getLendingpoolConfigurator() external view returns (address);
function BASE_CURRENCY() external view returns (address);
function BASE_CURRENCY_UNIT() external view returns (uint256);
}// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.8.0;
/**
* @title IChainlinkAggregator interface.
* @author Conclave
*/
interface IChainlinkAggregator {
function decimals() external view returns (uint8);
function latestAnswer() external view returns (int256);
function latestTimestamp() external view returns (uint256);
function latestRound() external view returns (uint256);
function getAnswer(uint256 roundId) external view returns (int256);
function getTimestamp(uint256 roundId) external view returns (uint256);
function getRoundData(uint80 _roundId)
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
function latestRoundData()
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 timestamp);
event NewRound(uint256 indexed roundId, address indexed startedBy);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC20Permit} from "./IERC20Permit.sol";
import {Address} from "./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 An operation with an ERC20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(
address spender, uint256 currentAllowance, uint256 requestedDecrease
);
/**
* @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.encodeCall(token.transfer, (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.encodeCall(token.transferFrom, (from, to, 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);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease)
internal
{
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(
spender, currentAllowance, requestedDecrease
);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @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.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @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);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @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(token).code.length > 0;
}
}// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.8.23;
import {AToken} from "../../../../contracts/protocol/tokenization/ERC20/AToken.sol";
/**
* @title ERC20 Non Rebasing AToken wrapper
* @author Conclave - Beirao
* @notice This contract wraps an AToken to provide a non-rebasing ERC20 interface.
* @dev All operations are performed in terms of shares rather than underlying assets.
*/
contract ATokenNonRebasing {
/**
* @dev The underlying AToken contract that this wrapper interacts with.
*/
AToken internal immutable _aToken;
/**
* @dev Emitted when `_value` tokens are moved from `_from` to `_to`.
* @param from The address tokens are transferred from.
* @param to The address tokens are transferred to.
* @param value The amount of tokens transferred.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when `_owner` approves `_spender` to spend `_value` tokens.
* @param owner The address granting the allowance.
* @param spender The address receiving the allowance.
* @param value The amount of tokens approved to spend.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Constructor that sets the wrapped AToken.
* @param aToken The address of the AToken to wrap.
*/
constructor(address aToken) {
_aToken = AToken(aToken);
}
/**
* @dev Returns the name of the token.
* @return The name of the token.
*/
function name() public view returns (string memory) {
return string.concat("Wrapped ", _aToken.name());
}
/**
* @dev Returns the symbol of the token.
* @return The symbol of the token.
*/
function symbol() public view returns (string memory) {
return string.concat("w", _aToken.symbol());
}
/**
* @dev Returns the number of decimals used for token precision.
* @return The number of decimals.
*/
function decimals() public view returns (uint8) {
return _aToken.decimals();
}
/**
* @dev Returns the total supply of shares.
* @return The total supply of shares.
*/
function totalSupply() public view virtual returns (uint256) {
return _aToken.scaledTotalSupply();
}
/**
* @dev Returns the address of the wrapped AToken.
* @return The address of the wrapped AToken.
*/
function ATOKEN_ADDRESS() public view returns (address) {
return address(_aToken);
}
/**
* @dev Returns the address of the underlying asset.
* @return The address of the underlying asset.
*/
function UNDERLYING_ASSET_ADDRESS() public view returns (address) {
return _aToken.UNDERLYING_ASSET_ADDRESS();
}
/**
* @dev Returns the reserve type of the underlying asset.
* @return The reserve type (true for stable, false for variable).
*/
function RESERVE_TYPE() public view returns (bool) {
return _aToken.RESERVE_TYPE();
}
/**
* @dev Returns the address of the LendingPool associated with the AToken.
* @return The address of the LendingPool.
*/
function getPool() external view returns (address) {
return _aToken.getPool();
}
/**
* @dev Returns the balance of shares for an account.
* @param account The address to query the balance of.
* @return The number of shares owned by `account`.
*/
function balanceOf(address account) public view virtual returns (uint256) {
return _aToken.scaledBalanceOf(account);
}
/**
* @dev Transfers shares from sender to recipient.
* @param recipient The address to receive the shares.
* @param amountShare The amount of shares to transfer.
* @return A boolean indicating whether the transfer was successful.
*/
function transfer(address recipient, uint256 amountShare) public virtual returns (bool) {
_aToken.transferShare(msg.sender, recipient, amountShare);
emit Transfer(msg.sender, recipient, amountShare);
return true;
}
/**
* @dev Returns the remaining shares that `spender` is allowed to spend on behalf of `owner`.
* @param owner The address that owns the shares.
* @param spender The address that can spend the shares.
* @return The number of shares `spender` can spend on behalf of `owner`.
*/
function allowance(address owner, address spender) public view virtual returns (uint256) {
return _aToken.shareAllowances(owner, spender);
}
/**
* @dev Sets `amountShare` as the allowance of `spender` over the caller's shares.
* @param spender The address authorized to spend the shares.
* @param amountShare The amount of shares to allow.
* @return A boolean indicating whether the approval was successful.
*/
function approve(address spender, uint256 amountShare) public virtual returns (bool) {
_approve(msg.sender, spender, amountShare);
return true;
}
/**
* @dev Transfers shares from one address to another using the allowance mechanism.
* @param sender The address to transfer shares from.
* @param recipient The address to transfer shares to.
* @param amountShare The amount of shares to transfer.
* @return A boolean indicating whether the transfer was successful.
*/
function transferFrom(address sender, address recipient, uint256 amountShare)
public
virtual
returns (bool)
{
_aToken.transferShare(sender, recipient, amountShare);
uint256 oldAllowance = _aToken.shareAllowances(sender, msg.sender);
require(oldAllowance >= amountShare, "ERC20: transfer amount exceeds allowance");
_approve(sender, msg.sender, oldAllowance - amountShare);
emit Transfer(sender, recipient, amountShare);
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
* @param spender The address being authorized to spend shares.
* @param addedValue The amount of shares to increase the allowance by.
* @return A boolean indicating whether the increase was successful.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
_approve(msg.sender, spender, _aToken.shareAllowances(msg.sender, spender) + addedValue);
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
* @param spender The address being authorized to spend shares.
* @param subtractedValue The amount of shares to decrease the allowance by.
* @return A boolean indicating whether the decrease was successful.
*/
function decreaseAllowance(address spender, uint256 subtractedValue)
public
virtual
returns (bool)
{
uint256 oldAllowance = _aToken.shareAllowances(msg.sender, spender);
require(oldAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
_approve(msg.sender, spender, oldAllowance - subtractedValue);
return true;
}
/**
* @dev Converts an amount of underlying assets to shares.
* @param assetAmount The amount of assets to convert.
* @return The equivalent amount in shares.
*/
function convertToShares(uint256 assetAmount) external view returns (uint256) {
return _aToken.convertToShares(assetAmount);
}
/**
* @dev Converts an amount of shares to underlying assets.
* @param shareAmount The amount of shares to convert.
* @return The equivalent amount in assets.
*/
function convertToAssets(uint256 shareAmount) external view returns (uint256) {
return _aToken.convertToAssets(shareAmount);
}
/**
* @dev Internal function to set the allowance for a spender.
* @param owner The owner of the shares.
* @param spender The spender being approved.
* @param amount The amount of shares to approve.
*/
function _approve(address owner, address spender, uint256 amount) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_aToken.shareApprove(owner, spender, amount);
emit Approval(owner, spender, amount);
}
}// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.8.23;
/**
* @title Errors library
* @author Conclave
* @notice Defines the error messages emitted by the different contracts of the Astera protocol
* @dev Error messages prefix glossary:
* - VL :: ValidationLogic
* - MATH :: Math libraries
* - AT :: AToken/AToken6909
* - LP :: Pool
* - RL :: ReserveLogic
* - LPCM :: Liquidation
* - DP :: DataProvider
* - O :: Oracle
* - PAP :: PoolAddressesProvider
* - RC :: Reserve configuration
* - R :: Rewarder
*/
library Errors {
/// @notice Amount must be greater than 0.
string public constant VL_INVALID_INPUT = "0";
/// @notice Amount must be greater than 0.
string public constant VL_INVALID_AMOUNT = "1";
/// @notice Action requires an active reserve.
string public constant VL_NO_ACTIVE_RESERVE = "2";
/// @notice Action cannot be performed because the reserve is frozen.
string public constant VL_RESERVE_FROZEN = "3";
/// @notice User cannot withdraw more than the available balance.
string public constant VL_NOT_ENOUGH_AVAILABLE_USER_BALANCE = "4";
/// @notice Transfer cannot be allowed.
string public constant VL_TRANSFER_NOT_ALLOWED = "5";
/// @notice Borrowing is not enabled.
string public constant VL_BORROWING_NOT_ENABLED = "6";
/// @notice The collateral balance is 0.
string public constant VL_COLLATERAL_BALANCE_IS_0 = "7";
/// @notice Health factor is lesser than the liquidation threshold.
string public constant VL_HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD = "8";
/// @notice There is not enough collateral to cover a new borrow.
string public constant VL_COLLATERAL_CANNOT_COVER_NEW_BORROW = "9";
/// @notice Flow is not enough.
string public constant VL_BORROW_FLOW_LIMIT_REACHED = "10";
/// @notice Minipool position cannot be liquidated.
string public constant VL_MINIPOOL_CANNOT_BE_LIQUIDATED = "11";
/// @notice For repayment of stable debt, the user needs to have stable debt, otherwise, he needs to have variable debt.
string public constant VL_NO_DEBT_OF_SELECTED_TYPE = "12";
/// @notice To repay on behalf of a user an explicit amount to repay is needed.
string public constant VL_NO_EXPLICIT_AMOUNT_TO_REPAY_ON_BEHALF = "13";
/// @notice The underlying balance needs to be greater than 0.
string public constant VL_UNDERLYING_BALANCE_NOT_GREATER_THAN_0 = "14";
/// @notice User deposit is already being used as collateral.
string public constant VL_DEPOSIT_ALREADY_IN_USE = "15";
/// @notice Inconsistent flashloan parameters.
string public constant VL_INCONSISTENT_FLASHLOAN_PARAMS = "16";
/// @notice Deposit cap reached.
string public constant VL_DEPOSIT_CAP_REACHED = "17";
/// @notice Reserve is inactive.
string public constant VL_RESERVE_INACTIVE = "18";
/// @notice Flashloan is disabled.
string public constant VL_FLASHLOAN_DISABLED = "19";
/// @notice Tranched asset cannot be flashloaned.
string public constant VL_TRANCHED_ASSET_CANNOT_BE_FLASHLOAN = "20";
/// @notice The caller must be the pool admin.
string public constant VL_CALLER_NOT_POOL_ADMIN = "21";
/// @notice U0 is greater than RAY.
string public constant VL_U0_GREATER_THAN_RAY = "22";
/// @notice Access restricted to lending pool.
string public constant VL_ACCESS_RESTRICTED_TO_LENDING_POOL = "23";
/// @notice The liquidity of the reserve needs to be 0.
string public constant VL_RESERVE_LIQUIDITY_NOT_0 = "24";
/// @notice Invalid risk parameters for the reserve.
string public constant VL_INVALID_CONFIGURATION = "25";
/// @notice The caller must be the emergency admin.
string public constant VL_CALLER_NOT_EMERGENCY_ADMIN = "26";
/// @notice Invalid flashloan premium.
string public constant VL_FLASHLOAN_PREMIUM_INVALID = "27";
/// @notice Invalid interest rate mode.
string public constant VL_INVALID_INTEREST_RATE_MODE = "28";
/// @notice Max reserves with flow borrowing reached.
string public constant VL_MAX_RESERVES_WITH_FLOW_BORROWING_REACHED = "29";
/// @notice The debt is too small to borrow and repay.
string public constant VL_DEBT_TOO_SMALL = "30";
/// @notice Division by zero.
string public constant MATH_DIVISION_BY_ZERO = "31";
/// @notice Multiplication overflow.
string public constant MATH_MULTIPLICATION_OVERFLOW = "32";
/// @notice Invalid amount to mint.
string public constant AT_INVALID_MINT_AMOUNT = "33";
/// @notice Invalid amount to burn.
string public constant AT_INVALID_BURN_AMOUNT = "34";
/// @notice The caller of this function must be a lending pool.
string public constant AT_CALLER_MUST_BE_LENDING_POOL = "35";
/// @notice Vault not initialized.
string public constant AT_VAULT_NOT_INITIALIZED = "36";
/// @notice Invalid address.
string public constant AT_INVALID_ADDRESS = "37";
/// @notice Invalid amount.
string public constant AT_INVALID_AMOUNT = "38";
/// @notice Invalid aToken ID.
string public constant AT_INVALID_ATOKEN_ID = "39";
/// @notice Invalid aToken address.
string public constant AT_INVALID_ATOKEN_ADDRESS = "40";
/// @notice Vault is not empty.
string public constant AT_VAULT_NOT_EMPTY = "41";
/// @notice Invalid controller address.
string public constant AT_INVALID_CONTROLLER = "42";
/// @notice Caller is not wrapper.
string public constant AT_CALLER_NOT_WRAPPER = "43";
/// @notice User borrows on behalf, but allowance is too small.
string public constant AT_BORROW_ALLOWANCE_NOT_ENOUGH = "44";
/// @notice The permit has expired.
string public constant AT_INVALID_EXPIRATION = "45";
/// @notice The signature is invalid.
string public constant AT_INVALID_SIGNATURE = "46";
/// @notice Profit handler not set.
string public constant AT_PROFIT_HANDLER_SET = "47";
/// @notice Caller is not AToken.
string public constant AT_CALLER_NOT_ATOKEN = "48";
/// @dev The aToken has already been set.
string public constant AT_ATOKEN_ALREADY_SET = "49";
/// @dev The debt token has already been set.
string public constant AT_DEBT_TOKEN_ALREADY_SET = "50";
/// @notice Caller is not the keeper.
string public constant AT_CALLER_NOT_KEEPER = "51";
/// @notice Reliquary allocation is more than 100%.
string public constant AT_RELIQUARY_ALLOCATION_MORE_THAN_100 = "52";
/// @notice The treasury has not been set.
string public constant AT_TREASURY_NOT_SET = "53";
/// @notice There is not enough liquidity available to borrow.
string public constant LP_NOT_ENOUGH_LIQUIDITY_TO_BORROW = "54";
/// @notice The caller of the function is not the lending pool configurator.
string public constant LP_CALLER_NOT_LENDING_POOL_CONFIGURATOR = "55";
/// @notice Caller must be an aToken.
string public constant LP_CALLER_MUST_BE_AN_ATOKEN = "56";
/// @notice Pool is paused.
string public constant LP_IS_PAUSED = "57";
/// @notice No more reserves allowed.
string public constant LP_NO_MORE_RESERVES_ALLOWED = "58";
/// @notice Invalid flash loan executor return.
string public constant LP_INVALID_FLASH_LOAN_EXECUTOR_RETURN = "59";
/// @notice Not a contract.
string public constant LP_NOT_CONTRACT = "60";
/// @notice Caller is not minipool.
string public constant LP_CALLER_NOT_MINIPOOL = "61";
/// @notice Base borrow rate can't be negative.
string public constant LP_BASE_BORROW_RATE_CANT_BE_NEGATIVE = "62";
/// @notice Invalid index.
string public constant LP_INVALID_INDEX = "63";
/// @notice Reserve has already been added.
string public constant LP_RESERVE_ALREADY_ADDED = "64";
/// @notice Reserve has already been initialized.
string public constant RL_RESERVE_ALREADY_INITIALIZED = "65";
/// @notice Reserve is not initialized.
string public constant RL_RESERVE_NOT_INITIALIZED = "66";
/// @notice Liquidity index overflows uint128.
string public constant RL_LIQUIDITY_INDEX_OVERFLOW = "67";
/// @notice Variable borrow index overflows uint128.
string public constant RL_VARIABLE_BORROW_INDEX_OVERFLOW = "68";
/// @notice Liquidity rate overflows uint128.
string public constant RL_LIQUIDITY_RATE_OVERFLOW = "69";
/// @notice Variable borrow rate overflows uint128.
string public constant RL_VARIABLE_BORROW_RATE_OVERFLOW = "70";
/// @notice Health factor is not below the threshold.
string public constant LPCM_HEALTH_FACTOR_NOT_BELOW_THRESHOLD = "71";
/// @notice The collateral chosen cannot be liquidated.
string public constant LPCM_COLLATERAL_CANNOT_BE_LIQUIDATED = "72";
/// @notice User did not borrow the specified currency.
string public constant LPCM_SPECIFIED_CURRENCY_NOT_BORROWED_BY_USER = "73";
/// @notice There is not enough liquidity available to liquidate.
string public constant LPCM_NOT_ENOUGH_LIQUIDITY_TO_LIQUIDATE = "74";
/// @notice Inconsistent parameters length.
string public constant O_INCONSISTENT_PARAMS_LENGTH = "75";
/// @notice Price feed inconsistency.
string public constant O_PRICE_FEED_INCONSISTENCY = "76";
/// @notice No mini pool ID for address.
string public constant PAP_NO_MINI_POOL_ID_FOR_ADDRESS = "77";
/// @notice Pool ID out of range.
string public constant PAP_POOL_ID_OUT_OF_RANGE = "78";
/// @notice Invalid LTV.
string public constant RC_INVALID_LTV = "79";
/// @notice Invalid liquidation threshold.
string public constant RC_INVALID_LIQ_THRESHOLD = "80";
/// @notice Invalid liquidation bonus.
string public constant RC_INVALID_LIQ_BONUS = "81";
/// @notice Invalid decimals.
string public constant RC_INVALID_DECIMALS = "82";
/// @notice Invalid reserve factor.
string public constant RC_INVALID_RESERVE_FACTOR = "83";
/// @notice Invalid deposit cap.
string public constant RC_INVALID_DEPOSIT_CAP = "84";
/// @notice LendingPool not set.
string public constant DP_LENDINGPOOL_NOT_SET = "85";
/// @notice Reserve is not configured.
string public constant DP_RESERVE_NOT_CONFIGURED = "86";
/// @notice Not registered.
string public constant R_NOT_REGISTERED = "87";
/// @notice Too many reward tokens.
string public constant R_TOO_MANY_REWARD_TOKENS = "88";
/// @notice No forwarder set.
string public constant R_NO_FORWARDER_SET = "89";
/// @notice Claimer unauthorized.
string public constant R_CLAIMER_UNAUTHORIZED = "90";
/// @notice Invalid address.
string public constant R_INVALID_ADDRESS = "91";
/// @notice Already set.
string public constant R_ALREADY_SET = "92";
/// @notice Transfer error.
string public constant R_TRANSFER_ERROR = "93";
/// @notice Rewarder not set.
string public constant R_REWARDER_NOT_SET = "94";
}// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.8.0;
import {ILendingPoolAddressesProvider} from "./ILendingPoolAddressesProvider.sol";
/**
* @title ILendingPoolConfigurator interface.
* @author Conclave
*/
interface ILendingPoolConfigurator {
struct InitReserveInput {
address aTokenImpl;
address variableDebtTokenImpl;
uint8 underlyingAssetDecimals;
address interestRateStrategyAddress;
address underlyingAsset;
address treasury;
address incentivesController;
string underlyingAssetName;
bool reserveType;
string aTokenName;
string aTokenSymbol;
string variableDebtTokenName;
string variableDebtTokenSymbol;
bytes params;
}
struct UpdateATokenInput {
address asset;
bool reserveType;
address treasury;
address incentivesController;
string name;
string symbol;
address implementation;
bytes params;
}
struct UpdateDebtTokenInput {
address asset;
bool reserveType;
address incentivesController;
string name;
string symbol;
address implementation;
bytes params;
}
/**
* @dev Emitted when a reserve is initialized.
* @param asset The address of the underlying asset of the reserve
* @param aToken The address of the associated aToken contract
* @param reserveType Whether the reserve is boosted by a vault
* @param variableDebtToken The address of the associated variable rate debt token
* @param interestRateStrategyAddress The address of the interest rate strategy for the reserve
*/
event ReserveInitialized(
address indexed asset,
address indexed aToken,
bool reserveType,
address variableDebtToken,
address interestRateStrategyAddress
);
/**
* @dev Emitted when borrowing is enabled on a reserve
* @param asset The address of the underlying asset of the reserve
* @param reserveType Whether the reserve is boosted by a vault
*/
event BorrowingEnabledOnReserve(address indexed asset, bool reserveType);
/**
* @dev Emitted when borrowing is disabled on a reserve
* @param asset The address of the underlying asset of the reserve
* @param reserveType Whether the reserve is boosted by a vault
*/
event BorrowingDisabledOnReserve(address indexed asset, bool reserveType);
/**
* @dev Emitted when the collateralization risk parameters for the specified asset are updated.
* @param asset The address of the underlying asset of the reserve
* @param reserveType Whether the reserve is boosted by a vault
* @param ltv The loan to value of the asset when used as collateral
* @param liquidationThreshold The threshold at which loans using this asset as collateral will be considered undercollateralized
* @param liquidationBonus The bonus liquidators receive to liquidate this asset
*/
event CollateralConfigurationChanged(
address indexed asset,
bool reserveType,
uint256 ltv,
uint256 liquidationThreshold,
uint256 liquidationBonus
);
/**
* @dev Emitted when a reserve is activated
* @param asset The address of the underlying asset of the reserve
* @param reserveType Whether the reserve is boosted by a vault
*/
event ReserveActivated(address indexed asset, bool reserveType);
/**
* @dev Emitted when a reserve is deactivated
* @param asset The address of the underlying asset of the reserve
* @param reserveType Whether the reserve is boosted by a vault
*/
event ReserveDeactivated(address indexed asset, bool reserveType);
/**
* @dev Emitted when a reserve is frozen
* @param asset The address of the underlying asset of the reserve
* @param reserveType Whether the reserve is boosted by a vault
*/
event ReserveFrozen(address indexed asset, bool reserveType);
/**
* @dev Emitted when a reserve is unfrozen
* @param asset The address of the underlying asset of the reserve
* @param reserveType Whether the reserve is boosted by a vault
*/
event ReserveUnfrozen(address indexed asset, bool reserveType);
/**
* @dev Emitted when FL is enabled
* @param asset The address of the underlying asset of the reserve
* @param reserveType Whether the reserve is boosted by a vault
*/
event EnableFlashloan(address indexed asset, bool reserveType);
/**
* @dev Emitted when FL is disabled
* @param asset The address of the underlying asset of the reserve
* @param reserveType Whether the reserve is boosted by a vault
*/
event DisableFlashloan(address indexed asset, bool reserveType);
/**
* @dev Emitted when a reserve factor is updated
* @param asset The address of the underlying asset of the reserve
* @param reserveType Whether the reserve is boosted by a vault
* @param factor The new reserve factor
*/
event ReserveFactorChanged(address indexed asset, bool reserveType, uint256 factor);
/**
* @dev Emitted when the reserve deposit cap is updated
* @param asset The address of the underlying asset of the reserve
* @param reserveType Whether the reserve is boosted by a vault
* @param depositCap The new depositCap, a 0 means no deposit cap
*/
event ReserveDepositCapChanged(address indexed asset, bool reserveType, uint256 depositCap);
/**
* @dev Emitted when a reserve interest strategy contract is updated
* @param asset The address of the underlying asset of the reserve
* @param reserveType Whether the reserve is boosted by a vault
* @param strategy The new address of the interest strategy contract
*/
event ReserveInterestRateStrategyChanged(
address indexed asset, bool reserveType, address strategy
);
/**
* @dev Emitted when an aToken implementation is upgraded
* @param asset The address of the underlying asset of the reserve
* @param proxy The aToken proxy address
* @param implementation The new aToken implementation
* @param reserveType Whether the reserve is boosted by a vault
*/
event ATokenUpgraded(
address indexed asset,
address indexed proxy,
address indexed implementation,
bool reserveType
);
/**
* @dev Emitted when the implementation of a variable debt token is upgraded
* @param asset The address of the underlying asset of the reserve
* @param proxy The variable debt token proxy address
* @param implementation The new variable debt token implementation
*/
event VariableDebtTokenUpgraded(
address indexed asset, address indexed proxy, address indexed implementation
);
/**
* @dev Emitted when the total premium on flashloans is updated.
* @param oldFlashloanPremiumTotal The old premium, expressed in bps
* @param newFlashloanPremiumTotal The new premium, expressed in bps
*/
event FlashloanPremiumTotalUpdated(
uint128 oldFlashloanPremiumTotal, uint128 newFlashloanPremiumTotal
);
function batchInitReserve(InitReserveInput[] calldata input) external;
function updateAToken(UpdateATokenInput calldata input) external;
function updateVariableDebtToken(UpdateDebtTokenInput calldata input) external;
function enableBorrowingOnReserve(address asset, bool reserveType) external;
function disableBorrowingOnReserve(address asset, bool reserveType) external;
function configureReserveAsCollateral(
address asset,
bool reserveType,
uint256 ltv,
uint256 liquidationThreshold,
uint256 liquidationBonus
) external;
function activateReserve(address asset, bool reserveType) external;
function deactivateReserve(address asset, bool reserveType) external;
function freezeReserve(address asset, bool reserveType) external;
function unfreezeReserve(address asset, bool reserveType) external;
function enableFlashloan(address asset, bool reserveType) external;
function disableFlashloan(address asset, bool reserveType) external;
function setAsteraReserveFactor(address asset, bool reserveType, uint256 reserveFactor)
external;
function setDepositCap(address asset, bool reserveType, uint256 depositCap) external;
function setReserveInterestRateStrategyAddress(
address asset,
bool reserveType,
address rateStrategyAddress
) external;
function setPoolPause(bool val) external;
function updateFlashloanPremiumTotal(uint128 newFlashloanPremiumTotal) external;
function setFarmingPct(address aTokenAddress, uint256 farmingPct) external;
function setClaimingThreshold(address aTokenAddress, uint256 claimingThreshold) external;
function setFarmingPctDrift(address aTokenAddress, uint256 _farmingPctDrift) external;
function setProfitHandler(address aTokenAddress, address _profitHandler) external;
function setVault(address aTokenAddress, address _vault) external;
function rebalance(address aTokenAddress) external;
function getTotalManagedAssets(address aTokenAddress) external view returns (uint256);
function setRewarderForReserve(address asset, bool reserveType, address rewarder) external;
function setTreasury(address asset, bool reserveType, address rewarder) external;
function getIsAToken(address token) external view returns (bool);
}// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.8.0;
/**
* @title LendingPoolAddressesProvider interface.
* @author Conclave
*/
interface ILendingPoolAddressesProvider {
/**
* @dev Emitted when the market identifier is updated.
* @param newMarketId The new market identifier for the protocol.
*/
event MarketIdSet(string newMarketId);
/**
* @dev Emitted when the lending pool implementation is updated.
* @param newAddress The address of the new `LendingPool` implementation contract.
*/
event LendingPoolUpdated(address indexed newAddress);
/**
* @dev Emitted when the configuration admin is updated.
* @param newAddress The address of the new configuration admin that can modify pool parameters.
*/
event ConfigurationAdminUpdated(address indexed newAddress);
/**
* @dev Emitted when the emergency admin is updated.
* @param newAddress The address of the new emergency admin that can pause protocol functions.
*/
event EmergencyAdminUpdated(address indexed newAddress);
/**
* @dev Emitted when the lending pool configurator implementation is updated.
* @param newAddress The address of the new `LendingPoolConfigurator` implementation contract.
*/
event LendingPoolConfiguratorUpdated(address indexed newAddress);
/**
* @dev Emitted when the price oracle is updated.
* @param newAddress The address of the new `PriceOracle` contract used for asset price feeds.
*/
event PriceOracleUpdated(address indexed newAddress);
/**
* @dev Emitted when a new proxy contract is created.
* @param id The identifier `bytes32` of the proxy being created.
* @param newAddress The address of the newly created proxy contract.
*/
event ProxyCreated(bytes32 indexed id, address indexed newAddress);
/**
* @dev Emitted when an address mapping is set in the provider.
* @param id The identifier `bytes32` for the address being set.
* @param newAddress The new address being mapped to the identifier.
* @param hasProxy Boolean indicating if the address is set behind a proxy contract.
*/
event AddressSet(bytes32 id, address indexed newAddress, bool hasProxy);
/**
* @dev Emitted when the MiniPool addresses provider is updated.
* @param newAddress The new MiniPool addresses provider address.
*/
event MiniPoolAddressesProviderUpdated(address indexed newAddress);
/**
* @dev Emitted when the flow limiter is updated.
* @param newAddress The new flow limiter address.
*/
event FlowLimiterUpdated(address indexed newAddress);
function getMiniPoolAddressesProvider() external view returns (address);
function getLendingPool() external view returns (address);
function getLendingPoolConfigurator() external view returns (address);
function getPoolAdmin() external view returns (address);
function getEmergencyAdmin() external view returns (address);
function getPriceOracle() external view returns (address);
function getFlowLimiter() external view returns (address);
function getAddress(bytes32 id) external view returns (address);
function setAddress(bytes32 id, address newAddress) external;
function setAddressAsProxy(bytes32 id, address impl) external;
function setLendingPoolImpl(address pool) external;
function setLendingPoolConfiguratorImpl(address configurator) external;
function setPoolAdmin(address admin) external;
function setEmergencyAdmin(address admin) external;
function setPriceOracle(address priceOracle) external;
function setMiniPoolAddressesProvider(address provider) external;
function setFlowLimiter(address flowLimiter) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @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.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
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].
*
* CAUTION: See Security Considerations above.
*/
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 v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @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
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
uint256 size;
assembly {
size := extcodesize(account)
}
return size > 0;
}
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success,) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @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 or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* 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.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @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`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value)
internal
returns (bytes memory)
{
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data)
internal
view
returns (bytes memory)
{
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data)
internal
returns (bytes memory)
{
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(address target, bool success, bytes memory returndata)
internal
view
returns (bytes memory)
{
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata)
internal
pure
returns (bytes memory)
{
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) 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 FailedInnerCall();
}
}
}// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.8.23;
import {IERC20} from "../../../../contracts/dependencies/openzeppelin/contracts/IERC20.sol";
import {SafeERC20} from "../../../../contracts/dependencies/openzeppelin/contracts/SafeERC20.sol";
import {ILendingPool} from "../../../../contracts/interfaces/ILendingPool.sol";
import {IAToken} from "../../../../contracts/interfaces/IAToken.sol";
import {WadRayMath} from "../../../../contracts/protocol/libraries/math/WadRayMath.sol";
import {Errors} from "../../../../contracts/protocol/libraries/helpers/Errors.sol";
import {VersionedInitializable} from
"../../../../contracts/protocol/libraries/upgradeability/VersionedInitializable.sol";
import {IncentivizedERC20} from
"../../../../contracts/protocol/tokenization/ERC20/IncentivizedERC20.sol";
import {IRewarder} from "../../../../contracts/interfaces/IRewarder.sol";
import {IERC4626} from "lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC4626.sol";
import {ATokenNonRebasing} from
"../../../../contracts/protocol/tokenization/ERC20/ATokenNonRebasing.sol";
/**
* @title Astera ERC20 AToken
* @notice Implementation of the interest bearing token for the Astera protocol.
* @author Conclave
*/
contract AToken is
VersionedInitializable,
IncentivizedERC20("ATOKEN_IMPL", "ATOKEN_IMPL", 0),
IAToken
{
using WadRayMath for uint256;
using SafeERC20 for IERC20;
/// @notice Constant used for EIP712 domain revision.
bytes public constant EIP712_REVISION = bytes("1");
/// @notice EIP712 domain separator data structure hash.
bytes32 internal constant EIP712_DOMAIN = keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
);
/// @notice EIP712 typehash for permit function.
bytes32 public constant PERMIT_TYPEHASH = keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
);
/// @notice Current revision of the AToken implementation.
uint256 public constant ATOKEN_REVISION = 0x1;
/// @notice EIP712 domain separator.
bytes32 public DOMAIN_SEPARATOR;
/// @notice Flag indicating if the reserve is boosted by a vault.
bool public RESERVE_TYPE;
/// @notice Chain ID cached at contract deployment for EIP712 domain separator.
uint256 public CACHED_CHAIN_ID;
/// @notice Reference to the `ILendingPool` contract.
ILendingPool internal _pool;
/// @notice Address of the treasury receiving fees.
address internal _treasury;
/// @notice Address of the underlying asset.
address internal _underlyingAsset;
/// @notice Reference to the incentives controller contract.
IRewarder internal _incentivesController;
/// @notice Address of the non rebasing AToken wrapper address.
address internal _aTokenWrapper;
/// @notice Mapping of share allowances from owner to spender.
mapping(address => mapping(address => uint256)) internal _shareAllowances;
/// @notice Mapping of nonces for permit function.
mapping(address => uint256) public _nonces;
// ---- Rehypothecation related vars ----
/// @notice The ERC4626 vault contract that this aToken supplies tokens to for rehypothecation.
IERC4626 public _vault;
/// @notice The total amount of underlying tokens that have entered/exited this contract from protocol perspective.
uint256 public _underlyingAmount;
/// @notice The percentage of underlying tokens that should be rehypothecated to the vault.
uint256 public _farmingPct;
/// @notice The current amount of underlying tokens supplied to the vault.
uint256 public _farmingBal;
/// @notice The minimum profit amount that will trigger a claim.
uint256 public _claimingThreshold;
/// @notice The minimum percentage difference that will trigger rebalancing.
uint256 public _farmingPctDrift;
/// @notice The address that receives claimed profits.
address public _profitHandler;
constructor() {
_blockInitializing();
}
/**
* @notice Modifier to ensure only the lending pool can call certain functions.
* @dev Reverts if the caller is not the lending pool contract.
*/
modifier onlyLendingPool() {
require(msg.sender == address(_pool), Errors.AT_CALLER_MUST_BE_LENDING_POOL);
_;
}
/**
* @notice Returns the current revision number of this implementation.
* @dev Implements the VersionedInitializable interface.
* @return The revision number of this contract.
*/
function getRevision() internal pure virtual override returns (uint256) {
return ATOKEN_REVISION;
}
/**
* @notice Initializes the aToken contract with its core configuration.
* @dev Sets up the token metadata, pool references, and EIP712 domain separator.
* @param pool The address of the lending pool where this aToken will be used.
* @param treasury The address of the Astera treasury, receiving the fees on this aToken.
* @param underlyingAsset The address of the underlying asset of this aToken (E.g. `WETH` for aWETH).
* @param incentivesController The smart contract managing potential incentives distribution.
* @param aTokenDecimals The decimals of the aToken, same as the underlying asset's.
* @param reserveType Whether the reserve is boosted by a vault.
* @param aTokenName The name of the aToken.
* @param aTokenSymbol The symbol of the aToken.
* @param params Additional params to configure contract.
*/
function initialize(
ILendingPool pool,
address treasury,
address underlyingAsset,
IRewarder incentivesController,
uint8 aTokenDecimals,
bool reserveType,
string calldata aTokenName,
string calldata aTokenSymbol,
bytes calldata params
) external override initializer {
_setName(aTokenName);
_setSymbol(aTokenSymbol);
_setDecimals(aTokenDecimals);
DOMAIN_SEPARATOR = _buildDomainSeparator();
CACHED_CHAIN_ID = block.chainid;
RESERVE_TYPE = reserveType;
_pool = pool;
_treasury = treasury;
_underlyingAsset = underlyingAsset;
_incentivesController = incentivesController;
if (_aTokenWrapper == address(0)) {
_aTokenWrapper = address(new ATokenNonRebasing(address(this)));
}
emit Initialized(
underlyingAsset,
address(pool),
_aTokenWrapper,
_treasury,
address(incentivesController),
aTokenDecimals,
reserveType,
aTokenName,
aTokenSymbol,
params
);
}
/**
* @notice Burns aTokens and transfers underlying tokens to a specified receiver.
* @dev Only callable by the LendingPool contract.
* @param user The owner of the aTokens getting burned.
* @param receiverOfUnderlying The address that will receive the underlying tokens.
* @param amount The amount of tokens being burned.
* @param index The new liquidity index of the reserve.
*/
function burn(address user, address receiverOfUnderlying, uint256 amount, uint256 index)
external
override
onlyLendingPool
{
uint256 amountScaled = amount.rayDiv(index);
require(amountScaled != 0, Errors.AT_INVALID_BURN_AMOUNT);
_rebalance(amount);
_underlyingAmount = _underlyingAmount - amount;
_burn(user, amountScaled);
IERC20(_underlyingAsset).safeTransfer(receiverOfUnderlying, amount);
emit Transfer(user, address(0), amount);
emit Burn(user, receiverOfUnderlying, amount, index);
}
/**
* @notice Mints new aTokens to a specified user.
* @dev Only callable by the LendingPool contract.
* @param user The address receiving the minted tokens.
* @param amount The amount of tokens to mint.
* @param index The new liquidity index of the reserve.
* @return True if the previous balance of the user was 0.
*/
function mint(address user, uint256 amount, uint256 index)
external
override
onlyLendingPool
returns (bool)
{
uint256 previousBalance = super.balanceOf(user);
uint256 amountScaled = amount.rayDiv(index);
require(amountScaled != 0, Errors.AT_INVALID_MINT_AMOUNT);
_underlyingAmount = _underlyingAmount + amount;
_rebalance(0);
_mint(user, amountScaled);
emit Transfer(address(0), user, amount);
emit Mint(user, amount, index);
return previousBalance == 0;
}
/**
* @notice Mints aTokens to the Astera treasury.
* @dev Only callable by the LendingPool contract. Does not check for rounding errors.
* @param amount The amount of tokens to mint.
* @param index The new liquidity index of the reserve.
*/
function mintToAsteraTreasury(uint256 amount, uint256 index)
external
override
onlyLendingPool
{
if (amount == 0) {
return;
}
address treasury = _treasury;
// Compared to the normal mint, we don't check for rounding errors.
// The amount to mint can easily be very small since it is a fraction of the interest accrued.
// In that case, the treasury will experience a (very small) loss, but it
// won't cause potentially valid transactions to fail.
_mint(treasury, amount.rayDiv(index));
emit Transfer(address(0), treasury, amount);
emit Mint(treasury, amount, index);
}
/**
* @notice Transfers aTokens during liquidation.
* @dev Only callable by the LendingPool contract.
* @param from The address getting liquidated, current owner of the aTokens.
* @param to The recipient of the aTokens.
* @param value The amount of tokens being transferred.
*/
function transferOnLiquidation(address from, address to, uint256 value)
external
override
onlyLendingPool
{
// Being a normal transfer, the Transfer() and BalanceTransfer() are emitted
// so no need to emit a specific event here.
_transfer(from, to, value, false);
emit Transfer(from, to, value);
}
/**
* @dev Calculates the balance of the user: principal balance + interest generated by the principal.
* @param user The user whose balance is calculated.
* @return The balance of the user.
*/
function balanceOf(address user)
public
view
override(IncentivizedERC20, IERC20)
returns (uint256)
{
return super.balanceOf(user).rayMul(
_pool.getReserveNormalizedIncome(_underlyingAsset, RESERVE_TYPE)
);
}
/**
* @dev Returns the scaled balance of the user. The scaled balance is the sum of all the
* updated stored balance divided by the reserve's liquidity index at the moment of the update.
* @param user The user whose balance is calculated.
* @return The scaled balance of the user.
*/
function scaledBalanceOf(address user) external view override returns (uint256) {
return super.balanceOf(user);
}
/**
* @dev Returns the scaled balance of the user and the scaled total supply.
* @param user The address of the user.
* @return The scaled balance of the user.
* @return The scaled total supply.
*/
function getScaledUserBalanceAndSupply(address user)
external
view
override
returns (uint256, uint256)
{
return (super.balanceOf(user), super.totalSupply());
}
/**
* @dev Calculates the total supply of the specific aToken.
* Since the balance of every single user increases over time, the total supply
* does that too.
* @return The current total supply.
*/
function totalSupply() public view override(IncentivizedERC20, IERC20) returns (uint256) {
uint256 currentSupplyScaled = super.totalSupply();
if (currentSupplyScaled == 0) {
return 0;
}
return currentSupplyScaled.rayMul(
_pool.getReserveNormalizedIncome(_underlyingAsset, RESERVE_TYPE)
);
}
/**
* @dev Returns the scaled total supply of the variable debt token. Represents sum(debt/index).
* @return The scaled total supply.
*/
function scaledTotalSupply() public view virtual override returns (uint256) {
return super.totalSupply();
}
/// @dev Returns the address of the Astera treasury, receiving the fees on this aToken.
function RESERVE_TREASURY_ADDRESS() public view returns (address) {
return _treasury;
}
/// @dev Returns the address of the underlying asset of this aToken (E.g. `WETH` for aWETH).
function UNDERLYING_ASSET_ADDRESS() public view override returns (address) {
return _underlyingAsset;
}
/// @dev Returns the address of the lending pool where this aToken is used.
function POOL() public view returns (ILendingPool) {
return _pool;
}
/// @dev For internal usage in the logic of the parent contract `IncentivizedERC20`.
function _getIncentivesController() internal view override returns (IRewarder) {
return _incentivesController;
}
/// @dev Returns the address of the incentives controller contract.
function getIncentivesController() external view override returns (IRewarder) {
return _getIncentivesController();
}
/**
* @dev Transfers the underlying asset to `target`. Used by the LendingPool to transfer
* assets in borrow(), withdraw() and flashLoan().
* @param target The recipient of the aTokens.
* @param amount The amount getting transferred.
* @return The amount transferred.
*/
function transferUnderlyingTo(address target, uint256 amount)
external
override
onlyLendingPool
returns (uint256)
{
_rebalance(amount);
_underlyingAmount = _underlyingAmount - amount;
IERC20(_underlyingAsset).safeTransfer(target, amount);
return amount;
}
/**
* @dev Invoked to execute actions on the aToken side after a repayment.
* @param user The user executing the repayment.
* @param onBehalfOf The user beneficiary.
* @param amount The amount getting repaid.
*/
function handleRepayment(address user, address onBehalfOf, uint256 amount)
external
override
onlyLendingPool
{
_underlyingAmount = _underlyingAmount + amount;
_rebalance(0);
}
/**
* @dev Implements the permit function as per
* https://github.com/ethereum/EIPs/blob/8a34d644aacf0f9f8f00815307fd7dd5da07655f/EIPS/eip-2612.md.
* @param owner The owner of the funds.
* @param spender The spender.
* @param value The amount.
* @param deadline The deadline timestamp, type(uint256).max for max deadline.
* @param v Signature param.
* @param s Signature param.
* @param r Signature param.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external {
require(owner != address(0), Errors.AT_INVALID_ADDRESS);
require(block.timestamp <= deadline, Errors.AT_INVALID_EXPIRATION);
uint256 currentValidNonce = _nonces[owner];
bytes32 digest = keccak256(
abi.encodePacked(
"\x19\x01",
_domainSeparator(),
keccak256(
abi.encode(PERMIT_TYPEHASH, owner, spender, value, currentValidNonce, deadline)
)
)
);
require(owner == ecrecover(digest, v, r, s), Errors.AT_INVALID_SIGNATURE);
_nonces[owner] = currentValidNonce + 1;
_approve(owner, spender, value);
}
/**
* @dev Returns the domain separator for the current chain.
*/
function _domainSeparator() internal view returns (bytes32) {
if (block.chainid == CACHED_CHAIN_ID) {
return DOMAIN_SEPARATOR;
} else {
return _buildDomainSeparator();
}
}
function _buildDomainSeparator() private view returns (bytes32) {
return keccak256(
abi.encode(
EIP712_DOMAIN,
keccak256(bytes(name())),
keccak256(EIP712_REVISION),
block.chainid,
address(this)
)
);
}
/**
* @dev Transfers the aTokens between two users. Validates the transfer
* (ie checks for valid HF after the transfer) if required.
* @param from The source address.
* @param to The destination address.
* @param amount The amount getting transferred.
* @param validate `true` if the transfer needs to be validated.
*/
function _transfer(address from, address to, uint256 amount, bool validate) internal {
address underlyingAsset = _underlyingAsset;
ILendingPool pool = _pool;
uint256 index = pool.getReserveNormalizedIncome(underlyingAsset, RESERVE_TYPE);
uint256 fromBalanceBefore = super.balanceOf(from).rayMul(index);
uint256 toBalanceBefore = super.balanceOf(to).rayMul(index);
super._transfer(from, to, amount.rayDiv(index));
if (validate) {
pool.finalizeTransfer(
underlyingAsset, RESERVE_TYPE, from, to, amount, fromBalanceBefore, toBalanceBefore
);
}
emit BalanceTransfer(from, to, amount, index);
}
/**
* @dev Overrides the parent _transfer to force validated transfer() and transferFrom().
* @param from The source address.
* @param to The destination address.
* @param amount The amount getting transferred.
*/
function _transfer(address from, address to, uint256 amount) internal override {
_transfer(from, to, amount, true);
}
/// --------- Share logic ---------
/**
* @dev Transfers the aToken shares between two users. Validates the transfer
* (ie checks for valid HF after the transfer) if required.
* Restricted to `_aTokenWrapper`.
* @param from The source address.
* @param to The destination address.
* @param shareAmount The share amount getting transferred.
*/
function transferShare(address from, address to, uint256 shareAmount) external {
require(msg.sender == _aTokenWrapper, Errors.AT_CALLER_NOT_WRAPPER);
address underlyingAsset = _underlyingAsset;
ILendingPool pool = _pool;
uint256 index = pool.getReserveNormalizedIncome(underlyingAsset, RESERVE_TYPE);
uint256 fromBalanceBefore = super.balanceOf(from).rayMul(index);
uint256 toBalanceBefore = super.balanceOf(to).rayMul(index);
super._transfer(from, to, shareAmount);
uint256 amount = shareAmount.rayMul(index);
pool.finalizeTransfer(
underlyingAsset, RESERVE_TYPE, from, to, amount, fromBalanceBefore, toBalanceBefore
);
emit BalanceTransfer(from, to, amount, index);
}
/**
* @dev Allows `spender` to spend the shares owned by `owner`.
* Restricted to `_aTokenWrapper`.
* @param owner The owner of the shares.
* @param spender The user allowed to spend owner tokens.
* @param shareAmount The share amount getting approved.
*/
function shareApprove(address owner, address spender, uint256 shareAmount) external {
require(msg.sender == _aTokenWrapper, Errors.AT_CALLER_NOT_WRAPPER);
_shareAllowances[owner][spender] = shareAmount;
}
/**
* @dev Returns the share allowance for a given owner and spender.
* @param owner The owner of the shares.
* @param spender The spender address.
* @return The current share allowance.
*/
function shareAllowances(address owner, address spender) external view returns (uint256) {
return _shareAllowances[owner][spender];
}
/// @dev Returns the address of the wrapper contract for this aToken.
function WRAPPER_ADDRESS() external view returns (address) {
return _aTokenWrapper;
}
/**
* @dev Converts an asset amount to share amount.
* @param assetAmount The amount of assets to convert.
* @return The equivalent amount in shares.
*/
function convertToShares(uint256 assetAmount) external view returns (uint256) {
return assetAmount.rayDiv(_pool.getReserveNormalizedIncome(_underlyingAsset, RESERVE_TYPE));
}
/**
* @dev Converts a share amount to asset amount.
* @param shareAmount The amount of shares to convert.
* @return The equivalent amount in assets.
*/
function convertToAssets(uint256 shareAmount) external view returns (uint256) {
return shareAmount.rayMul(_pool.getReserveNormalizedIncome(_underlyingAsset, RESERVE_TYPE));
}
/// --------- Rehypothecation logic ---------
/**
* @dev Rebalances the internal allocation of funds between the contract and the vault.
* @notice This function ensures there is enough liquidity to process a future transfer by freeing up `_amountToWithdraw`.
* @param _amountToWithdraw The amount of tokens that needs to be made available for withdrawal.
*/
function _rebalance(uint256 _amountToWithdraw) internal {
if (_farmingPct == 0 && _farmingBal == 0) {
return;
}
// How much has been allocated as per our internal records?
uint256 currentAllocated = _farmingBal;
// What is the present value of our shares?
uint256 ownedShares = IERC20(address(_vault)).balanceOf(address(this));
uint256 sharesToAssets = _vault.convertToAssets(ownedShares);
uint256 profit;
uint256 toWithdraw;
uint256 toDeposit;
// If we have profit that's more than the threshold, record it for withdrawal and redistribution.
if (
sharesToAssets > currentAllocated
&& sharesToAssets - currentAllocated >= _claimingThreshold
) {
profit = sharesToAssets - currentAllocated;
}
// What % of the final pool balance would the current allocation be?
uint256 finalBalance = _underlyingAmount - _amountToWithdraw;
uint256 pctOfFinalBal =
finalBalance == 0 ? type(uint256).max : currentAllocated * 10000 / finalBalance;
// If abs(percentOfFinalBal - yieldingPercentage) > drift, we will need to deposit more or withdraw some.
uint256 finalFarmingAmount = finalBalance * _farmingPct / 10000;
if (pctOfFinalBal > _farmingPct && pctOfFinalBal - _farmingPct > _farmingPctDrift) {
// We will end up overallocated, withdraw some.
toWithdraw = currentAllocated - finalFarmingAmount;
currentAllocated = currentAllocated - toWithdraw;
} else if (pctOfFinalBal < _farmingPct && _farmingPct - pctOfFinalBal > _farmingPctDrift) {
// We will end up underallocated, deposit more.
toDeposit = finalFarmingAmount - currentAllocated;
currentAllocated = currentAllocated + toDeposit;
}
// + means deposit, - means withdraw.
int256 netAssetMovement = int256(toDeposit) - int256(toWithdraw) - int256(profit);
if (netAssetMovement > 0) {
try _vault.deposit(uint256(netAssetMovement), address(this)) {}
catch {
return;
}
} else if (netAssetMovement < 0) {
try _vault.withdraw(uint256(-netAssetMovement), address(this), address(this)) {}
catch {
return;
}
}
// If we recorded profit, recalculate it for precision and distribute.
if (profit != 0) {
// Profit is ultimately (coll at hand) + (coll allocated to yield generator) - (recorded total coll Amount in pool).
profit = IERC20(_underlyingAsset).balanceOf(address(this)) + currentAllocated
- _underlyingAmount;
if (profit != 0 && _profitHandler != address(0)) {
// Distribute to profitHandler.
IERC20(_underlyingAsset).safeTransfer(_profitHandler, profit);
}
}
_farmingBal = currentAllocated;
emit Rebalance(address(_vault), _amountToWithdraw, netAssetMovement);
}
/**
* @dev Sets the farming percentage for yield generation.
* @param farmingPct The new farming percentage (0-10000).
*/
function setFarmingPct(uint256 farmingPct) external override onlyLendingPool {
require(address(_vault) != address(0), Errors.AT_VAULT_NOT_INITIALIZED);
require(address(_profitHandler) != address(0), Errors.AT_PROFIT_HANDLER_SET);
require(farmingPct <= 10000, Errors.AT_INVALID_AMOUNT);
_farmingPct = farmingPct;
emit FarmingPctSet(farmingPct);
}
/**
* @dev Sets the claiming threshold for profit distribution.
* @param claimingThreshold The new claiming threshold.
*/
function setClaimingThreshold(uint256 claimingThreshold) external override onlyLendingPool {
require(address(_vault) != address(0), Errors.AT_VAULT_NOT_INITIALIZED);
require(address(_profitHandler) != address(0), Errors.AT_PROFIT_HANDLER_SET);
_claimingThreshold = claimingThreshold;
emit ClaimingThresholdSet(claimingThreshold);
}
/**
* @dev Sets the farming percentage drift threshold.
* @param farmingPctDrift The new farming percentage drift (0-10000).
*/
function setFarmingPctDrift(uint256 farmingPctDrift) external override onlyLendingPool {
require(farmingPctDrift <= 10000, Errors.AT_INVALID_AMOUNT);
require(address(_vault) != address(0), Errors.AT_VAULT_NOT_INITIALIZED);
require(address(_profitHandler) != address(0), Errors.AT_PROFIT_HANDLER_SET);
_farmingPctDrift = farmingPctDrift;
emit FarmingPctDriftSet(farmingPctDrift);
}
/**
* @dev Sets the profit handler address.
* @param profitHandler The new profit handler address.
*/
function setProfitHandler(address profitHandler) external override onlyLendingPool {
require(profitHandler != address(0), Errors.AT_INVALID_ADDRESS);
_profitHandler = profitHandler;
emit ProfitHandlerSet(profitHandler);
}
/**
* @dev Sets the vault address for yield generation.
* @param vault The new vault address.
*/
function setVault(address vault) external override onlyLendingPool {
require(address(vault) != address(0), Errors.AT_INVALID_ADDRESS);
require(address(_profitHandler) != address(0), Errors.AT_PROFIT_HANDLER_SET);
if (address(_vault) != address(0)) {
require(_farmingBal == 0, Errors.AT_VAULT_NOT_EMPTY);
}
require(IERC4626(vault).asset() == _underlyingAsset, Errors.AT_INVALID_ADDRESS);
_vault = IERC4626(vault);
IERC20(_underlyingAsset).forceApprove(address(_vault), type(uint256).max);
emit VaultSet(vault);
}
/**
* @dev Sets the treasury address.
* @param treasury The new treasury address.
*/
function setTreasury(address treasury) external override onlyLendingPool {
require(treasury != address(0), Errors.AT_INVALID_ADDRESS);
_treasury = treasury;
emit TreasurySet(treasury);
}
/**
* @dev Sets the incentives controller address.
* @param incentivesController The new incentives controller address.
*/
function setIncentivesController(address incentivesController)
external
override
onlyLendingPool
{
require(incentivesController != address(0), Errors.AT_INVALID_ADDRESS);
_incentivesController = IRewarder(incentivesController);
emit IncentivesControllerSet(incentivesController);
}
/**
* @dev Triggers a rebalance of the vault allocation.
*/
function rebalance() external override onlyLendingPool {
_rebalance(0);
}
/// @dev Returns the total balance of underlying asset of this token, including balance lent to a vault.
function getTotalManagedAssets() public view override returns (uint256) {
return _underlyingAmount;
}
/// @dev Returns the address of the lending pool contract.
function getPool() external view returns (address) {
return address(_pool);
}
}// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.8.0;
import {ILendingPoolAddressesProvider} from
"../../contracts/interfaces/ILendingPoolAddressesProvider.sol";
import {DataTypes} from "../../contracts/protocol/libraries/types/DataTypes.sol";
/**
* @title ILendingPool interface.
* @author Conclave
*/
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
*/
event Deposit(
address indexed reserve, address user, address indexed onBehalfOf, uint256 amount
);
/**
* @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 borrowRate The numeric rate at which the user has borrowed
*/
event Borrow(
address indexed reserve,
address user,
address indexed onBehalfOf,
uint256 amount,
uint256 borrowRate
);
/**
* @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 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 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 interestRateMode The interest rate mode selected for the flash loan:
* 0 -> Don't open any debt, just revert if funds can't be transferred from the receiver
* != 0 -> Open debt at variable rate for the value of the amount flash-borrowed
* @param amount The amount flash borrowed
* @param premium The fee charged for the flash loan
*/
event FlashLoan(
address indexed target,
address indexed initiator,
address indexed asset,
DataTypes.InterestRateMode interestRateMode,
uint256 amount,
uint256 premium
);
/**
* @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 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 variableBorrowRate,
uint256 liquidityIndex,
uint256 variableBorrowIndex
);
/**
* @dev Emitted when the flash loan fee is updated.
* @param flashLoanPremiumTotal The new flash loan fee.
*/
event FlashLoanFeeUpdated(uint128 flashLoanPremiumTotal);
function deposit(address asset, bool reserveType, uint256 amount, address onBehalfOf)
external;
function withdraw(address asset, bool reserveType, uint256 amount, address to)
external
returns (uint256);
function borrow(address asset, bool reserveType, uint256 amount, address onBehalfOf) external;
function repay(address asset, bool reserveType, uint256 amount, address onBehalfOf)
external
returns (uint256);
function miniPoolBorrow(address asset, uint256 amount, address aTokenAddress) external;
function repayWithATokens(address asset, bool reserveType, uint256 amount)
external
returns (uint256);
function setUserUseReserveAsCollateral(address asset, bool reserveType, bool useAsCollateral)
external;
function liquidationCall(
address collateralAsset,
bool collateralAssetType,
address debtAsset,
bool debtAssetType,
address user,
uint256 debtToCover,
bool receiveAToken
) external;
struct FlashLoanParams {
address receiverAddress;
address[] assets;
bool[] reserveTypes;
address onBehalfOf;
}
function flashLoan(
FlashLoanParams memory flashLoanParams,
uint256[] calldata amounts,
uint256[] calldata modes,
bytes calldata params
) external;
function getUserAccountData(address user)
external
view
returns (
uint256 totalCollateralETH,
uint256 totalDebtETH,
uint256 availableBorrowsETH,
uint256 currentLiquidationThreshold,
uint256 ltv,
uint256 healthFactor
);
function initReserve(
address reserve,
bool reserveType,
address aTokenAddress,
address variableDebtAddress,
address interestRateStrategyAddress
) external;
function setReserveInterestRateStrategyAddress(
address reserve,
bool reserveType,
address rateStrategyAddress
) external;
function setConfiguration(address reserve, bool reserveType, uint256 configuration) external;
function getConfiguration(address asset, bool reserveType)
external
view
returns (DataTypes.ReserveConfigurationMap memory);
function getUserConfiguration(address user)
external
view
returns (DataTypes.UserConfigurationMap memory);
function getReserveNormalizedIncome(address asset, bool reserveType)
external
view
returns (uint256);
function getReserveNormalizedVariableDebt(address asset, bool reserveType)
external
view
returns (uint256);
function getReserveData(address asset, bool reserveType)
external
view
returns (DataTypes.ReserveData memory);
function finalizeTransfer(
address asset,
bool reserveType,
address from,
address to,
uint256 amount,
uint256 balanceFromBefore,
uint256 balanceToBefore
) external;
function getReservesList() external view returns (address[] memory, bool[] memory);
function getReservesCount() external view returns (uint256);
function getAddressesProvider() external view returns (ILendingPoolAddressesProvider);
function MAX_NUMBER_RESERVES() external view returns (uint256);
function setPause(bool val) external;
function paused() external view returns (bool);
function setFarmingPct(address aTokenAddress, uint256 farmingPct) external;
function setClaimingThreshold(address aTokenAddress, uint256 claimingThreshold) external;
function setFarmingPctDrift(address aTokenAddress, uint256 farmingPctDrift) external;
function setProfitHandler(address aTokenAddress, address profitHandler) external;
function setVault(address aTokenAddress, address vault) external;
function rebalance(address aTokenAddress) external;
function getTotalManagedAssets(address aTokenAddress) external view returns (uint256);
function updateFlashLoanFee(uint128 flashLoanPremiumTotal) external;
function setRewarderForReserve(address asset, bool reserveType, address rewarder) external;
function setTreasury(address asset, bool reserveType, address treasury) external;
function FLASHLOAN_PREMIUM_TOTAL() external view returns (uint128);
function getATokenNonRebasingFromAtoken(address aToken) external view returns (address);
function syncIndexesState(address asset, bool reserveType) external;
function syncRatesState(address asset, bool reserveType) external;
function getMinipoolFlowBorrowing(address asset) external view returns (address[] memory);
}// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.8.0;
import {IERC20} from "../../contracts/dependencies/openzeppelin/contracts/IERC20.sol";
import {IScaledBalanceToken} from "../../contracts/interfaces/base/IScaledBalanceToken.sol";
import {IInitializableAToken} from "../../contracts/interfaces/base/IInitializableAToken.sol";
import {IRewarder} from "../../contracts/interfaces/IRewarder.sol";
/**
* @title IAToken interface.
* @author Conclave
*/
interface IAToken is IERC20, IScaledBalanceToken, IInitializableAToken {
/**
* @dev Emitted after the mint action.
* @param user The address performing the mint.
* @param amount The amount being.
* @param index The new liquidity index of the reserve.
*/
event Mint(address indexed user, uint256 amount, uint256 index);
/**
* @dev Emitted after aTokens are burned.
* @param user The owner of the aTokens, getting them burned.
* @param target The address that will receive the underlying.
* @param amount The amount being burned.
* @param index The new liquidity index of the reserve.
*/
event Burn(address indexed user, address indexed target, uint256 amount, uint256 index);
/**
* @dev Emitted during the transfer action.
* @param user The user whose tokens are being transferred.
* @param to The recipient.
* @param amount The amount being transferred.
* @param index The new liquidity index of the reserve.
*/
event BalanceTransfer(address indexed user, address indexed to, uint256 amount, uint256 index);
/**
* @dev Emitted during the rebalance action.
* @param vault The vault that is being interacted with.
* @param amountToWithdraw The amount of asset that needs to be free after the rebalance.
* @param netAssetMovement The amount of asset being deposited into (if positive) or withdrawn from (if negative) the vault.
*/
event Rebalance(address indexed vault, uint256 amountToWithdraw, int256 netAssetMovement);
/**
* @dev Emitted when the farming percentage is set.
* @param farmingPct The new farming percentage.
*/
event FarmingPctSet(uint256 farmingPct);
/**
* @dev Emitted when the claiming threshold is set.
* @param claimingThreshold The new claiming threshold.
*/
event ClaimingThresholdSet(uint256 claimingThreshold);
/**
* @dev Emitted when the farming percentage drift is set.
* @param farmingPctDrift The new farming percentage drift.
*/
event FarmingPctDriftSet(uint256 farmingPctDrift);
/**
* @dev Emitted when the profit handler is set.
* @param profitHandler The new profit handler address.
*/
event ProfitHandlerSet(address profitHandler);
/**
* @dev Emitted when the vault is set.
* @param vault The new vault address.
*/
event VaultSet(address vault);
/**
* @dev Emitted when the treasury is set.
* @param treasury The new treasury address.
*/
event TreasurySet(address treasury);
/**
* @dev Emitted when the incentives controller is set.
* @param incentivesController The new incentives controller address.
*/
event IncentivesControllerSet(address incentivesController);
function mint(address user, uint256 amount, uint256 index) external returns (bool);
function burn(address user, address receiverOfUnderlying, uint256 amount, uint256 index)
external;
function mintToAsteraTreasury(uint256 amount, uint256 index) external;
function transferOnLiquidation(address from, address to, uint256 value) external;
function transferUnderlyingTo(address user, uint256 amount) external returns (uint256);
function handleRepayment(address user, address onBehalfOf, uint256 amount) external;
function getIncentivesController() external view returns (IRewarder);
function UNDERLYING_ASSET_ADDRESS() external view returns (address);
function RESERVE_TYPE() external view returns (bool);
/// --------- Share logic ---------
function transferShare(address from, address to, uint256 shareAmount) external;
function shareApprove(address owner, address spender, uint256 shareAmount) external;
function shareAllowances(address owner, address spender) external view returns (uint256);
function WRAPPER_ADDRESS() external view returns (address);
function convertToShares(uint256 assetAmount) external view returns (uint256);
function convertToAssets(uint256 shareAmount) external view returns (uint256);
/// --------- Rehypothecation logic ---------
function getTotalManagedAssets() external view returns (uint256);
function setFarmingPct(uint256 _farmingPct) external;
function setClaimingThreshold(uint256 _claimingThreshold) external;
function setFarmingPctDrift(uint256 _farmingPctDrift) external;
function setProfitHandler(address _profitHandler) external;
function setVault(address _vault) external;
function setTreasury(address _treasury) external;
function setIncentivesController(address _incentivesController) external;
function rebalance() external;
function getPool() external view returns (address);
}// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.8.23;
import {Errors} from "../../../../contracts/protocol/libraries/helpers/Errors.sol";
/**
* @title WadRayMath library
* @author Conclave
* @notice Provides multiplication and division functions for wads (decimal numbers with 18 digits precision) and rays (decimals with 27 digits precision).
* @dev Core math library for precise decimal calculations using wad (1e18) and ray (1e27) units.
*/
library WadRayMath {
uint256 internal constant WAD = 1e18;
uint256 internal constant halfWAD = WAD / 2;
uint256 internal constant RAY = 1e27;
uint256 internal constant halfRAY = RAY / 2;
int256 internal constant RAYint = 1e27;
int256 internal constant halfRAYint = RAYint / 2;
uint256 internal constant WAD_RAY_RATIO = 1e9;
/// @return One ray, `1e27`.
function ray() internal pure returns (uint256) {
return RAY;
}
/// @return One wad, `1e18`.
function wad() internal pure returns (uint256) {
return WAD;
}
/// @return Half ray, `1e27/2`.
function halfRay() internal pure returns (uint256) {
return halfRAY;
}
/// @return Half wad, `1e18/2`.
function halfWad() internal pure returns (uint256) {
return halfWAD;
}
/**
* @notice Converts ray number down to wad precision.
* @param a Ray number to convert.
* @return The input `a` converted to wad, rounded half up to the nearest wad.
*/
function rayToWad(uint256 a) internal pure returns (uint256) {
uint256 halfRatio = WAD_RAY_RATIO / 2;
uint256 result = halfRatio + a;
return result / WAD_RAY_RATIO;
}
/**
* @notice Converts wad number up to ray precision.
* @param a Wad number to convert.
* @return The input `a` converted to ray precision.
*/
function wadToRay(uint256 a) internal pure returns (uint256) {
uint256 result = a * WAD_RAY_RATIO;
return result;
}
// ----------- Classic operations -----------
/**
* @notice Divides two numbers, rounding up to the nearest uint.
* @dev Inspired from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/Math.sol.
* @param a Number to divide (numerator).
* @param b Number to divide by (denominator).
* @return The result of `a/b`, rounded up to the nearest uint.
*/
function divUp(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0, Errors.MATH_DIVISION_BY_ZERO);
// The following calculation ensures accurate ceiling division without overflow.
// Since a is non-zero, (a - 1) / b will not overflow.
// The largest possible result occurs when (a - 1) / b is type(uint256).max,
// but the largest value we can obtain is type(uint256).max - 1, which happens
// when a = type(uint256).max and b = 1.
unchecked {
return _toUint(a > 0) * ((a - 1) / b + 1);
}
}
/**
* @notice Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.
* @dev Inspired from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeCast.sol.
*/
function _toUint(bool b) internal pure returns (uint256 u) {
assembly ("memory-safe") {
u := iszero(iszero(b))
}
}
// ----------- WAD operations -----------
/**
* @notice Multiplies two wad numbers, rounding half up to the nearest wad.
* @param a First wad number to multiply.
* @param b Second wad number to multiply.
* @return The result of `a*b`, in wad precision.
*/
function wadMul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0 || b == 0) {
return 0;
}
require(a <= (type(uint256).max - halfWAD) / b, Errors.MATH_MULTIPLICATION_OVERFLOW);
return (a * b + halfWAD) / WAD;
}
/**
* @notice Divides two wad numbers, rounding half up to the nearest wad.
* @param a Wad number to divide (numerator).
* @param b Wad number to divide by (denominator).
* @return The result of `a/b`, in wad precision.
*/
function wadDiv(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0, Errors.MATH_DIVISION_BY_ZERO);
uint256 halfB = b / 2;
require(a <= (type(uint256).max - halfB) / WAD, Errors.MATH_MULTIPLICATION_OVERFLOW);
return (a * WAD + halfB) / b;
}
/**
* @notice Divides two wad numbers, rounding up to the nearest wad.
* @param a Wad number to divide (numerator).
* @param b Wad number to divide by (denominator).
* @return The result of `a/b`, in wad precision.
*/
function wadDivUp(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0, Errors.MATH_DIVISION_BY_ZERO);
require(a <= (type(uint256).max - b) / WAD, Errors.MATH_MULTIPLICATION_OVERFLOW);
return (a * WAD + b) / b;
}
// ----------- RAY operations -----------
/**
* @notice Multiplies two ray numbers, rounding half up to the nearest ray.
* @param a First ray number to multiply.
* @param b Second ray number to multiply.
* @return The result of `a*b`, in ray precision.
*/
function rayMul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0 || b == 0) {
return 0;
}
require(a <= (type(uint256).max - halfRAY) / b, Errors.MATH_MULTIPLICATION_OVERFLOW);
return (a * b + halfRAY) / RAY;
}
/**
* @notice Divides two ray numbers, rounding half up to the nearest ray.
* @param a Ray number to divide (numerator).
* @param b Ray number to divide by (denominator).
* @return The result of `a/b`, in ray precision.
*/
function rayDiv(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0, Errors.MATH_DIVISION_BY_ZERO);
uint256 halfB = b / 2;
require(a <= (type(uint256).max - halfB) / RAY, Errors.MATH_MULTIPLICATION_OVERFLOW);
return (a * RAY + halfB) / b;
}
/**
* @notice Divides two ray numbers, rounding up to the nearest ray.
* @param a Ray number to divide (numerator).
* @param b Ray number to divide by (denominator).
* @return The result of `a/b`, in ray precision.
*/
function rayDivUp(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0, Errors.MATH_DIVISION_BY_ZERO);
require(a <= (type(uint256).max - b) / RAY, Errors.MATH_MULTIPLICATION_OVERFLOW);
return (a * RAY + b) / b;
}
// ----------- RAY Int operations -----------
/**
* @notice Multiplies two ray integers, rounding half up to the nearest ray.
* @dev If `result` > 0 rounds up, if `result` < 0 rounds down.
* @param a First ray integer to multiply.
* @param b Second ray integer to multiply.
* @return result The result of `a*b`, in ray precision.
*/
function rayMulInt(int256 a, int256 b) internal pure returns (int256) {
int256 rawMul = a * b;
if (rawMul < 0) {
return (rawMul - halfRAYint) / RAYint;
} else if (rawMul > 0) {
return (rawMul + halfRAYint) / RAYint;
} else {
// if (a == 0 || b == 0)
return 0;
}
}
/**
* @notice Divides two ray integers, rounding half up to the nearest ray.
* @dev If `result` > 0 rounds up, if `result` < 0 rounds down.
* @param a Ray integer to divide (numerator).
* @param b Ray integer to divide by (denominator).
* @return The result of `a/b`, in ray precision.
*/
function rayDivInt(int256 a, int256 b) internal pure returns (int256) {
require(b != 0, Errors.MATH_DIVISION_BY_ZERO);
int256 halfB = b / 2;
if (a >= 0 && b > 0 || a <= 0 && b < 0) {
return (a * RAYint + halfB) / b;
} else {
return (a * RAYint - halfB) / b;
}
}
/**
* @notice Calculates the power of a ray integer base to an unsigned integer exponent.
* @dev Uses `rayMulInt` and a for loop for the calculation.
* @param base Ray integer base number.
* @param exponent Power exponent (not in ray precision).
* @return result The result of `base**exponent`, in ray precision.
*/
function rayPowerInt(int256 base, uint256 exponent) internal pure returns (int256) {
if (exponent == 0) {
return RAYint;
}
int256 result = base;
for (uint256 i = 1; i < exponent; i++) {
result = rayMulInt(result, base);
}
return result;
}
}// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.8.23;
/**
* @title VersionedInitializable
* @author Conclave, inspired by the OpenZeppelin Initializable contract
* @notice Helper contract to implement initializer functions. To use it, replace
* the constructor with a function that has the `initializer` modifier.
* @dev WARNING: Unlike constructors, initializer functions must be manually
* invoked. This applies both to deploying an Initializable contract, as well
* as extending an Initializable contract via inheritance.
* WARNING: When used with inheritance, manual care must be taken to not invoke
* a parent initializer twice, or ensure that all initializers are idempotent,
* because this is not dealt with automatically as with constructors.
*/
abstract contract VersionedInitializable {
/**
* @dev Indicates that the contract has been initialized through the `lastInitializedRevision` variable.
*/
uint256 private lastInitializedRevision = 0;
/**
* @dev Indicates that the contract is in the process of being initialized through the `initializing` flag.
*/
bool private initializing;
/**
* @dev Modifier to use in the initializer function of a contract.
* @notice Ensures initialization can only happen once per revision.
*/
modifier initializer() {
uint256 revision = getRevision();
require(
initializing || isConstructor() || revision > lastInitializedRevision,
"Contract instance has already been initialized"
);
bool isTopLevelCall = !initializing;
if (isTopLevelCall) {
initializing = true;
lastInitializedRevision = revision;
}
_;
if (isTopLevelCall) {
initializing = false;
}
}
/**
* @notice Returns the revision number of the contract.
* @dev Needs to be defined in the inherited class as a constant.
* @return The revision number of the implementing contract.
*/
function getRevision() internal pure virtual returns (uint256);
/**
* @notice Returns true if and only if the function is running in the constructor.
* @dev Uses assembly to check if code size is zero, which is only true during construction.
* @return True if the function is running in the constructor.
*/
function isConstructor() private view returns (bool) {
// extcodesize checks the size of the code stored in an address, and
// address returns the current address. Since the code is still not
// deployed when running a constructor, any checks on its code size will
// yield zero, making it an effective way to detect if a contract is
// under construction or not.
uint256 cs;
assembly {
cs := extcodesize(address())
}
return cs == 0;
}
function _blockInitializing() internal {
if (isConstructor()) {
lastInitializedRevision = type(uint256).max;
}
}
/**
* @dev Reserved storage space to allow for layout changes in the future.
*/
uint256[50] private ______gap;
}// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.8.23;
import {IERC20} from "../../../../contracts/dependencies/openzeppelin/contracts/IERC20.sol";
import {IERC20Detailed} from
"../../../../contracts/dependencies/openzeppelin/contracts/IERC20Detailed.sol";
import {IRewarder} from "../../../../contracts/interfaces/IRewarder.sol";
/**
* @title IncentivizedERC20
* @notice Implementation of the basic ERC20 standard with incentives functionality.
* @author Conclave
* @dev This contract extends the basic ERC20 implementation with incentives tracking capabilities.
*/
abstract contract IncentivizedERC20 is IERC20, IERC20Detailed {
mapping(address => uint256) internal _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 internal _totalSupply;
string private _name;
string private _symbol;
uint8 private _decimals;
/**
* @dev Constructor that sets the token details.
* @param name_ The name of the token.
* @param symbol_ The symbol of the token.
* @param decimals_ The number of decimals for token precision.
*/
constructor(string memory name_, string memory symbol_, uint8 decimals_) {
_name = name_;
_symbol = symbol_;
_decimals = decimals_;
}
/**
* @dev Returns the name of the token.
* @return The name of the token as a string.
*/
function name() public view override returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token.
* @return The symbol of the token as a string.
*/
function symbol() public view override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used for token precision.
* @return The decimal places of the token.
*/
function decimals() public view override returns (uint8) {
return _decimals;
}
/**
* @dev Returns the total supply of the token.
* @return The total token supply.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev Returns the token balance of a given account.
* @param account The address to query the balance for.
* @return The token balance of the `account`.
*/
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
/**
* @dev Abstract function to get the incentives controller.
* @return The IRewarder interface of the incentives controller.
* @dev Implemented by child aToken/debtToken to maintain backward compatibility.
*/
function _getIncentivesController() internal view virtual returns (IRewarder);
/**
* @dev Transfers tokens from sender to recipient.
* @param recipient The address receiving the tokens.
* @param amount The amount of tokens to transfer.
* @return A boolean indicating the success of the transfer.
*/
function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(msg.sender, recipient, amount);
emit Transfer(msg.sender, recipient, amount);
return true;
}
/**
* @dev Returns the spending allowance of `spender` for `owner`'s tokens.
* @param owner The address owning the tokens.
* @param spender The address authorized to spend the tokens.
* @return The remaining allowance of tokens.
*/
function allowance(address owner, address spender)
public
view
virtual
override
returns (uint256)
{
return _allowances[owner][spender];
}
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
* @param spender The address authorized to spend the tokens.
* @param amount The amount of tokens to be approved for spending.
* @return A boolean indicating the success of the approval.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
_approve(msg.sender, spender, amount);
return true;
}
/**
* @dev Transfers tokens from one address to another using the allowance mechanism.
* @param sender The address to transfer tokens from.
* @param recipient The address to transfer tokens to.
* @param amount The amount of tokens to transfer.
* @return A boolean indicating the success of the transfer.
*/
function transferFrom(address sender, address recipient, uint256 amount)
public
virtual
override
returns (bool)
{
_transfer(sender, recipient, amount);
uint256 oldAllowance = _allowances[sender][msg.sender];
require(oldAllowance >= amount, "ERC20: transfer amount exceeds allowance");
_approve(sender, msg.sender, oldAllowance - amount);
emit Transfer(sender, recipient, amount);
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender`.
* @param spender The address being authorized to spend tokens.
* @param addedValue The amount by which to increase the allowance.
* @return A boolean indicating the success of the operation.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
_approve(msg.sender, spender, _allowances[msg.sender][spender] + addedValue);
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender`.
* @param spender The address being authorized to spend tokens.
* @param subtractedValue The amount by which to decrease the allowance.
* @return A boolean indicating the success of the operation.
*/
function decreaseAllowance(address spender, uint256 subtractedValue)
public
virtual
returns (bool)
{
uint256 oldAllowance = _allowances[msg.sender][spender];
require(oldAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
_approve(msg.sender, spender, oldAllowance - subtractedValue);
return true;
}
/**
* @dev Internal function to execute token transfers.
* @param sender The address sending the tokens.
* @param recipient The address receiving the tokens.
* @param amount The amount of tokens to transfer.
*/
function _transfer(address sender, address recipient, uint256 amount) internal virtual {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(sender, recipient, amount);
uint256 oldSenderBalance = _balances[sender];
require(oldSenderBalance >= amount, "ERC20: transfer amount exceeds balance");
_balances[sender] = oldSenderBalance - amount;
uint256 oldRecipientBalance = _balances[recipient];
_balances[recipient] = _balances[recipient] + amount;
if (address(_getIncentivesController()) != address(0)) {
uint256 currentTotalSupply = _totalSupply;
_getIncentivesController().handleAction(sender, currentTotalSupply, oldSenderBalance);
if (sender != recipient) {
_getIncentivesController().handleAction(
recipient, currentTotalSupply, oldRecipientBalance
);
}
}
}
/**
* @dev Internal function to mint new tokens.
* @param account The address receiving the minted tokens.
* @param amount The amount of tokens to mint.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
uint256 oldTotalSupply = _totalSupply;
_totalSupply = oldTotalSupply + amount;
uint256 oldAccountBalance = _balances[account];
_balances[account] = oldAccountBalance + amount;
if (address(_getIncentivesController()) != address(0)) {
_getIncentivesController().handleAction(account, oldTotalSupply, oldAccountBalance);
}
}
/**
* @dev Internal function to burn tokens.
* @param account The address from which tokens will be burned.
* @param amount The amount of tokens to burn.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 oldTotalSupply = _totalSupply;
_totalSupply = oldTotalSupply - amount;
uint256 oldAccountBalance = _balances[account];
require(oldAccountBalance >= amount, "ERC20: burn amount exceeds balance");
_balances[account] = oldAccountBalance - amount;
if (address(_getIncentivesController()) != address(0)) {
_getIncentivesController().handleAction(account, oldTotalSupply, oldAccountBalance);
}
}
/**
* @dev Internal function to handle token approvals.
* @param owner The address granting the approval.
* @param spender The address receiving the approval.
* @param amount The amount of tokens approved.
*/
function _approve(address owner, address spender, uint256 amount) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Internal function to update the token name.
* @param newName The new name to set.
*/
function _setName(string memory newName) internal {
_name = newName;
}
/**
* @dev Internal function to update the token symbol.
* @param newSymbol The new symbol to set.
*/
function _setSymbol(string memory newSymbol) internal {
_symbol = newSymbol;
}
/**
* @dev Internal function to update the token decimals.
* @param newDecimals The new number of decimals to set.
*/
function _setDecimals(uint8 newDecimals) internal {
_decimals = newDecimals;
}
/**
* @dev Hook that is called before any transfer of tokens.
* @param from The address tokens are transferred from.
* @param to The address tokens are transferred to.
* @param amount The amount of tokens being transferred.
*/
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}
}// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.8.0;
/**
* @title IRewarder interface.
* @author Conclave
*/
interface IRewarder {
/**
* @notice Emitted when rewards are accrued for a user
* @param user The address of the user for whom rewards are being accrued
* @param amount The amount of rewards accrued
*/
event RewardsAccrued(address indexed user, uint256 amount);
/**
* @notice Emitted when rewards are claimed by a user
* @param user The address of the user claiming rewards
* @param to The address receiving the claimed rewards
* @param amount The amount of rewards claimed
*/
event RewardsClaimed(address indexed user, address indexed to, uint256 amount);
/**
* @notice Emitted when rewards are claimed on behalf of a user
* @param user The address of the user for whom rewards are claimed
* @param to The address receiving the claimed rewards
* @param claimer The address that initiated the claim
* @param amount The amount of rewards claimed
*/
event RewardsClaimed(
address indexed user, address indexed to, address indexed claimer, uint256 amount
);
/**
* @notice Emitted when a claimer is set for a user
* @param user The address of the user
* @param claimer The address authorized to claim on behalf of the user
*/
event ClaimerSet(address indexed user, address indexed claimer);
function getAssetData(address asset) external view returns (uint256, uint256, uint256);
function assets(address asset) external view returns (uint128, uint128, uint256);
function setClaimer(address user, address claimer) external;
function getClaimer(address user) external view returns (address);
function configureAssets(address[] calldata assets, uint256[] calldata emissionsPerSecond)
external;
function handleAction(address asset, uint256 userBalance, uint256 totalSupply) external;
function getRewardsBalance(address[] calldata assets, address user)
external
view
returns (uint256);
function claimRewards(address[] calldata assets, uint256 amount, address to)
external
returns (uint256);
function claimRewardsOnBehalf(
address[] calldata assets,
uint256 amount,
address user,
address to
) external returns (uint256);
function getUserUnclaimedRewards(address user) external view returns (uint256);
function getUserAssetData(address user, address asset) external view returns (uint256);
function REWARD_TOKEN() external view returns (address);
function PRECISION() external view returns (uint8);
function DISTRIBUTION_END() external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2;
import "./IERC20.sol";
/// @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in
/// https://eips.ethereum.org/EIPS/eip-4626
interface IERC4626 is IERC20 {
event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
event Withdraw(
address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares
);
/// @notice Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
/// @dev
/// - MUST be an ERC-20 token contract.
/// - MUST NOT revert.
function asset() external view returns (address assetTokenAddress);
/// @notice Returns the total amount of the underlying asset that is “managed” by Vault.
/// @dev
/// - SHOULD include any compounding that occurs from yield.
/// - MUST be inclusive of any fees that are charged against assets in the Vault.
/// - MUST NOT revert.
function totalAssets() external view returns (uint256 totalManagedAssets);
/// @notice Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal
/// scenario where all the conditions are met.
/// @dev
/// - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
/// - MUST NOT show any variations depending on the caller.
/// - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
/// - MUST NOT revert.
///
/// NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
/// “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
/// from.
function convertToShares(uint256 assets) external view returns (uint256 shares);
/// @notice Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal
/// scenario where all the conditions are met.
/// @dev
/// - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
/// - MUST NOT show any variations depending on the caller.
/// - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
/// - MUST NOT revert.
///
/// NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
/// “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
/// from.
function convertToAssets(uint256 shares) external view returns (uint256 assets);
/// @notice Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
/// through a deposit call.
/// @dev
/// - MUST return a limited value if receiver is subject to some deposit limit.
/// - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
/// - MUST NOT revert.
function maxDeposit(address receiver) external view returns (uint256 maxAssets);
/// @notice Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
/// current on-chain conditions.
/// @dev
/// - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
/// call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
/// in the same transaction.
/// - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
/// deposit would be accepted, regardless if the user has enough tokens approved, etc.
/// - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
/// - MUST NOT revert.
///
/// NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
/// share price or some other type of condition, meaning the depositor will lose assets by depositing.
function previewDeposit(uint256 assets) external view returns (uint256 shares);
/// @notice Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.
/// @dev
/// - MUST emit the Deposit event.
/// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
/// deposit execution, and are accounted for during deposit.
/// - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not
/// approving enough underlying tokens to the Vault contract, etc).
///
/// NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
/// @notice Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
/// @dev
/// - MUST return a limited value if receiver is subject to some mint limit.
/// - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
/// - MUST NOT revert.
function maxMint(address receiver) external view returns (uint256 maxShares);
/// @notice Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
/// current on-chain conditions.
/// @dev
/// - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
/// in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the
/// same transaction.
/// - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
/// would be accepted, regardless if the user has enough tokens approved, etc.
/// - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
/// - MUST NOT revert.
///
/// NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
/// share price or some other type of condition, meaning the depositor will lose assets by minting.
function previewMint(uint256 shares) external view returns (uint256 assets);
/// @notice Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
/// @dev
/// - MUST emit the Deposit event.
/// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint
/// execution, and are accounted for during mint.
/// - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not
/// approving enough underlying tokens to the Vault contract, etc).
///
/// NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
function mint(uint256 shares, address receiver) external returns (uint256 assets);
/// @notice Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
/// Vault, through a withdrawal call.
/// @dev
/// - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
/// - MUST NOT revert.
function maxWithdraw(address owner) external view returns (uint256 maxAssets);
/// @notice Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
/// given current on-chain conditions.
/// @dev
/// - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw
/// call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if
/// called
/// in the same transaction.
/// - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though
/// the withdrawal would be accepted, regardless if the user has enough shares, etc.
/// - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
/// - MUST NOT revert.
///
/// NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
/// share price or some other type of condition, meaning the depositor will lose assets by depositing.
function previewWithdraw(uint256 assets) external view returns (uint256 shares);
/// @notice Burns shares from owner and sends exactly assets of underlying tokens to receiver.
/// @dev
/// - MUST emit the Withdraw event.
/// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
/// withdraw execution, and are accounted for during withdrawal.
/// - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
/// not having enough shares, etc).
///
/// Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
/// Those methods should be performed separately.
function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);
/// @notice Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,
/// through a redeem call.
/// @dev
/// - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
/// - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.
/// - MUST NOT revert.
function maxRedeem(address owner) external view returns (uint256 maxShares);
/// @notice Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,
/// given current on-chain conditions.
/// @dev
/// - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call
/// in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the
/// same transaction.
/// - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the
/// redemption would be accepted, regardless if the user has enough shares, etc.
/// - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
/// - MUST NOT revert.
///
/// NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in
/// share price or some other type of condition, meaning the depositor will lose assets by redeeming.
function previewRedeem(uint256 shares) external view returns (uint256 assets);
/// @notice Burns exactly shares from owner and sends assets of underlying tokens to receiver.
/// @dev
/// - MUST emit the Withdraw event.
/// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
/// redeem execution, and are accounted for during redeem.
/// - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner
/// not having enough shares, etc).
///
/// NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
/// Those methods should be performed separately.
function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
}// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.8.23;
/**
* @title DataTypes
* @author Conclave
* @notice Library containing data structures used across the protocol.
* @dev Contains core data structures for reserves, user configurations, and system parameters.
*/
library DataTypes {
/**
* @notice Stores all configuration and state for a lending pool reserve.
* @param configuration Reserve configuration parameters.
* @param liquidityIndex Current `liquidityIndex`, expressed in ray.
* @param variableBorrowIndex Current `variableBorrowIndex`, expressed in ray.
* @param currentLiquidityRate Current supply interest rate, expressed in ray.
* @param currentVariableBorrowRate Current variable borrow interest rate, expressed in ray.
* @param lastUpdateTimestamp Timestamp of the last reserve update.
* @param aTokenAddress Address of the `aToken` contract.
* @param variableDebtTokenAddress Address of the variable debt token.
* @param interestRateStrategyAddress Address of the interest rate strategy.
* @param id Identifier of the reserve in the list of active reserves.
*/
struct ReserveData {
ReserveConfigurationMap configuration;
uint128 liquidityIndex;
uint128 variableBorrowIndex;
uint128 currentLiquidityRate;
uint128 currentVariableBorrowRate;
uint40 lastUpdateTimestamp;
address aTokenAddress;
address variableDebtTokenAddress;
address interestRateStrategyAddress;
uint8 id;
}
/**
* @notice Stores all configuration and state for a minipool reserve.
* @param configuration Reserve configuration parameters.
* @param liquidityIndex Current `liquidityIndex`, expressed in ray.
* @param variableBorrowIndex Current `variableBorrowIndex`, expressed in ray.
* @param currentLiquidityRate Current supply interest rate, expressed in ray.
* @param currentVariableBorrowRate Current variable borrow interest rate, expressed in ray.
* @param lastUpdateTimestamp Timestamp of the last reserve update.
* @param aErc6909 Address of the ERC6909 token contract for `aTokens`.
* @param aTokenID ID of the ERC6909 `aToken`.
* @param variableDebtTokenID ID of the ERC6909 debt token.
* @param interestRateStrategyAddress Address of the interest rate strategy.
* @param id Identifier of the reserve in the list of active reserves.
*/
struct MiniPoolReserveData {
ReserveConfigurationMap configuration;
uint128 liquidityIndex;
uint128 variableBorrowIndex;
uint128 currentLiquidityRate;
uint128 currentVariableBorrowRate;
uint40 lastUpdateTimestamp;
address aErc6909;
uint256 aTokenID;
uint256 variableDebtTokenID;
address interestRateStrategyAddress;
uint8 id;
}
/**
* @notice Stores the configuration parameters for a reserve.
* @dev Encoded as a packed bitfield for gas optimization.
* - bits 0-15: `Loan to Value` ratio.
* - bits 16-31: `Liquidation threshold`.
* - bits 32-47: `Liquidation bonus`.
* - bits 48-55: Decimals of the underlying asset.
* - bit 56: Reserve is active.
* - bit 57: Reserve is frozen.
* - bit 58: Borrowing is enabled.
* - bit 59: Flashloan is enabled.
* - bits 60-75: `Astera` reserve factor.
* - bits 76-91: Minipool owner reserve factor.
* - bits 92-163: Deposit cap.
* - bit 164: Reserve type.
* - bits 165-255: Unused.
*/
struct ReserveConfigurationMap {
uint256 data;
}
/**
* @notice Stores reference information for a reserve.
* @param asset Address of the underlying asset.
* @param reserveType Boolean indicating if the reserve is vault-boosted.
*/
struct ReserveReference {
address asset;
bool reserveType;
}
/**
* @notice Stores the user's configuration for all reserves.
* @dev Encoded as a packed bitfield for gas optimization.
*/
struct UserConfigurationMap {
uint256 data;
}
/**
* @notice Defines the possible interest rate modes for flashloans.
* @param NONE The flashloan must not be paid back.
* @param VARIABLE If not paid back, try to open a variable rate loan.
*/
enum InterestRateMode {
NONE,
VARIABLE
}
}// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.8.0;
/**
* @title IScaledBalanceToken interface.
* @author Conclave
*/
interface IScaledBalanceToken {
function scaledBalanceOf(address user) external view returns (uint256);
function getScaledUserBalanceAndSupply(address user) external view returns (uint256, uint256);
function scaledTotalSupply() external view returns (uint256);
}// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.8.0;
import {ILendingPool} from "../../../contracts/interfaces/ILendingPool.sol";
import {IRewarder} from "../../../contracts/interfaces/IRewarder.sol";
/**
* @title IInitializableAToken interface.
* @author Conclave
*/
interface IInitializableAToken {
/**
* @dev Emitted when an aToken is initialized
* @param underlyingAsset The address of the underlying asset
* @param pool The address of the associated lending pool
* @param aTokenWrapper The address of the aToken wrapper
* @param treasury The address of the treasury
* @param rewarder The address of the incentives controller for this aToken
* @param aTokenDecimals the decimals of the underlying
* @param reserveType Whether the reserve is boosted by a vault
* @param aTokenName the name of the aToken
* @param aTokenSymbol the symbol of the aToken
* @param params A set of encoded parameters for additional initialization
*
*/
event Initialized(
address indexed underlyingAsset,
address indexed pool,
address aTokenWrapper,
address treasury,
address rewarder,
uint8 aTokenDecimals,
bool reserveType,
string aTokenName,
string aTokenSymbol,
bytes params
);
function initialize(
ILendingPool pool,
address treasury,
address underlyingAsset,
IRewarder rewarder,
uint8 aTokenDecimals,
bool reserveType,
string calldata aTokenName,
string calldata aTokenSymbol,
bytes calldata params
) external;
}// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
interface IERC20Detailed is IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2;
/// @dev Interface of the ERC20 standard as defined in the EIP.
/// @dev This includes the optional name, symbol, and decimals metadata.
interface IERC20 {
/// @dev Emitted when `value` tokens are moved from one account (`from`) to another (`to`).
event Transfer(address indexed from, address indexed to, uint256 value);
/// @dev Emitted when the allowance of a `spender` for an `owner` is set, where `value`
/// is the new allowance.
event Approval(address indexed owner, address indexed spender, uint256 value);
/// @notice Returns the amount of tokens in existence.
function totalSupply() external view returns (uint256);
/// @notice Returns the amount of tokens owned by `account`.
function balanceOf(address account) external view returns (uint256);
/// @notice Moves `amount` tokens from the caller's account to `to`.
function transfer(address to, uint256 amount) external returns (bool);
/// @notice Returns the remaining number of tokens that `spender` is allowed
/// to spend on behalf of `owner`
function allowance(address owner, address spender) external view returns (uint256);
/// @notice Sets `amount` as the allowance of `spender` over the caller's tokens.
/// @dev Be aware of front-running risks: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
function approve(address spender, uint256 amount) external returns (bool);
/// @notice Moves `amount` tokens from `from` to `to` using the allowance mechanism.
/// `amount` is then deducted from the caller's allowance.
function transferFrom(address from, address to, uint256 amount) external returns (bool);
/// @notice Returns the name of the token.
function name() external view returns (string memory);
/// @notice Returns the symbol of the token.
function symbol() external view returns (string memory);
/// @notice Returns the decimals places of the token.
function decimals() external view returns (uint8);
}{
"remappings": [
"ds-test/=lib/forge-std/lib/ds-test/src/",
"eth-gas-reporter/=node_modules/eth-gas-reporter/",
"forge-std/=lib/forge-std/src/",
"hardhat/=node_modules/hardhat/",
"pythnetwork/pyth-sdk-solidity/=node_modules/@pythnetwork/pyth-sdk-solidity/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"solady/=lib/solady/src/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"@pythnetwork/=node_modules/@pythnetwork/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/"
],
"optimizer": {
"enabled": true,
"runs": 500
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"viaIR": false,
"libraries": {
"contracts/protocol/core/lendingpool/logic/BorrowLogic.sol": {
"BorrowLogic": "0xed4E9A39760AA4d26A6fD3176Dae0a0107605a3B"
},
"contracts/protocol/core/lendingpool/logic/DepositLogic.sol": {
"DepositLogic": "0x063F37Ae33e1dA7113e7B066f7D952CC59121873"
},
"contracts/protocol/core/lendingpool/logic/FlashLoanLogic.sol": {
"FlashLoanLogic": "0x8E5938fC9d55D0db6663685378BCCDC2492EA1B3"
},
"contracts/protocol/core/lendingpool/logic/GenericLogic.sol": {
"GenericLogic": "0xE10600cf3845fc3Af9a34173D8F71eE3ed9CE26c"
},
"contracts/protocol/core/lendingpool/logic/LiquidationLogic.sol": {
"LiquidationLogic": "0xa0089F0Db9A73E56E1808E04C071Af0A78ca6050"
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address[]","name":"assets","type":"address[]"},{"internalType":"address[]","name":"sources","type":"address[]"},{"internalType":"uint256[]","name":"timeouts","type":"uint256[]"},{"internalType":"address","name":"fallbackOracle","type":"address"},{"internalType":"address","name":"baseCurrency","type":"address"},{"internalType":"uint256","name":"baseCurrencyUnit","type":"uint256"},{"internalType":"address","name":"lendingpoolAddressesProvider","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":true,"internalType":"address","name":"source","type":"address"},{"indexed":false,"internalType":"uint256","name":"timeout","type":"uint256"}],"name":"AssetSourceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"baseCurrency","type":"address"},{"indexed":false,"internalType":"uint256","name":"baseCurrencyUnit","type":"uint256"}],"name":"BaseCurrencySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"fallbackOracle","type":"address"}],"name":"FallbackOracleUpdated","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"},{"inputs":[],"name":"BASE_CURRENCY","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BASE_CURRENCY_UNIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CDX_USD","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"getAssetPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"getAssetTimeout","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"assets","type":"address[]"}],"name":"getAssetsPrices","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFallbackOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLendingpoolConfigurator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"getSourceOfAsset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"assets","type":"address[]"},{"internalType":"address[]","name":"sources","type":"address[]"},{"internalType":"uint256[]","name":"timeouts","type":"uint256[]"}],"name":"setAssetSources","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"fallbackOracle","type":"address"}],"name":"setFallbackOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60c06040523480156200001157600080fd5b5060405162001543380380620015438339810160408190526200003491620004b1565b33806200005c57604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b62000067816200016b565b506200007384620001bb565b6200008087878762000205565b6001600160a01b0383811660805260a0839052600580546001600160a01b0319169183169182179055604080516385c858b160e01b815290516385c858b1916004808201926020929091908290030181865afa158015620000e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200010b9190620005df565b600480546001600160a01b0319166001600160a01b03928316179055604051838152908416907fe27c4c1372396a3d15a9922f74f9dfc7c72b1ad6d63868470787249c356454c19060200160405180910390a2505050505050506200066b565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600380546001600160a01b0319166001600160a01b0383169081179091556040517fce7a780d33665b1ea097af5f155e3821b809ecbaa839d3b33aa83ba28168cefb90600090a250565b82518251604080518082019091526002815261373560f01b6020820152908214620002455760405162461bcd60e51b815260040162000053919062000604565b508151811460405180604001604052806002815260200161373560f01b81525090620002865760405162461bcd60e51b815260040162000053919062000604565b5060005b818110156200039e576000858281518110620002aa57620002aa62000655565b602002602001015190506000858381518110620002cb57620002cb62000655565b602002602001015190506000858481518110620002ec57620002ec62000655565b6020908102919091018101516001600160a01b0385811660009081526001909352604090922080546001600160a01b03191692851692909217909155905080156200033857806200033c565b6000195b6001600160a01b0384811660008181526002602090815260409182902094909455518481529185169290917f1a01b1e12dca4fda1b35d92f9e71f98ea7d139b356b02ecedf5e6120d5ed17ed910160405180910390a35050506001016200028a565b5050505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715620003e657620003e6620003a5565b604052919050565b60006001600160401b038211156200040a576200040a620003a5565b5060051b60200190565b80516001600160a01b03811681146200042c57600080fd5b919050565b600082601f8301126200044357600080fd5b815160206200045c6200045683620003ee565b620003bb565b8083825260208201915060208460051b8701019350868411156200047f57600080fd5b602086015b84811015620004a657620004988162000414565b835291830191830162000484565b509695505050505050565b600080600080600080600060e0888a031215620004cd57600080fd5b87516001600160401b0380821115620004e557600080fd5b620004f38b838c0162000431565b985060209150818a0151818111156200050b57600080fd5b620005198c828d0162000431565b98505060408a0151818111156200052f57600080fd5b8a019050601f81018b136200054357600080fd5b8051620005546200045682620003ee565b81815260059190911b8201830190838101908d8311156200057457600080fd5b928401925b82841015620005945783518252928401929084019062000579565b8099505050505050620005aa6060890162000414565b9350620005ba6080890162000414565b925060a08801519150620005d160c0890162000414565b905092959891949750929550565b600060208284031215620005f257600080fd5b620005fd8262000414565b9392505050565b60006020808352835180602085015260005b81811015620006345785810183015185820160400152820162000616565b506000604082860101526040601f19601f8301168501019250505092915050565b634e487b7160e01b600052603260045260246000fd5b60805160a051610ea46200069f600039600081816101b101526105ea01526000818161024801526105060152610ea46000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c80638c89b64f1161008c5780639d23d9f2116100665780639d23d9f214610210578063b3596f0714610230578063e19f470014610243578063f2fde38b1461026a57600080fd5b80638c89b64f146101ac5780638da5cb5b146101d357806392bf2be0146101e457600080fd5b80636210308c116100c85780636210308c14610149578063715018a61461015a578063731cd47c146101625780637ef28b2d1461019957600080fd5b80630741272c146100ef5780630d43014914610119578063170aee7314610134575b600080fd5b6004546001600160a01b03165b6040516001600160a01b0390911681526020015b60405180910390f35b6100fc73c0d3700000987c99b3c9009069e4f8413fd2233081565b610147610142366004610b7b565b61027d565b005b6003546001600160a01b03166100fc565b610147610291565b61018b610170366004610b7b565b6001600160a01b031660009081526002602052604090205490565b604051908152602001610110565b6101476101a7366004610beb565b6102a5565b61018b7f000000000000000000000000000000000000000000000000000000000000000081565b6000546001600160a01b03166100fc565b6100fc6101f2366004610b7b565b6001600160a01b039081166000908152600160205260409020541690565b61022361021e366004610c85565b610353565b6040516101109190610cc7565b61018b61023e366004610b7b565b610400565b6100fc7f000000000000000000000000000000000000000000000000000000000000000081565b610147610278366004610b7b565b6108c8565b610285610903565b61028e8161093f565b50565b610299610903565b6102a36000610989565b565b6102ad610903565b61034b86868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808a02828101820190935289825290935089925088918291850190849080828437600092019190915250506040805160208089028281018201909352888252909350889250879182918501908490808284376000920191909152506109d992505050565b505050505050565b606060008267ffffffffffffffff81111561037057610370610d0b565b604051908082528060200260200182016040528015610399578160200160208202803683370190505b50905060005b838110156103f6576103d18585838181106103bc576103bc610d21565b905060200201602081019061023e9190610b7b565b8282815181106103e3576103e3610d21565b602090810291909101015260010161039f565b5090505b92915050565b60048054604051631303c50d60e21b81526001600160a01b038481169382019390935260009283921690634c0f143490602401602060405180830381865afa158015610450573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104749190610d37565b156104e257826001600160a01b031663b16a19de6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104db9190610d59565b90506104e5565b50815b6001600160a01b0380821660008181526001602052604081205483169290917f000000000000000000000000000000000000000000000000000000000000000090911614806105e257506001600160a01b03851673c0d3700000987c99b3c9009069e4f8413fd223301480156105e25750600560009054906101000a90046001600160a01b03166001600160a01b0316630261bf8b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105cd9190610d59565b6001600160a01b0316336001600160a01b0316145b1561060e57507f0000000000000000000000000000000000000000000000000000000000000000610835565b6001600160a01b0382166106915760035460405163b3596f0760e01b81526001600160a01b0385811660048301529091169063b3596f0790602401602060405180830381865afa158015610666573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061068a9190610d76565b9050610835565b600080600080856001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156106d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106f99190610dae565b5093509350935093508369ffffffffffffffffffff166000148061071b575080155b8061072557504281115b80610731575060008313155b8061073a575081155b8061076557506001600160a01b0387166000908152600260205260409020546107638242610dfe565b115b1561082c576003546040805180820190915260028152611b9b60f11b6020820152906001600160a01b03166107b65760405162461bcd60e51b81526004016107ad9190610e1f565b60405180910390fd5b5060035460405163b3596f0760e01b81526001600160a01b0389811660048301529091169063b3596f0790602401602060405180830381865afa158015610801573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108259190610d76565b9450610830565b8294505b505050505b826001600160a01b0316856001600160a01b0316146108c0576040516303d1689d60e11b8152600481018290526001600160a01b038616906307a2d13a90602401602060405180830381865afa158015610893573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b79190610d76565b95945050505050565b949350505050565b6108d0610903565b6001600160a01b0381166108fa57604051631e4fbdf760e01b8152600060048201526024016107ad565b61028e81610989565b336109166000546001600160a01b031690565b6001600160a01b0316146102a35760405163118cdaa760e01b81523360048201526024016107ad565b600380546001600160a01b0319166001600160a01b0383169081179091556040517fce7a780d33665b1ea097af5f155e3821b809ecbaa839d3b33aa83ba28168cefb90600090a250565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b82518251604080518082019091526002815261373560f01b6020820152908214610a165760405162461bcd60e51b81526004016107ad9190610e1f565b508151811460405180604001604052806002815260200161373560f01b81525090610a545760405162461bcd60e51b81526004016107ad9190610e1f565b5060005b81811015610b5f576000858281518110610a7457610a74610d21565b602002602001015190506000858381518110610a9257610a92610d21565b602002602001015190506000858481518110610ab057610ab0610d21565b6020908102919091018101516001600160a01b0385811660009081526001909352604090922080546001600160a01b0319169285169290921790915590508015610afa5780610afe565b6000195b6001600160a01b0384811660008181526002602090815260409182902094909455518481529185169290917f1a01b1e12dca4fda1b35d92f9e71f98ea7d139b356b02ecedf5e6120d5ed17ed910160405180910390a3505050600101610a58565b5050505050565b6001600160a01b038116811461028e57600080fd5b600060208284031215610b8d57600080fd5b8135610b9881610b66565b9392505050565b60008083601f840112610bb157600080fd5b50813567ffffffffffffffff811115610bc957600080fd5b6020830191508360208260051b8501011115610be457600080fd5b9250929050565b60008060008060008060608789031215610c0457600080fd5b863567ffffffffffffffff80821115610c1c57600080fd5b610c288a838b01610b9f565b90985096506020890135915080821115610c4157600080fd5b610c4d8a838b01610b9f565b90965094506040890135915080821115610c6657600080fd5b50610c7389828a01610b9f565b979a9699509497509295939492505050565b60008060208385031215610c9857600080fd5b823567ffffffffffffffff811115610caf57600080fd5b610cbb85828601610b9f565b90969095509350505050565b6020808252825182820181905260009190848201906040850190845b81811015610cff57835183529284019291840191600101610ce3565b50909695505050505050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600060208284031215610d4957600080fd5b81518015158114610b9857600080fd5b600060208284031215610d6b57600080fd5b8151610b9881610b66565b600060208284031215610d8857600080fd5b5051919050565b805169ffffffffffffffffffff81168114610da957600080fd5b919050565b600080600080600060a08688031215610dc657600080fd5b610dcf86610d8f565b9450602086015193506040860151925060608601519150610df260808701610d8f565b90509295509295909350565b818103818111156103fa57634e487b7160e01b600052601160045260246000fd5b60006020808352835180602085015260005b81811015610e4d57858101830151858201604001528201610e31565b506000604082860101526040601f19601f830116850101925050509291505056fea26469706673582212204ed58285f874b61e1fffac4917a35b3327dab356ce287689e3e3f704579b5b1964736f6c6343000817003300000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000ae42509853e8aaf5c3cc9812fc60c915a237343d00000000000000000000000000000000000000000000000000000000000000040000000000000000000000003aab2285ddcddad8edf438c1bab47e1a9d05a9b4000000000000000000000000e5d7c2a44ffddf6b295a15c148167daaaf5cf34f000000000000000000000000176211869ca2b568f2a7d4ee941e073a821ee1ff000000000000000000000000a219439258ca9da29e9cc4ce5596924745e12b9300000000000000000000000000000000000000000000000000000000000000040000000000000000000000007a99092816c8bd5ec8ba229e3a6e6da1e628e1f90000000000000000000000003c6cd9cc7c7a4c2cf5a82734cd249d7d593354da000000000000000000000000aadaa473c1bdf7317ec07c915680af29debfdcb5000000000000000000000000efca2bbe0edd0e22b2e0d2f8248e99f4bef4a7db00000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000015180000000000000000000000000000000000000000000000000000000000001518000000000000000000000000000000000000000000000000000000000000151800000000000000000000000000000000000000000000000000000000000015180
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100ea5760003560e01c80638c89b64f1161008c5780639d23d9f2116100665780639d23d9f214610210578063b3596f0714610230578063e19f470014610243578063f2fde38b1461026a57600080fd5b80638c89b64f146101ac5780638da5cb5b146101d357806392bf2be0146101e457600080fd5b80636210308c116100c85780636210308c14610149578063715018a61461015a578063731cd47c146101625780637ef28b2d1461019957600080fd5b80630741272c146100ef5780630d43014914610119578063170aee7314610134575b600080fd5b6004546001600160a01b03165b6040516001600160a01b0390911681526020015b60405180910390f35b6100fc73c0d3700000987c99b3c9009069e4f8413fd2233081565b610147610142366004610b7b565b61027d565b005b6003546001600160a01b03166100fc565b610147610291565b61018b610170366004610b7b565b6001600160a01b031660009081526002602052604090205490565b604051908152602001610110565b6101476101a7366004610beb565b6102a5565b61018b7f0000000000000000000000000000000000000000000000000000000005f5e10081565b6000546001600160a01b03166100fc565b6100fc6101f2366004610b7b565b6001600160a01b039081166000908152600160205260409020541690565b61022361021e366004610c85565b610353565b6040516101109190610cc7565b61018b61023e366004610b7b565b610400565b6100fc7f000000000000000000000000000000000000000000000000000000000000000081565b610147610278366004610b7b565b6108c8565b610285610903565b61028e8161093f565b50565b610299610903565b6102a36000610989565b565b6102ad610903565b61034b86868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808a02828101820190935289825290935089925088918291850190849080828437600092019190915250506040805160208089028281018201909352888252909350889250879182918501908490808284376000920191909152506109d992505050565b505050505050565b606060008267ffffffffffffffff81111561037057610370610d0b565b604051908082528060200260200182016040528015610399578160200160208202803683370190505b50905060005b838110156103f6576103d18585838181106103bc576103bc610d21565b905060200201602081019061023e9190610b7b565b8282815181106103e3576103e3610d21565b602090810291909101015260010161039f565b5090505b92915050565b60048054604051631303c50d60e21b81526001600160a01b038481169382019390935260009283921690634c0f143490602401602060405180830381865afa158015610450573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104749190610d37565b156104e257826001600160a01b031663b16a19de6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104db9190610d59565b90506104e5565b50815b6001600160a01b0380821660008181526001602052604081205483169290917f000000000000000000000000000000000000000000000000000000000000000090911614806105e257506001600160a01b03851673c0d3700000987c99b3c9009069e4f8413fd223301480156105e25750600560009054906101000a90046001600160a01b03166001600160a01b0316630261bf8b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105cd9190610d59565b6001600160a01b0316336001600160a01b0316145b1561060e57507f0000000000000000000000000000000000000000000000000000000005f5e100610835565b6001600160a01b0382166106915760035460405163b3596f0760e01b81526001600160a01b0385811660048301529091169063b3596f0790602401602060405180830381865afa158015610666573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061068a9190610d76565b9050610835565b600080600080856001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156106d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106f99190610dae565b5093509350935093508369ffffffffffffffffffff166000148061071b575080155b8061072557504281115b80610731575060008313155b8061073a575081155b8061076557506001600160a01b0387166000908152600260205260409020546107638242610dfe565b115b1561082c576003546040805180820190915260028152611b9b60f11b6020820152906001600160a01b03166107b65760405162461bcd60e51b81526004016107ad9190610e1f565b60405180910390fd5b5060035460405163b3596f0760e01b81526001600160a01b0389811660048301529091169063b3596f0790602401602060405180830381865afa158015610801573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108259190610d76565b9450610830565b8294505b505050505b826001600160a01b0316856001600160a01b0316146108c0576040516303d1689d60e11b8152600481018290526001600160a01b038616906307a2d13a90602401602060405180830381865afa158015610893573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b79190610d76565b95945050505050565b949350505050565b6108d0610903565b6001600160a01b0381166108fa57604051631e4fbdf760e01b8152600060048201526024016107ad565b61028e81610989565b336109166000546001600160a01b031690565b6001600160a01b0316146102a35760405163118cdaa760e01b81523360048201526024016107ad565b600380546001600160a01b0319166001600160a01b0383169081179091556040517fce7a780d33665b1ea097af5f155e3821b809ecbaa839d3b33aa83ba28168cefb90600090a250565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b82518251604080518082019091526002815261373560f01b6020820152908214610a165760405162461bcd60e51b81526004016107ad9190610e1f565b508151811460405180604001604052806002815260200161373560f01b81525090610a545760405162461bcd60e51b81526004016107ad9190610e1f565b5060005b81811015610b5f576000858281518110610a7457610a74610d21565b602002602001015190506000858381518110610a9257610a92610d21565b602002602001015190506000858481518110610ab057610ab0610d21565b6020908102919091018101516001600160a01b0385811660009081526001909352604090922080546001600160a01b0319169285169290921790915590508015610afa5780610afe565b6000195b6001600160a01b0384811660008181526002602090815260409182902094909455518481529185169290917f1a01b1e12dca4fda1b35d92f9e71f98ea7d139b356b02ecedf5e6120d5ed17ed910160405180910390a3505050600101610a58565b5050505050565b6001600160a01b038116811461028e57600080fd5b600060208284031215610b8d57600080fd5b8135610b9881610b66565b9392505050565b60008083601f840112610bb157600080fd5b50813567ffffffffffffffff811115610bc957600080fd5b6020830191508360208260051b8501011115610be457600080fd5b9250929050565b60008060008060008060608789031215610c0457600080fd5b863567ffffffffffffffff80821115610c1c57600080fd5b610c288a838b01610b9f565b90985096506020890135915080821115610c4157600080fd5b610c4d8a838b01610b9f565b90965094506040890135915080821115610c6657600080fd5b50610c7389828a01610b9f565b979a9699509497509295939492505050565b60008060208385031215610c9857600080fd5b823567ffffffffffffffff811115610caf57600080fd5b610cbb85828601610b9f565b90969095509350505050565b6020808252825182820181905260009190848201906040850190845b81811015610cff57835183529284019291840191600101610ce3565b50909695505050505050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600060208284031215610d4957600080fd5b81518015158114610b9857600080fd5b600060208284031215610d6b57600080fd5b8151610b9881610b66565b600060208284031215610d8857600080fd5b5051919050565b805169ffffffffffffffffffff81168114610da957600080fd5b919050565b600080600080600060a08688031215610dc657600080fd5b610dcf86610d8f565b9450602086015193506040860151925060608601519150610df260808701610d8f565b90509295509295909350565b818103818111156103fa57634e487b7160e01b600052601160045260246000fd5b60006020808352835180602085015260005b81811015610e4d57858101830151858201604001528201610e31565b506000604082860101526040601f19601f830116850101925050509291505056fea26469706673582212204ed58285f874b61e1fffac4917a35b3327dab356ce287689e3e3f704579b5b1964736f6c63430008170033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000ae42509853e8aaf5c3cc9812fc60c915a237343d00000000000000000000000000000000000000000000000000000000000000040000000000000000000000003aab2285ddcddad8edf438c1bab47e1a9d05a9b4000000000000000000000000e5d7c2a44ffddf6b295a15c148167daaaf5cf34f000000000000000000000000176211869ca2b568f2a7d4ee941e073a821ee1ff000000000000000000000000a219439258ca9da29e9cc4ce5596924745e12b9300000000000000000000000000000000000000000000000000000000000000040000000000000000000000007a99092816c8bd5ec8ba229e3a6e6da1e628e1f90000000000000000000000003c6cd9cc7c7a4c2cf5a82734cd249d7d593354da000000000000000000000000aadaa473c1bdf7317ec07c915680af29debfdcb5000000000000000000000000efca2bbe0edd0e22b2e0d2f8248e99f4bef4a7db00000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000015180000000000000000000000000000000000000000000000000000000000001518000000000000000000000000000000000000000000000000000000000000151800000000000000000000000000000000000000000000000000000000000015180
-----Decoded View---------------
Arg [0] : assets (address[]): 0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0xA219439258ca9da29E9Cc4cE5596924745e12B93
Arg [1] : sources (address[]): 0x7A99092816C8BD5ec8ba229e3a6E6Da1E628E1F9,0x3c6Cd9Cc7c7a4c2Cf5a82734CD249D7D593354dA,0xAADAa473C1bDF7317ec07c915680Af29DeBfdCb5,0xefCA2bbe0EdD0E22b2e0d2F8248E99F4bEf4A7dB
Arg [2] : timeouts (uint256[]): 86400,86400,86400,86400
Arg [3] : fallbackOracle (address): 0x0000000000000000000000000000000000000000
Arg [4] : baseCurrency (address): 0x0000000000000000000000000000000000000000
Arg [5] : baseCurrencyUnit (uint256): 100000000
Arg [6] : lendingpoolAddressesProvider (address): 0xaE42509853e8aaF5C3cc9812FC60c915a237343D
-----Encoded View---------------
22 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000180
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000220
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [5] : 0000000000000000000000000000000000000000000000000000000005f5e100
Arg [6] : 000000000000000000000000ae42509853e8aaf5c3cc9812fc60c915a237343d
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000004
Arg [8] : 0000000000000000000000003aab2285ddcddad8edf438c1bab47e1a9d05a9b4
Arg [9] : 000000000000000000000000e5d7c2a44ffddf6b295a15c148167daaaf5cf34f
Arg [10] : 000000000000000000000000176211869ca2b568f2a7d4ee941e073a821ee1ff
Arg [11] : 000000000000000000000000a219439258ca9da29e9cc4ce5596924745e12b93
Arg [12] : 0000000000000000000000000000000000000000000000000000000000000004
Arg [13] : 0000000000000000000000007a99092816c8bd5ec8ba229e3a6e6da1e628e1f9
Arg [14] : 0000000000000000000000003c6cd9cc7c7a4c2cf5a82734cd249d7d593354da
Arg [15] : 000000000000000000000000aadaa473c1bdf7317ec07c915680af29debfdcb5
Arg [16] : 000000000000000000000000efca2bbe0edd0e22b2e0d2f8248e99f4bef4a7db
Arg [17] : 0000000000000000000000000000000000000000000000000000000000000004
Arg [18] : 0000000000000000000000000000000000000000000000000000000000015180
Arg [19] : 0000000000000000000000000000000000000000000000000000000000015180
Arg [20] : 0000000000000000000000000000000000000000000000000000000000015180
Arg [21] : 0000000000000000000000000000000000000000000000000000000000015180
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.