ETH Price: $2,908.30 (-0.58%)

Contract

0xaB0F37a98E35C65Eeed5cCeE43B465Bb6EA798f4

Overview

ETH Balance

Linea Mainnet LogoLinea Mainnet LogoLinea Mainnet Logo0 ETH

ETH Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To

There are no matching entries

> 10 Internal Transactions found.

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
215903102025-08-03 12:04:12175 days ago1754222652
0xaB0F37a9...b6EA798f4
0 ETH
215903102025-08-03 12:04:12175 days ago1754222652
0xaB0F37a9...b6EA798f4
0 ETH
215903102025-08-03 12:04:12175 days ago1754222652
0xaB0F37a9...b6EA798f4
0 ETH
215903102025-08-03 12:04:12175 days ago1754222652
0xaB0F37a9...b6EA798f4
0 ETH
215903102025-08-03 12:04:12175 days ago1754222652
0xaB0F37a9...b6EA798f4
0 ETH
215903102025-08-03 12:04:12175 days ago1754222652
0xaB0F37a9...b6EA798f4
0 ETH
215903102025-08-03 12:04:12175 days ago1754222652
0xaB0F37a9...b6EA798f4
0 ETH
215903102025-08-03 12:04:12175 days ago1754222652
0xaB0F37a9...b6EA798f4
0 ETH
215903102025-08-03 12:04:12175 days ago1754222652
0xaB0F37a9...b6EA798f4
0 ETH
215903102025-08-03 12:04:12175 days ago1754222652
0xaB0F37a9...b6EA798f4
0 ETH
215903102025-08-03 12:04:12175 days ago1754222652
0xaB0F37a9...b6EA798f4
0 ETH
215903102025-08-03 12:04:12175 days ago1754222652
0xaB0F37a9...b6EA798f4
0 ETH
215903102025-08-03 12:04:12175 days ago1754222652
0xaB0F37a9...b6EA798f4
0 ETH
215903102025-08-03 12:04:12175 days ago1754222652
0xaB0F37a9...b6EA798f4
0 ETH
215903102025-08-03 12:04:12175 days ago1754222652
0xaB0F37a9...b6EA798f4
0 ETH
212813862025-07-25 16:35:43184 days ago1753461343
0xaB0F37a9...b6EA798f4
0 ETH
212813862025-07-25 16:35:43184 days ago1753461343
0xaB0F37a9...b6EA798f4
0 ETH
212813862025-07-25 16:35:43184 days ago1753461343
0xaB0F37a9...b6EA798f4
0 ETH
212813862025-07-25 16:35:43184 days ago1753461343
0xaB0F37a9...b6EA798f4
0 ETH
212813862025-07-25 16:35:43184 days ago1753461343
0xaB0F37a9...b6EA798f4
0 ETH
212813862025-07-25 16:35:43184 days ago1753461343
0xaB0F37a9...b6EA798f4
0 ETH
212813862025-07-25 16:35:43184 days ago1753461343
0xaB0F37a9...b6EA798f4
0 ETH
212813862025-07-25 16:35:43184 days ago1753461343
0xaB0F37a9...b6EA798f4
0 ETH
212813862025-07-25 16:35:43184 days ago1753461343
0xaB0F37a9...b6EA798f4
0 ETH
212813862025-07-25 16:35:43184 days ago1753461343
0xaB0F37a9...b6EA798f4
0 ETH
View All Internal Transactions
Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Oracle

Compiler Version
v0.8.23+commit.f704f362

Optimization Enabled:
Yes with 500 runs

Other Settings:
paris EvmVersion
// 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);
    }
}

File 8 of 25 : Errors.sol
// 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();
        }
    }
}

File 13 of 25 : AToken.sol
// 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);
    }
}

File 14 of 25 : ILendingPool.sol
// 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);
}

File 21 of 25 : DataTypes.sol
// 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);
}

File 23 of 25 : IInitializableAToken.sol
// 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);
}

Settings
{
  "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

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"}]

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


Block Transaction Gas Used Reward
view all blocks sequenced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ 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.