ETH Price: $2,528.62 (+0.24%)

Transaction Decoder

Block:
20248559 at Jul-06-2024 04:07:35 PM +UTC
Transaction Fee:
0.000181596532223469 ETH $0.46
Gas Used:
51,531 Gas / 3.524024999 Gwei

Emitted Events:

217 InitializableImmutableAdminUpgradeabilityProxy.0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925( 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925, 0x000000000000000000000000eccb9b9c6fb7590a4d0588953b3170a1a84e3341, 0x000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3, ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff )

Account State Difference:

  Address   Before After State Difference Code
2.316550425937900071 Eth2.316553002487900071 Eth0.00000257655
0x473693Ec...901FB50E8
0xECCb9B9C...1a84E3341
0.420476918463059662 Eth
Nonce: 765
0.420295321930836193 Eth
Nonce: 766
0.000181596532223469

Execution Trace

InitializableImmutableAdminUpgradeabilityProxy.095ea7b3( )
  • AToken.approve( spender=0x000000000022D473030F116dDEE9F6B43aC78BA3, amount=115792089237316195423570985008687907853269984665640564039457584007913129639935 ) => ( True )
    File 1 of 2: InitializableImmutableAdminUpgradeabilityProxy
    // SPDX-License-Identifier: AGPL-3.0 AND MIT AND agpl-3.0
    
    // File @openzeppelin/contracts/utils/[email protected]
    
    // Original license: SPDX_License_Identifier: MIT
    // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
    
    pragma solidity ^0.8.1;
    
    /**
     * @dev Collection of functions related to the address type
     */
    library Address {
    	/**
    	 * @dev Returns true if `account` is a contract.
    	 *
    	 * [IMPORTANT]
    	 * ====
    	 * It is unsafe to assume that an address for which this function returns
    	 * false is an externally-owned account (EOA) and not a contract.
    	 *
    	 * Among others, `isContract` will return false for the following
    	 * types of addresses:
    	 *
    	 *  - an externally-owned account
    	 *  - a contract in construction
    	 *  - an address where a contract will be created
    	 *  - an address where a contract lived, but was destroyed
    	 *
    	 * Furthermore, `isContract` will also return true if the target contract within
    	 * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
    	 * which only has an effect at the end of a transaction.
    	 * ====
    	 *
    	 * [IMPORTANT]
    	 * ====
    	 * You shouldn't rely on `isContract` to protect against flash loan attacks!
    	 *
    	 * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
    	 * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
    	 * constructor.
    	 * ====
    	 */
    	function isContract(address account) internal view returns (bool) {
    		// This method relies on extcodesize/address.code.length, which returns 0
    		// for contracts in construction, since the code is only stored at the end
    		// of the constructor execution.
    
    		return account.code.length > 0;
    	}
    
    	/**
    	 * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
    	 * `recipient`, forwarding all available gas and reverting on errors.
    	 *
    	 * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
    	 * of certain opcodes, possibly making contracts go over the 2300 gas limit
    	 * imposed by `transfer`, making them unable to receive funds via
    	 * `transfer`. {sendValue} removes this limitation.
    	 *
    	 * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
    	 *
    	 * IMPORTANT: because control is transferred to `recipient`, care must be
    	 * taken to not create reentrancy vulnerabilities. Consider using
    	 * {ReentrancyGuard} or the
    	 * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
    	 */
    	function sendValue(address payable recipient, uint256 amount) internal {
    		require(address(this).balance >= amount, "Address: insufficient balance");
    
    		(bool success, ) = recipient.call{value: amount}("");
    		require(success, "Address: unable to send value, recipient may have reverted");
    	}
    
    	/**
    	 * @dev Performs a Solidity function call using a low level `call`. A
    	 * plain `call` is an unsafe replacement for a function call: use this
    	 * function instead.
    	 *
    	 * If `target` reverts with a revert reason, it is bubbled up by this
    	 * function (like regular Solidity function calls).
    	 *
    	 * Returns the raw returned data. To convert to the expected return value,
    	 * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
    	 *
    	 * Requirements:
    	 *
    	 * - `target` must be a contract.
    	 * - calling `target` with `data` must not revert.
    	 *
    	 * _Available since v3.1._
    	 */
    	function functionCall(address target, bytes memory data) internal returns (bytes memory) {
    		return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    	}
    
    	/**
    	 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
    	 * `errorMessage` as a fallback revert reason when `target` reverts.
    	 *
    	 * _Available since v3.1._
    	 */
    	function functionCall(
    		address target,
    		bytes memory data,
    		string memory errorMessage
    	) internal returns (bytes memory) {
    		return functionCallWithValue(target, data, 0, errorMessage);
    	}
    
    	/**
    	 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
    	 * but also transferring `value` wei to `target`.
    	 *
    	 * Requirements:
    	 *
    	 * - the calling contract must have an ETH balance of at least `value`.
    	 * - the called Solidity function must be `payable`.
    	 *
    	 * _Available since v3.1._
    	 */
    	function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
    		return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    	}
    
    	/**
    	 * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
    	 * with `errorMessage` as a fallback revert reason when `target` reverts.
    	 *
    	 * _Available since v3.1._
    	 */
    	function functionCallWithValue(
    		address target,
    		bytes memory data,
    		uint256 value,
    		string memory errorMessage
    	) internal returns (bytes memory) {
    		require(address(this).balance >= value, "Address: insufficient balance for call");
    		(bool success, bytes memory returndata) = target.call{value: value}(data);
    		return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    	}
    
    	/**
    	 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
    	 * but performing a static call.
    	 *
    	 * _Available since v3.3._
    	 */
    	function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
    		return functionStaticCall(target, data, "Address: low-level static call failed");
    	}
    
    	/**
    	 * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
    	 * but performing a static call.
    	 *
    	 * _Available since v3.3._
    	 */
    	function functionStaticCall(
    		address target,
    		bytes memory data,
    		string memory errorMessage
    	) internal view returns (bytes memory) {
    		(bool success, bytes memory returndata) = target.staticcall(data);
    		return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    	}
    
    	/**
    	 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
    	 * but performing a delegate call.
    	 *
    	 * _Available since v3.4._
    	 */
    	function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
    		return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    	}
    
    	/**
    	 * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
    	 * but performing a delegate call.
    	 *
    	 * _Available since v3.4._
    	 */
    	function functionDelegateCall(
    		address target,
    		bytes memory data,
    		string memory errorMessage
    	) internal returns (bytes memory) {
    		(bool success, bytes memory returndata) = target.delegatecall(data);
    		return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    	}
    
    	/**
    	 * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
    	 * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
    	 *
    	 * _Available since v4.8._
    	 */
    	function verifyCallResultFromTarget(
    		address target,
    		bool success,
    		bytes memory returndata,
    		string memory errorMessage
    	) internal view returns (bytes memory) {
    		if (success) {
    			if (returndata.length == 0) {
    				// only check isContract if the call was successful and the return data is empty
    				// otherwise we already know that it was a contract
    				require(isContract(target), "Address: call to non-contract");
    			}
    			return returndata;
    		} else {
    			_revert(returndata, errorMessage);
    		}
    	}
    
    	/**
    	 * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
    	 * revert reason or using the provided one.
    	 *
    	 * _Available since v4.3._
    	 */
    	function verifyCallResult(
    		bool success,
    		bytes memory returndata,
    		string memory errorMessage
    	) internal pure returns (bytes memory) {
    		if (success) {
    			return returndata;
    		} else {
    			_revert(returndata, errorMessage);
    		}
    	}
    
    	function _revert(bytes memory returndata, string memory errorMessage) private pure {
    		// Look for revert reason and bubble it up if present
    		if (returndata.length > 0) {
    			// The easiest way to bubble the revert reason is using memory via assembly
    			/// @solidity memory-safe-assembly
    			assembly {
    				let returndata_size := mload(returndata)
    				revert(add(32, returndata), returndata_size)
    			}
    		} else {
    			revert(errorMessage);
    		}
    	}
    }
    
    // File contracts/dependencies/openzeppelin/upgradeability/Proxy.sol
    
    // Original license: SPDX_License_Identifier: agpl-3.0
    pragma solidity 0.8.12;
    
    /**
     * @title Proxy
     * @dev Implements delegation of calls to other contracts, with proper
     * forwarding of return values and bubbling of failures.
     * It defines a fallback function that delegates all calls to the address
     * returned by the abstract _implementation() internal function.
     */
    abstract contract Proxy {
    	/**
    	 * @dev Fallback function.
    	 * Implemented entirely in `_fallback`.
    	 */
    	fallback() external payable {
    		_fallback();
    	}
    
    	/**
    	 * @return The Address of the implementation.
    	 */
    	function _implementation() internal view virtual returns (address);
    
    	/**
    	 * @dev Delegates execution to an implementation contract.
    	 * This is a low level function that doesn't return to its internal call site.
    	 * It will return to the external caller whatever the implementation returns.
    	 * @param implementation Address to delegate.
    	 */
    	function _delegate(address implementation) internal {
    		//solium-disable-next-line
    		assembly {
    			// Copy msg.data. We take full control of memory in this inline assembly
    			// block because it will not return to Solidity code. We overwrite the
    			// Solidity scratch pad at memory position 0.
    			calldatacopy(0, 0, calldatasize())
    
    			// Call the implementation.
    			// out and outsize are 0 because we don't know the size yet.
    			let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
    
    			// Copy the returned data.
    			returndatacopy(0, 0, returndatasize())
    
    			switch result
    			// delegatecall returns 0 on error.
    			case 0 {
    				revert(0, returndatasize())
    			}
    			default {
    				return(0, returndatasize())
    			}
    		}
    	}
    
    	/**
    	 * @dev Function that is run as the first thing in the fallback function.
    	 * Can be redefined in derived contracts to add functionality.
    	 * Redefinitions must call super._willFallback().
    	 */
    	function _willFallback() internal virtual {}
    
    	/**
    	 * @dev fallback implementation.
    	 * Extracted to enable manual triggering.
    	 */
    	function _fallback() internal {
    		_willFallback();
    		_delegate(_implementation());
    	}
    }
    
    // File contracts/dependencies/openzeppelin/upgradeability/BaseUpgradeabilityProxy.sol
    
    // Original license: SPDX_License_Identifier: agpl-3.0
    pragma solidity 0.8.12;
    
    /**
     * @title BaseUpgradeabilityProxy
     * @dev This contract implements a proxy that allows to change the
     * implementation address to which it will delegate.
     * Such a change is called an implementation upgrade.
     */
    contract BaseUpgradeabilityProxy is Proxy {
    	/**
    	 * @dev Emitted when the implementation is upgraded.
    	 * @param implementation Address of the new implementation.
    	 */
    	event Upgraded(address indexed implementation);
    
    	/**
    	 * @dev Storage slot with the address of the current implementation.
    	 * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
    	 * validated in the constructor.
    	 */
    	bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
    
    	/**
    	 * @dev Returns the current implementation.
    	 * @return impl Address of the current implementation
    	 */
    	function _implementation() internal view override returns (address impl) {
    		bytes32 slot = IMPLEMENTATION_SLOT;
    		//solium-disable-next-line
    		assembly {
    			impl := sload(slot)
    		}
    	}
    
    	/**
    	 * @dev Upgrades the proxy to a new implementation.
    	 * @param newImplementation Address of the new implementation.
    	 */
    	function _upgradeTo(address newImplementation) internal {
    		_setImplementation(newImplementation);
    		emit Upgraded(newImplementation);
    	}
    
    	/**
    	 * @dev Sets the implementation address of the proxy.
    	 * @param newImplementation Address of the new implementation.
    	 */
    	function _setImplementation(address newImplementation) internal {
    		require(Address.isContract(newImplementation), "Cannot set a proxy implementation to a non-contract address");
    
    		bytes32 slot = IMPLEMENTATION_SLOT;
    
    		//solium-disable-next-line
    		assembly {
    			sstore(slot, newImplementation)
    		}
    	}
    }
    
    // File contracts/dependencies/openzeppelin/upgradeability/InitializableUpgradeabilityProxy.sol
    
    // Original license: SPDX_License_Identifier: agpl-3.0
    pragma solidity 0.8.12;
    
    /**
     * @title InitializableUpgradeabilityProxy
     * @dev Extends BaseUpgradeabilityProxy with an initializer for initializing
     * implementation and init data.
     */
    contract InitializableUpgradeabilityProxy is BaseUpgradeabilityProxy {
    	/**
    	 * @dev Contract initializer.
    	 * @param _logic Address of the initial implementation.
    	 * @param _data Data to send as msg.data to the implementation to initialize the proxied contract.
    	 * It should include the signature and the parameters of the function to be called, as described in
    	 * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
    	 * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.
    	 */
    	function initialize(address _logic, bytes memory _data) public payable {
    		require(_implementation() == address(0));
    		assert(IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1));
    		_setImplementation(_logic);
    		if (_data.length > 0) {
    			(bool success, ) = _logic.delegatecall(_data);
    			require(success);
    		}
    	}
    }
    
    // File contracts/lending/libraries/aave-upgradeability/BaseImmutableAdminUpgradeabilityProxy.sol
    
    // Original license: SPDX_License_Identifier: AGPL-3.0
    pragma solidity 0.8.12;
    
    /**
     * @title BaseImmutableAdminUpgradeabilityProxy
     * @author Aave, inspired by the OpenZeppelin upgradeability proxy pattern
     * @dev This contract combines an upgradeability proxy with an authorization
     * mechanism for administrative tasks. The admin role is stored in an immutable, which
     * helps saving transactions costs
     * All external functions in this contract must be guarded by the
     * `ifAdmin` modifier. See ethereum/solidity#3864 for a Solidity
     * feature proposal that would enable this to be done automatically.
     */
    contract BaseImmutableAdminUpgradeabilityProxy is BaseUpgradeabilityProxy {
    	address immutable ADMIN;
    
    	constructor(address _admin) {
    		ADMIN = _admin;
    	}
    
    	modifier ifAdmin() {
    		if (msg.sender == ADMIN) {
    			_;
    		} else {
    			_fallback();
    		}
    	}
    
    	/**
    	 * @return _address The address of the proxy admin.
    	 */
    	function admin() external ifAdmin returns (address _address) {
    		return ADMIN;
    	}
    
    	/**
    	 * @return _address The address of the implementation.
    	 */
    	function implementation() external ifAdmin returns (address _address) {
    		return _implementation();
    	}
    
    	/**
    	 * @dev Upgrade the backing implementation of the proxy.
    	 * Only the admin can call this function.
    	 * @param newImplementation Address of the new implementation.
    	 */
    	function upgradeTo(address newImplementation) external ifAdmin {
    		_upgradeTo(newImplementation);
    	}
    
    	/**
    	 * @dev Upgrade the backing implementation of the proxy and call a function
    	 * on the new implementation.
    	 * This is useful to initialize the proxied contract.
    	 * @param newImplementation Address of the new implementation.
    	 * @param data Data to send as msg.data in the low level call.
    	 * It should include the signature and the parameters of the function to be called, as described in
    	 * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
    	 */
    	function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {
    		_upgradeTo(newImplementation);
    		(bool success, ) = newImplementation.delegatecall(data);
    		require(success);
    	}
    
    	/**
    	 * @dev Only fall back when the sender is not the admin.
    	 */
    	function _willFallback() internal virtual override {
    		require(msg.sender != ADMIN, "Cannot call fallback function from the proxy admin");
    		super._willFallback();
    	}
    }
    
    // File contracts/lending/libraries/aave-upgradeability/InitializableImmutableAdminUpgradeabilityProxy.sol
    
    // Original license: SPDX_License_Identifier: AGPL-3.0
    pragma solidity 0.8.12;
    
    /**
     * @title InitializableAdminUpgradeabilityProxy
     * @dev Extends BaseAdminUpgradeabilityProxy with an initializer function
     */
    contract InitializableImmutableAdminUpgradeabilityProxy is
    	BaseImmutableAdminUpgradeabilityProxy,
    	InitializableUpgradeabilityProxy
    {
    	constructor(address admin) BaseImmutableAdminUpgradeabilityProxy(admin) {}
    
    	/**
    	 * @dev Only fall back when the sender is not the admin.
    	 */
    	function _willFallback() internal override(BaseImmutableAdminUpgradeabilityProxy, Proxy) {
    		BaseImmutableAdminUpgradeabilityProxy._willFallback();
    	}
    }

    File 2 of 2: AToken
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
    pragma solidity ^0.8.0;
    import "../IERC20.sol";
    /**
     * @dev Interface for the optional metadata functions from the ERC20 standard.
     *
     * _Available since v4.1._
     */
    interface IERC20Metadata is IERC20 {
        /**
         * @dev Returns the name of the token.
         */
        function name() external view returns (string memory);
        /**
         * @dev Returns the symbol of the token.
         */
        function symbol() external view returns (string memory);
        /**
         * @dev Returns the decimals places of the token.
         */
        function decimals() external view returns (uint8);
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)
    pragma solidity ^0.8.0;
    /**
     * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
     * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
     *
     * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
     * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
     * need to send a transaction, and thus is not required to hold Ether at all.
     */
    interface IERC20Permit {
        /**
         * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
         * given ``owner``'s signed approval.
         *
         * IMPORTANT: The same issues {IERC20-approve} has related to transaction
         * ordering also apply here.
         *
         * Emits an {Approval} event.
         *
         * Requirements:
         *
         * - `spender` cannot be the zero address.
         * - `deadline` must be a timestamp in the future.
         * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
         * over the EIP712-formatted function arguments.
         * - the signature must use ``owner``'s current nonce (see {nonces}).
         *
         * For more information on the signature format, see the
         * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
         * section].
         */
        function permit(
            address owner,
            address spender,
            uint256 value,
            uint256 deadline,
            uint8 v,
            bytes32 r,
            bytes32 s
        ) external;
        /**
         * @dev Returns the current nonce for `owner`. This value must be
         * included whenever a signature is generated for {permit}.
         *
         * Every successful call to {permit} increases ``owner``'s nonce by one. This
         * prevents a signature from being used multiple times.
         */
        function nonces(address owner) external view returns (uint256);
        /**
         * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
         */
        // solhint-disable-next-line func-name-mixedcase
        function DOMAIN_SEPARATOR() external view returns (bytes32);
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
    pragma solidity ^0.8.0;
    /**
     * @dev Interface of the ERC20 standard as defined in the EIP.
     */
    interface IERC20 {
        /**
         * @dev Emitted when `value` tokens are moved from one account (`from`) to
         * another (`to`).
         *
         * Note that `value` may be zero.
         */
        event Transfer(address indexed from, address indexed to, uint256 value);
        /**
         * @dev Emitted when the allowance of a `spender` for an `owner` is set by
         * a call to {approve}. `value` is the new allowance.
         */
        event Approval(address indexed owner, address indexed spender, uint256 value);
        /**
         * @dev Returns the amount of tokens in existence.
         */
        function totalSupply() external view returns (uint256);
        /**
         * @dev Returns the amount of tokens owned by `account`.
         */
        function balanceOf(address account) external view returns (uint256);
        /**
         * @dev Moves `amount` tokens from the caller's account to `to`.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * Emits a {Transfer} event.
         */
        function transfer(address to, uint256 amount) external returns (bool);
        /**
         * @dev Returns the remaining number of tokens that `spender` will be
         * allowed to spend on behalf of `owner` through {transferFrom}. This is
         * zero by default.
         *
         * This value changes when {approve} or {transferFrom} are called.
         */
        function allowance(address owner, address spender) external view returns (uint256);
        /**
         * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * IMPORTANT: Beware that changing an allowance with this method brings the risk
         * that someone may use both the old and the new allowance by unfortunate
         * transaction ordering. One possible solution to mitigate this race
         * condition is to first reduce the spender's allowance to 0 and set the
         * desired value afterwards:
         * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
         *
         * Emits an {Approval} event.
         */
        function approve(address spender, uint256 amount) external returns (bool);
        /**
         * @dev Moves `amount` tokens from `from` to `to` using the
         * allowance mechanism. `amount` is then deducted from the caller's
         * allowance.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * Emits a {Transfer} event.
         */
        function transferFrom(address from, address to, uint256 amount) external returns (bool);
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
    pragma solidity ^0.8.0;
    import "../IERC20.sol";
    import "../extensions/IERC20Permit.sol";
    import "../../../utils/Address.sol";
    /**
     * @title SafeERC20
     * @dev Wrappers around ERC20 operations that throw on failure (when the token
     * contract returns false). Tokens that return no value (and instead revert or
     * throw on failure) are also supported, non-reverting calls are assumed to be
     * successful.
     * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
     * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
     */
    library SafeERC20 {
        using Address for address;
        /**
         * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
         * non-reverting calls are assumed to be successful.
         */
        function safeTransfer(IERC20 token, address to, uint256 value) internal {
            _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
        }
        /**
         * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
         * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
         */
        function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
            _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
        }
        /**
         * @dev Deprecated. This function has issues similar to the ones found in
         * {IERC20-approve}, and its usage is discouraged.
         *
         * Whenever possible, use {safeIncreaseAllowance} and
         * {safeDecreaseAllowance} instead.
         */
        function safeApprove(IERC20 token, address spender, uint256 value) internal {
            // safeApprove should only be called when setting an initial allowance,
            // or when resetting it to zero. To increase and decrease it, use
            // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
            require(
                (value == 0) || (token.allowance(address(this), spender) == 0),
                "SafeERC20: approve from non-zero to non-zero allowance"
            );
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
        }
        /**
         * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
         * non-reverting calls are assumed to be successful.
         */
        function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
            uint256 oldAllowance = token.allowance(address(this), spender);
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
        }
        /**
         * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
         * non-reverting calls are assumed to be successful.
         */
        function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
            unchecked {
                uint256 oldAllowance = token.allowance(address(this), spender);
                require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
                _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
            }
        }
        /**
         * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
         * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
         * to be set to zero before setting it to a non-zero value, such as USDT.
         */
        function forceApprove(IERC20 token, address spender, uint256 value) internal {
            bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
            if (!_callOptionalReturnBool(token, approvalCall)) {
                _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
                _callOptionalReturn(token, approvalCall);
            }
        }
        /**
         * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
         * Revert on invalid signature.
         */
        function safePermit(
            IERC20Permit token,
            address owner,
            address spender,
            uint256 value,
            uint256 deadline,
            uint8 v,
            bytes32 r,
            bytes32 s
        ) internal {
            uint256 nonceBefore = token.nonces(owner);
            token.permit(owner, spender, value, deadline, v, r, s);
            uint256 nonceAfter = token.nonces(owner);
            require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
        }
        /**
         * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
         * on the return value: the return value is optional (but if data is returned, it must not be false).
         * @param token The token targeted by the call.
         * @param data The call data (encoded using abi.encode or one of its variants).
         */
        function _callOptionalReturn(IERC20 token, bytes memory data) private {
            // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
            // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
            // the target address contains contract code and also asserts for success in the low-level call.
            bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
            require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
        /**
         * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
         * on the return value: the return value is optional (but if data is returned, it must not be false).
         * @param token The token targeted by the call.
         * @param data The call data (encoded using abi.encode or one of its variants).
         *
         * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
         */
        function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
            // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
            // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
            // and not revert is the subcall reverts.
            (bool success, bytes memory returndata) = address(token).call(data);
            return
                success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
    pragma solidity ^0.8.1;
    /**
     * @dev Collection of functions related to the address type
     */
    library Address {
        /**
         * @dev Returns true if `account` is a contract.
         *
         * [IMPORTANT]
         * ====
         * It is unsafe to assume that an address for which this function returns
         * false is an externally-owned account (EOA) and not a contract.
         *
         * Among others, `isContract` will return false for the following
         * types of addresses:
         *
         *  - an externally-owned account
         *  - a contract in construction
         *  - an address where a contract will be created
         *  - an address where a contract lived, but was destroyed
         *
         * Furthermore, `isContract` will also return true if the target contract within
         * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
         * which only has an effect at the end of a transaction.
         * ====
         *
         * [IMPORTANT]
         * ====
         * You shouldn't rely on `isContract` to protect against flash loan attacks!
         *
         * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
         * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
         * constructor.
         * ====
         */
        function isContract(address account) internal view returns (bool) {
            // This method relies on extcodesize/address.code.length, which returns 0
            // for contracts in construction, since the code is only stored at the end
            // of the constructor execution.
            return account.code.length > 0;
        }
        /**
         * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
         * `recipient`, forwarding all available gas and reverting on errors.
         *
         * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
         * of certain opcodes, possibly making contracts go over the 2300 gas limit
         * imposed by `transfer`, making them unable to receive funds via
         * `transfer`. {sendValue} removes this limitation.
         *
         * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
         *
         * IMPORTANT: because control is transferred to `recipient`, care must be
         * taken to not create reentrancy vulnerabilities. Consider using
         * {ReentrancyGuard} or the
         * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
         */
        function sendValue(address payable recipient, uint256 amount) internal {
            require(address(this).balance >= amount, "Address: insufficient balance");
            (bool success, ) = recipient.call{value: amount}("");
            require(success, "Address: unable to send value, recipient may have reverted");
        }
        /**
         * @dev Performs a Solidity function call using a low level `call`. A
         * plain `call` is an unsafe replacement for a function call: use this
         * function instead.
         *
         * If `target` reverts with a revert reason, it is bubbled up by this
         * function (like regular Solidity function calls).
         *
         * Returns the raw returned data. To convert to the expected return value,
         * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
         *
         * Requirements:
         *
         * - `target` must be a contract.
         * - calling `target` with `data` must not revert.
         *
         * _Available since v3.1._
         */
        function functionCall(address target, bytes memory data) internal returns (bytes memory) {
            return functionCallWithValue(target, data, 0, "Address: low-level call failed");
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
         * `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCall(
            address target,
            bytes memory data,
            string memory errorMessage
        ) internal returns (bytes memory) {
            return functionCallWithValue(target, data, 0, errorMessage);
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but also transferring `value` wei to `target`.
         *
         * Requirements:
         *
         * - the calling contract must have an ETH balance of at least `value`.
         * - the called Solidity function must be `payable`.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
            return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
        }
        /**
         * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
         * with `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(
            address target,
            bytes memory data,
            uint256 value,
            string memory errorMessage
        ) internal returns (bytes memory) {
            require(address(this).balance >= value, "Address: insufficient balance for call");
            (bool success, bytes memory returndata) = target.call{value: value}(data);
            return verifyCallResultFromTarget(target, success, returndata, errorMessage);
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but performing a static call.
         *
         * _Available since v3.3._
         */
        function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
            return functionStaticCall(target, data, "Address: low-level static call failed");
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
         * but performing a static call.
         *
         * _Available since v3.3._
         */
        function functionStaticCall(
            address target,
            bytes memory data,
            string memory errorMessage
        ) internal view returns (bytes memory) {
            (bool success, bytes memory returndata) = target.staticcall(data);
            return verifyCallResultFromTarget(target, success, returndata, errorMessage);
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but performing a delegate call.
         *
         * _Available since v3.4._
         */
        function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
            return functionDelegateCall(target, data, "Address: low-level delegate call failed");
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
         * but performing a delegate call.
         *
         * _Available since v3.4._
         */
        function functionDelegateCall(
            address target,
            bytes memory data,
            string memory errorMessage
        ) internal returns (bytes memory) {
            (bool success, bytes memory returndata) = target.delegatecall(data);
            return verifyCallResultFromTarget(target, success, returndata, errorMessage);
        }
        /**
         * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
         * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
         *
         * _Available since v4.8._
         */
        function verifyCallResultFromTarget(
            address target,
            bool success,
            bytes memory returndata,
            string memory errorMessage
        ) internal view returns (bytes memory) {
            if (success) {
                if (returndata.length == 0) {
                    // only check isContract if the call was successful and the return data is empty
                    // otherwise we already know that it was a contract
                    require(isContract(target), "Address: call to non-contract");
                }
                return returndata;
            } else {
                _revert(returndata, errorMessage);
            }
        }
        /**
         * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
         * revert reason or using the provided one.
         *
         * _Available since v4.3._
         */
        function verifyCallResult(
            bool success,
            bytes memory returndata,
            string memory errorMessage
        ) internal pure returns (bytes memory) {
            if (success) {
                return returndata;
            } else {
                _revert(returndata, errorMessage);
            }
        }
        function _revert(bytes memory returndata, string memory errorMessage) private pure {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly
                /// @solidity memory-safe-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/SafeMath.sol)
    pragma solidity ^0.8.0;
    // CAUTION
    // This version of SafeMath should only be used with Solidity 0.8 or later,
    // because it relies on the compiler's built in overflow checks.
    /**
     * @dev Wrappers over Solidity's arithmetic operations.
     *
     * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
     * now has built in overflow checking.
     */
    library SafeMath {
        /**
         * @dev Returns the addition of two unsigned integers, with an overflow flag.
         *
         * _Available since v3.4._
         */
        function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            unchecked {
                uint256 c = a + b;
                if (c < a) return (false, 0);
                return (true, c);
            }
        }
        /**
         * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
         *
         * _Available since v3.4._
         */
        function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            unchecked {
                if (b > a) return (false, 0);
                return (true, a - b);
            }
        }
        /**
         * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
         *
         * _Available since v3.4._
         */
        function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            unchecked {
                // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                // benefit is lost if 'b' is also tested.
                // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
                if (a == 0) return (true, 0);
                uint256 c = a * b;
                if (c / a != b) return (false, 0);
                return (true, c);
            }
        }
        /**
         * @dev Returns the division of two unsigned integers, with a division by zero flag.
         *
         * _Available since v3.4._
         */
        function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            unchecked {
                if (b == 0) return (false, 0);
                return (true, a / b);
            }
        }
        /**
         * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
         *
         * _Available since v3.4._
         */
        function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            unchecked {
                if (b == 0) return (false, 0);
                return (true, a % b);
            }
        }
        /**
         * @dev Returns the addition of two unsigned integers, reverting on
         * overflow.
         *
         * Counterpart to Solidity's `+` operator.
         *
         * Requirements:
         *
         * - Addition cannot overflow.
         */
        function add(uint256 a, uint256 b) internal pure returns (uint256) {
            return a + b;
        }
        /**
         * @dev Returns the subtraction of two unsigned integers, reverting on
         * overflow (when the result is negative).
         *
         * Counterpart to Solidity's `-` operator.
         *
         * Requirements:
         *
         * - Subtraction cannot overflow.
         */
        function sub(uint256 a, uint256 b) internal pure returns (uint256) {
            return a - b;
        }
        /**
         * @dev Returns the multiplication of two unsigned integers, reverting on
         * overflow.
         *
         * Counterpart to Solidity's `*` operator.
         *
         * Requirements:
         *
         * - Multiplication cannot overflow.
         */
        function mul(uint256 a, uint256 b) internal pure returns (uint256) {
            return a * b;
        }
        /**
         * @dev Returns the integer division of two unsigned integers, reverting on
         * division by zero. The result is rounded towards zero.
         *
         * Counterpart to Solidity's `/` operator.
         *
         * Requirements:
         *
         * - The divisor cannot be zero.
         */
        function div(uint256 a, uint256 b) internal pure returns (uint256) {
            return a / b;
        }
        /**
         * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
         * reverting when dividing by zero.
         *
         * Counterpart to Solidity's `%` operator. This function uses a `revert`
         * opcode (which leaves remaining gas untouched) while Solidity uses an
         * invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         *
         * - The divisor cannot be zero.
         */
        function mod(uint256 a, uint256 b) internal pure returns (uint256) {
            return a % b;
        }
        /**
         * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
         * overflow (when the result is negative).
         *
         * CAUTION: This function is deprecated because it requires allocating memory for the error
         * message unnecessarily. For custom revert reasons use {trySub}.
         *
         * Counterpart to Solidity's `-` operator.
         *
         * Requirements:
         *
         * - Subtraction cannot overflow.
         */
        function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            unchecked {
                require(b <= a, errorMessage);
                return a - b;
            }
        }
        /**
         * @dev Returns the integer division of two unsigned integers, reverting with custom message on
         * division by zero. The result is rounded towards zero.
         *
         * Counterpart to Solidity's `/` operator. Note: this function uses a
         * `revert` opcode (which leaves remaining gas untouched) while Solidity
         * uses an invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         *
         * - The divisor cannot be zero.
         */
        function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            unchecked {
                require(b > 0, errorMessage);
                return a / b;
            }
        }
        /**
         * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
         * reverting with custom message when dividing by zero.
         *
         * CAUTION: This function is deprecated because it requires allocating memory for the error
         * message unnecessarily. For custom revert reasons use {tryMod}.
         *
         * Counterpart to Solidity's `%` operator. This function uses a `revert`
         * opcode (which leaves remaining gas untouched) while Solidity uses an
         * invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         *
         * - The divisor cannot be zero.
         */
        function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            unchecked {
                require(b > 0, errorMessage);
                return a % b;
            }
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.12;
    /*
     * @dev Provides information about the current execution context, including the
     * sender of the transaction and its data. While these are generally available
     * via msg.sender and msg.data, they should not be accessed in such a direct
     * manner, since when dealing with GSN meta-transactions the account sending and
     * paying for execution may not be the actual sender (as far as an application
     * is concerned).
     *
     * This contract is only required for intermediate, library-like contracts.
     */
    abstract contract Context {
    \tfunction _msgSender() internal view virtual returns (address payable) {
    \t\treturn payable(msg.sender);
    \t}
    \tfunction _msgData() internal view virtual returns (bytes memory) {
    \t\tthis; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
    \t\treturn msg.data;
    \t}
    }
    // SPDX-License-Identifier: agpl-3.0
    pragma solidity 0.8.12;
    pragma experimental ABIEncoderV2;
    interface IAaveIncentivesController {
    \tevent RewardsAccrued(address indexed user, uint256 amount);
    \tevent RewardsClaimed(address indexed user, address indexed to, uint256 amount);
    \tevent RewardsClaimed(address indexed user, address indexed to, address indexed claimer, uint256 amount);
    \tevent ClaimerSet(address indexed user, address indexed claimer);
    \t/*
    \t * @dev Returns the configuration of the distribution for a certain asset
    \t * @param asset The address of the reference asset of the distribution
    \t * @return The asset index, the emission per second and the last updated timestamp
    \t **/
    \tfunction getAssetData(address asset) external view returns (uint256, uint256, uint256);
    \t/**
    \t * @dev Whitelists an address to claim the rewards on behalf of another address
    \t * @param user The address of the user
    \t * @param claimer The address of the claimer
    \t */
    \tfunction setClaimer(address user, address claimer) external;
    \t/**
    \t * @dev Returns the whitelisted claimer for a certain address (0x0 if not set)
    \t * @param user The address of the user
    \t * @return The claimer address
    \t */
    \tfunction getClaimer(address user) external view returns (address);
    \t/**
    \t * @dev Configure assets for a certain rewards emission
    \t * @param assets The assets to incentivize
    \t * @param emissionsPerSecond The emission for each asset
    \t */
    \tfunction configureAssets(address[] calldata assets, uint256[] calldata emissionsPerSecond) external;
    \t/**
    \t * @dev Called by the corresponding asset on any update that affects the rewards distribution
    \t * @param user The address of the user
    \t **/
    \tfunction handleActionBefore(address user) external;
    \t/**
    \t * @dev Called by the corresponding asset on any update that affects the rewards distribution
    \t * @param user The address of the user
    \t * @param userBalance The balance of the user of the asset in the lending pool
    \t * @param totalSupply The total supply of the asset in the lending pool
    \t **/
    \tfunction handleActionAfter(address user, uint256 userBalance, uint256 totalSupply) external;
    \t/**
    \t * @dev Returns the total of rewards of an user, already accrued + not yet accrued
    \t * @param user The address of the user
    \t * @return The rewards
    \t **/
    \tfunction getRewardsBalance(address[] calldata assets, address user) external view returns (uint256);
    \t/**
    \t * @dev Claims reward for an user, on all the assets of the lending pool, accumulating the pending rewards
    \t * @param amount Amount of rewards to claim
    \t * @param to Address that will be receiving the rewards
    \t * @return Rewards claimed
    \t **/
    \tfunction claimRewards(address[] calldata assets, uint256 amount, address to) external returns (uint256);
    \t/**
    \t * @dev Claims reward for an user on behalf, on all the assets of the lending pool, accumulating the pending rewards. The caller must
    \t * be whitelisted via "allowClaimOnBehalf" function by the RewardsAdmin role manager
    \t * @param amount Amount of rewards to claim
    \t * @param user Address to check and claim rewards
    \t * @param to Address that will be receiving the rewards
    \t * @return Rewards claimed
    \t **/
    \tfunction claimRewardsOnBehalf(
    \t\taddress[] calldata assets,
    \t\tuint256 amount,
    \t\taddress user,
    \t\taddress to
    \t) external returns (uint256);
    \t/**
    \t * @dev returns the unclaimed rewards of the user
    \t * @param user the address of the user
    \t * @return the unclaimed user rewards
    \t */
    \tfunction getUserUnclaimedRewards(address user) external view returns (uint256);
    \t/**
    \t * @dev returns the unclaimed rewards of the user
    \t * @param user the address of the user
    \t * @param asset The asset to incentivize
    \t * @return the user index for the asset
    \t */
    \tfunction getUserAssetData(address user, address asset) external view returns (uint256);
    \t/**
    \t * @dev for backward compatibility with previous implementation of the Incentives controller
    \t */
    \tfunction REWARD_TOKEN() external view returns (address);
    \t/**
    \t * @dev for backward compatibility with previous implementation of the Incentives controller
    \t */
    \tfunction PRECISION() external view returns (uint8);
    \t/**
    \t * @dev Gets the distribution end timestamp of the emissions
    \t */
    \tfunction DISTRIBUTION_END() external view returns (uint256);
    }
    // SPDX-License-Identifier: agpl-3.0
    pragma solidity 0.8.12;
    import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
    import {IScaledBalanceToken} from "./IScaledBalanceToken.sol";
    import {IInitializableAToken} from "./IInitializableAToken.sol";
    import {IAaveIncentivesController} from "./IAaveIncentivesController.sol";
    import {ILendingPool} from "./ILendingPool.sol";
    interface IAToken is IERC20, IScaledBalanceToken, IInitializableAToken {
    \t/**
    \t * @dev Emitted after the mint action
    \t * @param from The address performing the mint
    \t * @param value The amount being
    \t * @param index The new liquidity index of the reserve
    \t **/
    \tevent Mint(address indexed from, uint256 value, uint256 index);
    \t/**
    \t * @dev Mints `amount` aTokens to `user`
    \t * @param user The address receiving the minted tokens
    \t * @param amount The amount of tokens getting minted
    \t * @param index The new liquidity index of the reserve
    \t * @return `true` if the the previous balance of the user was 0
    \t */
    \tfunction mint(address user, uint256 amount, uint256 index) external returns (bool);
    \t/**
    \t * @dev Emitted after aTokens are burned
    \t * @param from The owner of the aTokens, getting them burned
    \t * @param target The address that will receive the underlying
    \t * @param value The amount being burned
    \t * @param index The new liquidity index of the reserve
    \t **/
    \tevent Burn(address indexed from, address indexed target, uint256 value, uint256 index);
    \t/**
    \t * @dev Emitted during the transfer action
    \t * @param from The user whose tokens are being transferred
    \t * @param to The recipient
    \t * @param value The amount being transferred
    \t * @param index The new liquidity index of the reserve
    \t **/
    \tevent BalanceTransfer(address indexed from, address indexed to, uint256 value, uint256 index);
    \t/**
    \t * @dev Burns aTokens from `user` and sends the equivalent amount of underlying to `receiverOfUnderlying`
    \t * @param user The owner of the aTokens, getting them burned
    \t * @param receiverOfUnderlying The address that will receive the underlying
    \t * @param amount The amount being burned
    \t * @param index The new liquidity index of the reserve
    \t **/
    \tfunction burn(address user, address receiverOfUnderlying, uint256 amount, uint256 index) external;
    \t/**
    \t * @dev Mints aTokens to the reserve treasury
    \t * @param amount The amount of tokens getting minted
    \t * @param index The new liquidity index of the reserve
    \t */
    \tfunction mintToTreasury(uint256 amount, uint256 index) external;
    \t/**
    \t * @dev Transfers aTokens in the event of a borrow being liquidated, in case the liquidators reclaims the aToken
    \t * @param from The address getting liquidated, current owner of the aTokens
    \t * @param to The recipient
    \t * @param value The amount of tokens getting transferred
    \t **/
    \tfunction transferOnLiquidation(address from, address to, uint256 value) external;
    \t/**
    \t * @dev Transfers the underlying asset to `target`. Used by the LendingPool to transfer
    \t * assets in borrow(), withdraw() and flashLoan()
    \t * @param user The recipient of the underlying
    \t * @param amount The amount getting transferred
    \t * @return The amount transferred
    \t **/
    \tfunction transferUnderlyingTo(address user, uint256 amount) external returns (uint256);
    \t/**
    \t * @dev Invoked to execute actions on the aToken side after a repayment.
    \t * @param user The user executing the repayment
    \t * @param amount The amount getting repaid
    \t **/
    \tfunction handleRepayment(address user, uint256 amount) external;
    \t/**
    \t * @dev Updates the treasury address
    \t * @param treasury The new treasury address
    \t */
    \tfunction setTreasuryAddress(address treasury) external;
    \t/**
    \t * @dev Returns the address of the incentives controller contract
    \t **/
    \tfunction getIncentivesController() external view returns (IAaveIncentivesController);
    \t/**
    \t * @dev Returns the address of the underlying asset of this aToken (E.g. WETH for aWETH)
    \t **/
    \tfunction UNDERLYING_ASSET_ADDRESS() external view returns (address);
    \t/**
    \t * @dev Returns the address of the lending pool where this aToken is used
    \t **/
    \tfunction POOL() external view returns (ILendingPool);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.12;
    import "./LockedBalance.sol";
    interface IFeeDistribution {
    \tstruct RewardData {
    \t\taddress token;
    \t\tuint256 amount;
    \t}
    \tfunction addReward(address rewardsToken) external;
    \tfunction removeReward(address _rewardToken) external;
    }
    // SPDX-License-Identifier: agpl-3.0
    pragma solidity 0.8.12;
    import {ILendingPool} from "./ILendingPool.sol";
    import {IAaveIncentivesController} from "./IAaveIncentivesController.sol";
    /**
     * @title IInitializableAToken
     * @notice Interface for the initialize function on AToken
     * @author Aave
     **/
    interface IInitializableAToken {
    \t/**
    \t * @dev Emitted when an aToken is initialized
    \t * @param underlyingAsset The address of the underlying asset
    \t * @param pool The address of the associated lending pool
    \t * @param treasury The address of the treasury
    \t * @param incentivesController The address of the incentives controller for this aToken
    \t * @param aTokenDecimals the decimals of the underlying
    \t * @param aTokenName the name of the aToken
    \t * @param aTokenSymbol the symbol of the aToken
    \t * @param params A set of encoded parameters for additional initialization
    \t **/
    \tevent Initialized(
    \t\taddress indexed underlyingAsset,
    \t\taddress indexed pool,
    \t\taddress treasury,
    \t\taddress incentivesController,
    \t\tuint8 aTokenDecimals,
    \t\tstring aTokenName,
    \t\tstring aTokenSymbol,
    \t\tbytes params
    \t);
    \t/**
    \t * @dev Initializes the aToken
    \t * @param pool The address of the lending pool where this aToken will be used
    \t * @param treasury The address of the Aave treasury, receiving the fees on this aToken
    \t * @param underlyingAsset The address of the underlying asset of this aToken (E.g. WETH for aWETH)
    \t * @param incentivesController The smart contract managing potential incentives distribution
    \t * @param aTokenDecimals The decimals of the aToken, same as the underlying asset's
    \t * @param aTokenName The name of the aToken
    \t * @param aTokenSymbol The symbol of the aToken
    \t */
    \tfunction initialize(
    \t\tILendingPool pool,
    \t\taddress treasury,
    \t\taddress underlyingAsset,
    \t\tIAaveIncentivesController incentivesController,
    \t\tuint8 aTokenDecimals,
    \t\tstring calldata aTokenName,
    \t\tstring calldata aTokenSymbol,
    \t\tbytes calldata params
    \t) external;
    }
    // SPDX-License-Identifier: agpl-3.0
    pragma solidity 0.8.12;
    pragma experimental ABIEncoderV2;
    import {ILendingPoolAddressesProvider} from "./ILendingPoolAddressesProvider.sol";
    import {DataTypes} from "../lending/libraries/types/DataTypes.sol";
    interface ILendingPool {
    \t/**
    \t * @dev Emitted on deposit()
    \t * @param reserve The address of the underlying asset of the reserve
    \t * @param user The address initiating the deposit
    \t * @param onBehalfOf The beneficiary of the deposit, receiving the aTokens
    \t * @param amount The amount deposited
    \t * @param referral The referral code used
    \t **/
    \tevent Deposit(
    \t\taddress indexed reserve,
    \t\taddress user,
    \t\taddress indexed onBehalfOf,
    \t\tuint256 amount,
    \t\tuint16 indexed referral
    \t);
    \t/**
    \t * @dev Emitted on withdraw()
    \t * @param reserve The address of the underlyng asset being withdrawn
    \t * @param user The address initiating the withdrawal, owner of aTokens
    \t * @param to Address that will receive the underlying
    \t * @param amount The amount to be withdrawn
    \t **/
    \tevent Withdraw(address indexed reserve, address indexed user, address indexed to, uint256 amount);
    \t/**
    \t * @dev Emitted on borrow() and flashLoan() when debt needs to be opened
    \t * @param reserve The address of the underlying asset being borrowed
    \t * @param user The address of the user initiating the borrow(), receiving the funds on borrow() or just
    \t * initiator of the transaction on flashLoan()
    \t * @param onBehalfOf The address that will be getting the debt
    \t * @param amount The amount borrowed out
    \t * @param borrowRateMode The rate mode: 1 for Stable, 2 for Variable
    \t * @param borrowRate The numeric rate at which the user has borrowed
    \t * @param referral The referral code used
    \t **/
    \tevent Borrow(
    \t\taddress indexed reserve,
    \t\taddress user,
    \t\taddress indexed onBehalfOf,
    \t\tuint256 amount,
    \t\tuint256 borrowRateMode,
    \t\tuint256 borrowRate,
    \t\tuint16 indexed referral
    \t);
    \t/**
    \t * @dev Emitted on repay()
    \t * @param reserve The address of the underlying asset of the reserve
    \t * @param user The beneficiary of the repayment, getting his debt reduced
    \t * @param repayer The address of the user initiating the repay(), providing the funds
    \t * @param amount The amount repaid
    \t **/
    \tevent Repay(address indexed reserve, address indexed user, address indexed repayer, uint256 amount);
    \t/**
    \t * @dev Emitted on swapBorrowRateMode()
    \t * @param reserve The address of the underlying asset of the reserve
    \t * @param user The address of the user swapping his rate mode
    \t * @param rateMode The rate mode that the user wants to swap to
    \t **/
    \tevent Swap(address indexed reserve, address indexed user, uint256 rateMode);
    \t/**
    \t * @dev Emitted on setUserUseReserveAsCollateral()
    \t * @param reserve The address of the underlying asset of the reserve
    \t * @param user The address of the user enabling the usage as collateral
    \t **/
    \tevent ReserveUsedAsCollateralEnabled(address indexed reserve, address indexed user);
    \t/**
    \t * @dev Emitted on setUserUseReserveAsCollateral()
    \t * @param reserve The address of the underlying asset of the reserve
    \t * @param user The address of the user enabling the usage as collateral
    \t **/
    \tevent ReserveUsedAsCollateralDisabled(address indexed reserve, address indexed user);
    \t/**
    \t * @dev Emitted on rebalanceStableBorrowRate()
    \t * @param reserve The address of the underlying asset of the reserve
    \t * @param user The address of the user for which the rebalance has been executed
    \t **/
    \tevent RebalanceStableBorrowRate(address indexed reserve, address indexed user);
    \t/**
    \t * @dev Emitted on flashLoan()
    \t * @param target The address of the flash loan receiver contract
    \t * @param initiator The address initiating the flash loan
    \t * @param asset The address of the asset being flash borrowed
    \t * @param amount The amount flash borrowed
    \t * @param premium The fee flash borrowed
    \t * @param referralCode The referral code used
    \t **/
    \tevent FlashLoan(
    \t\taddress indexed target,
    \t\taddress indexed initiator,
    \t\taddress indexed asset,
    \t\tuint256 amount,
    \t\tuint256 premium,
    \t\tuint16 referralCode
    \t);
    \t/**
    \t * @dev Emitted when the pause is triggered.
    \t */
    \tevent Paused();
    \t/**
    \t * @dev Emitted when the pause is lifted.
    \t */
    \tevent Unpaused();
    \t/**
    \t * @dev Emitted when a borrower is liquidated. This event is emitted by the LendingPool via
    \t * LendingPoolCollateral manager using a DELEGATECALL
    \t * This allows to have the events in the generated ABI for LendingPool.
    \t * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation
    \t * @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation
    \t * @param user The address of the borrower getting liquidated
    \t * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover
    \t * @param liquidatedCollateralAmount The amount of collateral received by the liiquidator
    \t * @param liquidator The address of the liquidator
    \t * @param receiveAToken `true` if the liquidators wants to receive the collateral aTokens, `false` if he wants
    \t * to receive the underlying collateral asset directly
    \t **/
    \tevent LiquidationCall(
    \t\taddress indexed collateralAsset,
    \t\taddress indexed debtAsset,
    \t\taddress indexed user,
    \t\tuint256 debtToCover,
    \t\tuint256 liquidatedCollateralAmount,
    \t\taddress liquidator,
    \t\tbool receiveAToken
    \t);
    \t/**
    \t * @dev Emitted when the state of a reserve is updated. NOTE: This event is actually declared
    \t * in the ReserveLogic library and emitted in the updateInterestRates() function. Since the function is internal,
    \t * the event will actually be fired by the LendingPool contract. The event is therefore replicated here so it
    \t * gets added to the LendingPool ABI
    \t * @param reserve The address of the underlying asset of the reserve
    \t * @param liquidityRate The new liquidity rate
    \t * @param stableBorrowRate The new stable borrow rate
    \t * @param variableBorrowRate The new variable borrow rate
    \t * @param liquidityIndex The new liquidity index
    \t * @param variableBorrowIndex The new variable borrow index
    \t **/
    \tevent ReserveDataUpdated(
    \t\taddress indexed reserve,
    \t\tuint256 liquidityRate,
    \t\tuint256 stableBorrowRate,
    \t\tuint256 variableBorrowRate,
    \t\tuint256 liquidityIndex,
    \t\tuint256 variableBorrowIndex
    \t);
    \tfunction initialize(ILendingPoolAddressesProvider provider) external;
    \t/**
    \t * @dev Deposits an `amount` of underlying asset into the reserve, receiving in return overlying aTokens.
    \t * - E.g. User deposits 100 USDC and gets in return 100 aUSDC
    \t * @param asset The address of the underlying asset to deposit
    \t * @param amount The amount to be deposited
    \t * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user
    \t *   wants to receive them on his own wallet, or a different address if the beneficiary of aTokens
    \t *   is a different wallet
    \t * @param referralCode Code used to register the integrator originating the operation, for potential rewards.
    \t *   0 if the action is executed directly by the user, without any middle-man
    \t **/
    \tfunction deposit(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external;
    \tfunction depositWithAutoDLP(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external;
    \t/**
    \t * @dev Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned
    \t * E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC
    \t * @param asset The address of the underlying asset to withdraw
    \t * @param amount The underlying amount to be withdrawn
    \t *   - Send the value type(uint256).max in order to withdraw the whole aToken balance
    \t * @param to Address that will receive the underlying, same as msg.sender if the user
    \t *   wants to receive it on his own wallet, or a different address if the beneficiary is a
    \t *   different wallet
    \t * @return The final amount withdrawn
    \t **/
    \tfunction withdraw(address asset, uint256 amount, address to) external returns (uint256);
    \t/**
    \t * @dev Allows users to borrow a specific `amount` of the reserve underlying asset, provided that the borrower
    \t * already deposited enough collateral, or he was given enough allowance by a credit delegator on the
    \t * corresponding debt token (StableDebtToken or VariableDebtToken)
    \t * - E.g. User borrows 100 USDC passing as `onBehalfOf` his own address, receiving the 100 USDC in his wallet
    \t *   and 100 stable/variable debt tokens, depending on the `interestRateMode`
    \t * @param asset The address of the underlying asset to borrow
    \t * @param amount The amount to be borrowed
    \t * @param interestRateMode The interest rate mode at which the user wants to borrow: 1 for Stable, 2 for Variable
    \t * @param referralCode Code used to register the integrator originating the operation, for potential rewards.
    \t *   0 if the action is executed directly by the user, without any middle-man
    \t * @param onBehalfOf Address of the user who will receive the debt. Should be the address of the borrower itself
    \t * calling the function if he wants to borrow against his own collateral, or the address of the credit delegator
    \t * if he has been given credit delegation allowance
    \t **/
    \tfunction borrow(
    \t\taddress asset,
    \t\tuint256 amount,
    \t\tuint256 interestRateMode,
    \t\tuint16 referralCode,
    \t\taddress onBehalfOf
    \t) external;
    \t/**
    \t * @notice Repays a borrowed `amount` on a specific reserve, burning the equivalent debt tokens owned
    \t * - E.g. User repays 100 USDC, burning 100 variable/stable debt tokens of the `onBehalfOf` address
    \t * @param asset The address of the borrowed underlying asset previously borrowed
    \t * @param amount The amount to repay
    \t * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode`
    \t * @param rateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable
    \t * @param onBehalfOf Address of the user who will get his debt reduced/removed. Should be the address of the
    \t * user calling the function if he wants to reduce/remove his own debt, or the address of any other
    \t * other borrower whose debt should be removed
    \t * @return The final amount repaid
    \t **/
    \tfunction repay(address asset, uint256 amount, uint256 rateMode, address onBehalfOf) external returns (uint256);
    \t/**
    \t * @dev Allows a borrower to swap his debt between stable and variable mode, or viceversa
    \t * @param asset The address of the underlying asset borrowed
    \t * @param rateMode The rate mode that the user wants to swap to
    \t **/
    \tfunction swapBorrowRateMode(address asset, uint256 rateMode) external;
    \t/**
    \t * @dev Rebalances the stable interest rate of a user to the current stable rate defined on the reserve.
    \t * - Users can be rebalanced if the following conditions are satisfied:
    \t *     1. Usage ratio is above 95%
    \t *     2. the current deposit APY is below REBALANCE_UP_THRESHOLD * maxVariableBorrowRate, which means that too much has been
    \t *        borrowed at a stable rate and depositors are not earning enough
    \t * @param asset The address of the underlying asset borrowed
    \t * @param user The address of the user to be rebalanced
    \t **/
    \tfunction rebalanceStableBorrowRate(address asset, address user) external;
    \t/**
    \t * @dev Allows depositors to enable/disable a specific deposited asset as collateral
    \t * @param asset The address of the underlying asset deposited
    \t * @param useAsCollateral `true` if the user wants to use the deposit as collateral, `false` otherwise
    \t **/
    \tfunction setUserUseReserveAsCollateral(address asset, bool useAsCollateral) external;
    \t/**
    \t * @dev Function to liquidate a non-healthy position collateral-wise, with Health Factor below 1
    \t * - The caller (liquidator) covers `debtToCover` amount of debt of the user getting liquidated, and receives
    \t *   a proportionally amount of the `collateralAsset` plus a bonus to cover market risk
    \t * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation
    \t * @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation
    \t * @param user The address of the borrower getting liquidated
    \t * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover
    \t * @param receiveAToken `true` if the liquidators wants to receive the collateral aTokens, `false` if he wants
    \t * to receive the underlying collateral asset directly
    \t **/
    \tfunction liquidationCall(
    \t\taddress collateralAsset,
    \t\taddress debtAsset,
    \t\taddress user,
    \t\tuint256 debtToCover,
    \t\tbool receiveAToken
    \t) external;
    \t/**
    \t * @dev Allows smartcontracts to access the liquidity of the pool within one transaction,
    \t * as long as the amount taken plus a fee is returned.
    \t * IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept into consideration.
    \t * For further details please visit https://developers.aave.com
    \t * @param receiverAddress The address of the contract receiving the funds, implementing the IFlashLoanReceiver interface
    \t * @param assets The addresses of the assets being flash-borrowed
    \t * @param amounts The amounts amounts being flash-borrowed
    \t * @param modes Types of the debt to open if the flash loan is not returned:
    \t *   0 -> Don't open any debt, just revert if funds can't be transferred from the receiver
    \t *   1 -> Open debt at stable rate for the value of the amount flash-borrowed to the `onBehalfOf` address
    \t *   2 -> Open debt at variable rate for the value of the amount flash-borrowed to the `onBehalfOf` address
    \t * @param onBehalfOf The address  that will receive the debt in the case of using on `modes` 1 or 2
    \t * @param params Variadic packed params to pass to the receiver as extra information
    \t * @param referralCode Code used to register the integrator originating the operation, for potential rewards.
    \t *   0 if the action is executed directly by the user, without any middle-man
    \t **/
    \tfunction flashLoan(
    \t\taddress receiverAddress,
    \t\taddress[] calldata assets,
    \t\tuint256[] calldata amounts,
    \t\tuint256[] calldata modes,
    \t\taddress onBehalfOf,
    \t\tbytes calldata params,
    \t\tuint16 referralCode
    \t) external;
    \t/**
    \t * @dev Returns the user account data across all the reserves
    \t * @param user The address of the user
    \t * @return totalCollateral the total collateral in USD to 8 decimals of the user
    \t * @return totalDebt the total debt in USD to 8 decimals of the user
    \t * @return availableBorrows the borrowing power left of the user
    \t * @return currentLiquidationThreshold the liquidation threshold of the user
    \t * @return ltv the loan to value of the user
    \t * @return healthFactor the current health factor of the user
    \t **/
    \tfunction getUserAccountData(
    \t\taddress user
    \t)
    \t\texternal
    \t\tview
    \t\treturns (
    \t\t\tuint256 totalCollateral,
    \t\t\tuint256 totalDebt,
    \t\t\tuint256 availableBorrows,
    \t\t\tuint256 currentLiquidationThreshold,
    \t\t\tuint256 ltv,
    \t\t\tuint256 healthFactor
    \t\t);
    \tfunction initReserve(
    \t\taddress reserve,
    \t\taddress aTokenAddress,
    \t\taddress stableDebtAddress,
    \t\taddress variableDebtAddress,
    \t\taddress interestRateStrategyAddress
    \t) external;
    \tfunction setReserveInterestRateStrategyAddress(address reserve, address rateStrategyAddress) external;
    \tfunction setConfiguration(address reserve, uint256 configuration) external;
    \t/**
    \t * @dev Returns the configuration of the reserve
    \t * @param asset The address of the underlying asset of the reserve
    \t * @return The configuration of the reserve
    \t **/
    \tfunction getConfiguration(address asset) external view returns (DataTypes.ReserveConfigurationMap memory);
    \t/**
    \t * @dev Returns the configuration of the user across all the reserves
    \t * @param user The user address
    \t * @return The configuration of the user
    \t **/
    \tfunction getUserConfiguration(address user) external view returns (DataTypes.UserConfigurationMap memory);
    \t/**
    \t * @dev Returns the normalized income normalized income of the reserve
    \t * @param asset The address of the underlying asset of the reserve
    \t * @return The reserve's normalized income
    \t */
    \tfunction getReserveNormalizedIncome(address asset) external view returns (uint256);
    \t/**
    \t * @dev Returns the normalized variable debt per unit of asset
    \t * @param asset The address of the underlying asset of the reserve
    \t * @return The reserve normalized variable debt
    \t */
    \tfunction getReserveNormalizedVariableDebt(address asset) external view returns (uint256);
    \t/**
    \t * @dev Returns the state and configuration of the reserve
    \t * @param asset The address of the underlying asset of the reserve
    \t * @return The state of the reserve
    \t **/
    \tfunction getReserveData(address asset) external view returns (DataTypes.ReserveData memory);
    \tfunction finalizeTransfer(
    \t\taddress asset,
    \t\taddress from,
    \t\taddress to,
    \t\tuint256 amount,
    \t\tuint256 balanceFromAfter,
    \t\tuint256 balanceToBefore
    \t) external;
    \tfunction getReservesList() external view returns (address[] memory);
    \tfunction getAddressesProvider() external view returns (ILendingPoolAddressesProvider);
    \tfunction setPause(bool val) external;
    \tfunction paused() external view returns (bool);
    }
    // SPDX-License-Identifier: agpl-3.0
    pragma solidity 0.8.12;
    /**
     * @title LendingPoolAddressesProvider contract
     * @dev Main registry of addresses part of or connected to the protocol, including permissioned roles
     * - Acting also as factory of proxies and admin of those, so with right to change its implementations
     * - Owned by the Aave Governance
     * @author Aave
     **/
    interface ILendingPoolAddressesProvider {
    \tevent MarketIdSet(string newMarketId);
    \tevent LendingPoolUpdated(address indexed newAddress);
    \tevent ConfigurationAdminUpdated(address indexed newAddress);
    \tevent EmergencyAdminUpdated(address indexed newAddress);
    \tevent LendingPoolConfiguratorUpdated(address indexed newAddress);
    \tevent LendingPoolCollateralManagerUpdated(address indexed newAddress);
    \tevent PriceOracleUpdated(address indexed newAddress);
    \tevent LendingRateOracleUpdated(address indexed newAddress);
    \tevent ProxyCreated(bytes32 id, address indexed newAddress);
    \tevent AddressSet(bytes32 id, address indexed newAddress, bool hasProxy);
    \tfunction getMarketId() external view returns (string memory);
    \tfunction setMarketId(string calldata marketId) external;
    \tfunction setAddress(bytes32 id, address newAddress) external;
    \tfunction setAddressAsProxy(bytes32 id, address impl) external;
    \tfunction getAddress(bytes32 id) external view returns (address);
    \tfunction getLendingPool() external view returns (address);
    \tfunction setLendingPoolImpl(address pool) external;
    \tfunction getLendingPoolConfigurator() external view returns (address);
    \tfunction setLendingPoolConfiguratorImpl(address configurator) external;
    \tfunction getLendingPoolCollateralManager() external view returns (address);
    \tfunction setLendingPoolCollateralManager(address manager) external;
    \tfunction getPoolAdmin() external view returns (address);
    \tfunction setPoolAdmin(address admin) external;
    \tfunction getEmergencyAdmin() external view returns (address);
    \tfunction setEmergencyAdmin(address admin) external;
    \tfunction getPriceOracle() external view returns (address);
    \tfunction setPriceOracle(address priceOracle) external;
    \tfunction getLendingRateOracle() external view returns (address);
    \tfunction setLendingRateOracle(address lendingRateOracle) external;
    \tfunction getLiquidationFeeTo() external view returns (address);
    \tfunction setLiquidationFeeTo(address liquidationFeeTo) external;
    }
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.12;
    import "./LockedBalance.sol";
    import {IFeeDistribution} from "./IMultiFeeDistribution.sol";
    interface IMiddleFeeDistribution is IFeeDistribution {
    \tfunction forwardReward(address[] memory _rewardTokens) external;
    \tfunction getRdntTokenAddress() external view returns (address);
    \tfunction getMultiFeeDistributionAddress() external view returns (address);
    \tfunction operationExpenseRatio() external view returns (uint256);
    \tfunction operationExpenses() external view returns (address);
    \tfunction isRewardToken(address) external view returns (bool);
    }
    // SPDX-License-Identifier: agpl-3.0
    pragma solidity 0.8.12;
    import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
    interface IMintableToken is IERC20 {
    \tfunction mint(address _receiver, uint256 _amount) external returns (bool);
    \tfunction burn(uint256 _amount) external returns (bool);
    \tfunction setMinter(address _minter) external returns (bool);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.12;
    import "./LockedBalance.sol";
    import "./IFeeDistribution.sol";
    import "./IMintableToken.sol";
    interface IMultiFeeDistribution is IFeeDistribution {
    \tfunction exit(bool claimRewards) external;
    \tfunction stake(uint256 amount, address onBehalfOf, uint256 typeIndex) external;
    \tfunction rdntToken() external view returns (IMintableToken);
    \tfunction getPriceProvider() external view returns (address);
    \tfunction lockInfo(address user) external view returns (LockedBalance[] memory);
    \tfunction autocompoundDisabled(address user) external view returns (bool);
    \tfunction defaultLockIndex(address _user) external view returns (uint256);
    \tfunction autoRelockDisabled(address user) external view returns (bool);
    \tfunction totalBalance(address user) external view returns (uint256);
    \tfunction lockedBalance(address user) external view returns (uint256);
    \tfunction lockedBalances(
    \t\taddress user
    \t) external view returns (uint256, uint256, uint256, uint256, LockedBalance[] memory);
    \tfunction getBalances(address _user) external view returns (Balances memory);
    \tfunction zapVestingToLp(address _address) external returns (uint256);
    \tfunction claimableRewards(address account) external view returns (IFeeDistribution.RewardData[] memory rewards);
    \tfunction setDefaultRelockTypeIndex(uint256 _index) external;
    \tfunction daoTreasury() external view returns (address);
    \tfunction stakingToken() external view returns (address);
    \tfunction userSlippage(address) external view returns (uint256);
    \tfunction claimFromConverter(address) external;
    \tfunction vestTokens(address user, uint256 amount, bool withPenalty) external;
    }
    interface IMFDPlus is IMultiFeeDistribution {
    \tfunction getLastClaimTime(address _user) external returns (uint256);
    \tfunction claimBounty(address _user, bool _execute) external returns (bool issueBaseBounty);
    \tfunction claimCompound(address _user, bool _execute, uint256 _slippage) external returns (uint256 bountyAmt);
    \tfunction setAutocompound(bool state, uint256 slippage) external;
    \tfunction setUserSlippage(uint256 slippage) external;
    \tfunction toggleAutocompound() external;
    }
    // SPDX-License-Identifier: agpl-3.0
    pragma solidity 0.8.12;
    /************
    @title IPriceOracle interface
    @notice Interface for the Aave price oracle.*/
    interface IPriceOracle {
    \t/***********
        @dev returns the asset price in ETH
         */
    \tfunction getAssetPrice(address asset) external view returns (uint256);
    \t/***********
        @dev sets the asset price, in wei
         */
    \tfunction setAssetPrice(address asset, uint256 price) external;
    }
    // SPDX-License-Identifier: agpl-3.0
    pragma solidity 0.8.12;
    interface IScaledBalanceToken {
    \t/**
    \t * @dev Returns the scaled balance of the user. The scaled balance is the sum of all the
    \t * updated stored balance divided by the reserve's liquidity index at the moment of the update
    \t * @param user The user whose balance is calculated
    \t * @return The scaled balance of the user
    \t **/
    \tfunction scaledBalanceOf(address user) external view returns (uint256);
    \t/**
    \t * @dev Returns the scaled balance of the user and the scaled total supply.
    \t * @param user The address of the user
    \t * @return The scaled balance of the user
    \t * @return The scaled balance and the scaled total supply
    \t **/
    \tfunction getScaledUserBalanceAndSupply(address user) external view returns (uint256, uint256);
    \t/**
    \t * @dev Returns the scaled total supply of the variable debt token. Represents sum(debt/index)
    \t * @return The scaled total supply
    \t **/
    \tfunction scaledTotalSupply() external view returns (uint256);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.12;
    struct LockedBalance {
    \tuint256 amount;
    \tuint256 unlockTime;
    \tuint256 multiplier;
    \tuint256 duration;
    }
    struct EarnedBalance {
    \tuint256 amount;
    \tuint256 unlockTime;
    \tuint256 penalty;
    }
    struct Reward {
    \tuint256 periodFinish;
    \tuint256 rewardPerSecond;
    \tuint256 lastUpdateTime;
    \tuint256 rewardPerTokenStored;
    \t// tracks already-added balances to handle accrued interest in aToken rewards
    \t// for the stakingToken this value is unused and will always be 0
    \tuint256 balance;
    }
    struct Balances {
    \tuint256 total; // sum of earnings and lockings; no use when LP and RDNT is different
    \tuint256 unlocked; // RDNT token
    \tuint256 locked; // LP token or RDNT token
    \tuint256 lockedWithMultiplier; // Multiplied locked amount
    \tuint256 earned; // RDNT token
    }
    // SPDX-License-Identifier: AGPL-3.0
    pragma solidity 0.8.12;
    /**
     * @title VersionedInitializable
     *
     * @dev Helper contract to implement initializer functions. To use it, replace
     * the constructor with a function that has the `initializer` modifier.
     * 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.
     *
     * @author Aave, inspired by the OpenZeppelin Initializable contract
     */
    abstract contract VersionedInitializable {
    \t/**
    \t * @dev Indicates that the contract has been initialized.
    \t */
    \tuint256 private lastInitializedRevision = 0;
    \t/**
    \t * @dev Indicates that the contract is in the process of being initialized.
    \t */
    \tbool private initializing;
    \t/**
    \t * @dev Indicates that the contract has been initialized.
    \t */
    \tbool private initialized;
    \t/**
    \t * @dev Modifier to use in the initializer function of a contract.
    \t */
    \tmodifier initializer() {
    \t\tuint256 revision = getRevision();
    \t\tbool isTopLevelCall = !initializing;
    \t\trequire(
    \t\t\tisTopLevelCall && (revision > lastInitializedRevision || !initialized),
    \t\t\t"Contract instance has already been initialized"
    \t\t);
    \t\tif (isTopLevelCall) {
    \t\t\tinitializing = true;
    \t\t\tinitialized = true;
    \t\t\tlastInitializedRevision = revision;
    \t\t}
    \t\t_;
    \t\tif (isTopLevelCall) {
    \t\t\tinitializing = false;
    \t\t}
    \t}
    \t/**
    \t * @dev returns the revision number of the contract
    \t * Needs to be defined in the inherited class as a constant.
    \t **/
    \tfunction getRevision() internal pure virtual returns (uint256);
    \tfunction _disableInitializers() internal virtual {
    \t\trequire(!initializing, "Initializable: contract is initializing");
    \t\tif (!initialized) {
    \t\t\tlastInitializedRevision = getRevision();
    \t\t\tinitialized = true;
    \t\t}
    \t}
    \t// Reserved storage space to allow for layout changes in the future.
    \tuint256[50] private ______gap;
    }
    // SPDX-License-Identifier: AGPL-3.0
    pragma solidity 0.8.12;
    /**
     * @title Errors library
     * @author Aave
     * @notice Defines the error messages emitted by the different contracts of the Aave protocol
     * @dev Error messages prefix glossary:
     *  - VL = ValidationLogic
     *  - MATH = Math libraries
     *  - CT = Common errors between tokens (AToken, VariableDebtToken and StableDebtToken)
     *  - AT = AToken
     *  - SDT = StableDebtToken
     *  - VDT = VariableDebtToken
     *  - LP = LendingPool
     *  - LPAPR = LendingPoolAddressesProviderRegistry
     *  - LPC = LendingPoolConfiguration
     *  - RL = ReserveLogic
     *  - LPCM = LendingPoolCollateralManager
     *  - P = Pausable
     */
    library Errors {
    \t//common errors
    \tstring public constant CALLER_NOT_POOL_ADMIN = "33"; // 'The caller must be the pool admin'
    \tstring public constant BORROW_ALLOWANCE_NOT_ENOUGH = "59"; // User borrows on behalf, but allowance are too small
    \t//contract specific errors
    \tstring public constant VL_INVALID_AMOUNT = "1"; // 'Amount must be greater than 0'
    \tstring public constant VL_NO_ACTIVE_RESERVE = "2"; // 'Action requires an active reserve'
    \tstring public constant VL_RESERVE_FROZEN = "3"; // 'Action cannot be performed because the reserve is frozen'
    \tstring public constant VL_CURRENT_AVAILABLE_LIQUIDITY_NOT_ENOUGH = "4"; // 'The current liquidity is not enough'
    \tstring public constant VL_NOT_ENOUGH_AVAILABLE_USER_BALANCE = "5"; // 'User cannot withdraw more than the available balance'
    \tstring public constant VL_TRANSFER_NOT_ALLOWED = "6"; // 'Transfer cannot be allowed.'
    \tstring public constant VL_BORROWING_NOT_ENABLED = "7"; // 'Borrowing is not enabled'
    \tstring public constant VL_INVALID_INTEREST_RATE_MODE_SELECTED = "8"; // 'Invalid interest rate mode selected'
    \tstring public constant VL_COLLATERAL_BALANCE_IS_0 = "9"; // 'The collateral balance is 0'
    \tstring public constant VL_HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD = "10"; // 'Health factor is lesser than the liquidation threshold'
    \tstring public constant VL_COLLATERAL_CANNOT_COVER_NEW_BORROW = "11"; // 'There is not enough collateral to cover a new borrow'
    \tstring public constant VL_STABLE_BORROWING_NOT_ENABLED = "12"; // stable borrowing not enabled
    \tstring public constant VL_COLLATERAL_SAME_AS_BORROWING_CURRENCY = "13"; // collateral is (mostly) the same currency that is being borrowed
    \tstring public constant VL_AMOUNT_BIGGER_THAN_MAX_LOAN_SIZE_STABLE = "14"; // 'The requested amount is greater than the max loan size in stable rate mode
    \tstring public constant VL_NO_DEBT_OF_SELECTED_TYPE = "15"; // 'for repayment of stable debt, the user needs to have stable debt, otherwise, he needs to have variable debt'
    \tstring public constant VL_NO_EXPLICIT_AMOUNT_TO_REPAY_ON_BEHALF = "16"; // 'To repay on behalf of an user an explicit amount to repay is needed'
    \tstring public constant VL_NO_STABLE_RATE_LOAN_IN_RESERVE = "17"; // 'User does not have a stable rate loan in progress on this reserve'
    \tstring public constant VL_NO_VARIABLE_RATE_LOAN_IN_RESERVE = "18"; // 'User does not have a variable rate loan in progress on this reserve'
    \tstring public constant VL_UNDERLYING_BALANCE_NOT_GREATER_THAN_0 = "19"; // 'The underlying balance needs to be greater than 0'
    \tstring public constant VL_DEPOSIT_ALREADY_IN_USE = "20"; // 'User deposit is already being used as collateral'
    \tstring public constant LP_NOT_ENOUGH_STABLE_BORROW_BALANCE = "21"; // 'User does not have any stable rate loan for this reserve'
    \tstring public constant LP_INTEREST_RATE_REBALANCE_CONDITIONS_NOT_MET = "22"; // 'Interest rate rebalance conditions were not met'
    \tstring public constant LP_LIQUIDATION_CALL_FAILED = "23"; // 'Liquidation call failed'
    \tstring public constant LP_NOT_ENOUGH_LIQUIDITY_TO_BORROW = "24"; // 'There is not enough liquidity available to borrow'
    \tstring public constant LP_REQUESTED_AMOUNT_TOO_SMALL = "25"; // 'The requested amount is too small for a FlashLoan.'
    \tstring public constant LP_INCONSISTENT_PROTOCOL_ACTUAL_BALANCE = "26"; // 'The actual balance of the protocol is inconsistent'
    \tstring public constant LP_CALLER_NOT_LENDING_POOL_CONFIGURATOR = "27"; // 'The caller of the function is not the lending pool configurator'
    \tstring public constant LP_INCONSISTENT_FLASHLOAN_PARAMS = "28";
    \tstring public constant CT_CALLER_MUST_BE_LENDING_POOL = "29"; // 'The caller of this function must be a lending pool'
    \tstring public constant CT_CANNOT_GIVE_ALLOWANCE_TO_HIMSELF = "30"; // 'User cannot give allowance to himself'
    \tstring public constant CT_TRANSFER_AMOUNT_NOT_GT_0 = "31"; // 'Transferred amount needs to be greater than zero'
    \tstring public constant RL_RESERVE_ALREADY_INITIALIZED = "32"; // 'Reserve has already been initialized'
    \tstring public constant LPC_RESERVE_LIQUIDITY_NOT_0 = "34"; // 'The liquidity of the reserve needs to be 0'
    \tstring public constant LPC_INVALID_ATOKEN_POOL_ADDRESS = "35"; // 'The liquidity of the reserve needs to be 0'
    \tstring public constant LPC_INVALID_STABLE_DEBT_TOKEN_POOL_ADDRESS = "36"; // 'The liquidity of the reserve needs to be 0'
    \tstring public constant LPC_INVALID_VARIABLE_DEBT_TOKEN_POOL_ADDRESS = "37"; // 'The liquidity of the reserve needs to be 0'
    \tstring public constant LPC_INVALID_STABLE_DEBT_TOKEN_UNDERLYING_ADDRESS = "38"; // 'The liquidity of the reserve needs to be 0'
    \tstring public constant LPC_INVALID_VARIABLE_DEBT_TOKEN_UNDERLYING_ADDRESS = "39"; // 'The liquidity of the reserve needs to be 0'
    \tstring public constant LPC_INVALID_ADDRESSES_PROVIDER_ID = "40"; // 'The liquidity of the reserve needs to be 0'
    \tstring public constant LPC_INVALID_CONFIGURATION = "75"; // 'Invalid risk parameters for the reserve'
    \tstring public constant LPC_CALLER_NOT_EMERGENCY_ADMIN = "76"; // 'The caller must be the emergency admin'
    \tstring public constant LPAPR_PROVIDER_NOT_REGISTERED = "41"; // 'Provider is not registered'
    \tstring public constant LPCM_HEALTH_FACTOR_NOT_BELOW_THRESHOLD = "42"; // 'Health factor is not below the threshold'
    \tstring public constant LPCM_COLLATERAL_CANNOT_BE_LIQUIDATED = "43"; // 'The collateral chosen cannot be liquidated'
    \tstring public constant LPCM_SPECIFIED_CURRENCY_NOT_BORROWED_BY_USER = "44"; // 'User did not borrow the specified currency'
    \tstring public constant LPCM_NOT_ENOUGH_LIQUIDITY_TO_LIQUIDATE = "45"; // "There isn't enough liquidity available to liquidate"
    \tstring public constant LPCM_NO_ERRORS = "46"; // 'No errors'
    \tstring public constant LP_INVALID_FLASHLOAN_MODE = "47"; //Invalid flashloan mode selected
    \tstring public constant MATH_MULTIPLICATION_OVERFLOW = "48";
    \tstring public constant MATH_ADDITION_OVERFLOW = "49";
    \tstring public constant MATH_DIVISION_BY_ZERO = "50";
    \tstring public constant RL_LIQUIDITY_INDEX_OVERFLOW = "51"; //  Liquidity index overflows uint128
    \tstring public constant RL_VARIABLE_BORROW_INDEX_OVERFLOW = "52"; //  Variable borrow index overflows uint128
    \tstring public constant RL_LIQUIDITY_RATE_OVERFLOW = "53"; //  Liquidity rate overflows uint128
    \tstring public constant RL_VARIABLE_BORROW_RATE_OVERFLOW = "54"; //  Variable borrow rate overflows uint128
    \tstring public constant RL_STABLE_BORROW_RATE_OVERFLOW = "55"; //  Stable borrow rate overflows uint128
    \tstring public constant CT_INVALID_MINT_AMOUNT = "56"; //invalid amount to mint
    \tstring public constant LP_FAILED_REPAY_WITH_COLLATERAL = "57";
    \tstring public constant CT_INVALID_BURN_AMOUNT = "58"; //invalid amount to burn
    \tstring public constant LP_FAILED_COLLATERAL_SWAP = "60";
    \tstring public constant LP_INVALID_EQUAL_ASSETS_TO_SWAP = "61";
    \tstring public constant LP_REENTRANCY_NOT_ALLOWED = "62";
    \tstring public constant LP_CALLER_MUST_BE_AN_ATOKEN = "63";
    \tstring public constant LP_IS_PAUSED = "64"; // 'Pool is paused'
    \tstring public constant LP_NO_MORE_RESERVES_ALLOWED = "65";
    \tstring public constant LP_INVALID_FLASH_LOAN_EXECUTOR_RETURN = "66";
    \tstring public constant RC_INVALID_LTV = "67";
    \tstring public constant RC_INVALID_LIQ_THRESHOLD = "68";
    \tstring public constant RC_INVALID_LIQ_BONUS = "69";
    \tstring public constant RC_INVALID_DECIMALS = "70";
    \tstring public constant RC_INVALID_RESERVE_FACTOR = "71";
    \tstring public constant LPAPR_INVALID_ADDRESSES_PROVIDER_ID = "72";
    \tstring public constant VL_INCONSISTENT_FLASHLOAN_PARAMS = "73";
    \tstring public constant LP_INCONSISTENT_PARAMS_LENGTH = "74";
    \tstring public constant UL_INVALID_INDEX = "77";
    \tstring public constant LP_NOT_CONTRACT = "78";
    \tstring public constant SDT_STABLE_DEBT_OVERFLOW = "79";
    \tstring public constant SDT_BURN_EXCEEDS_BALANCE = "80";
    \t/**
    \t * @dev Custom Radiant codes added +200 to avoid conflicts with the AaveV2/V3 ones
    \t * @custom:borrow-and-supply-caps
    \t */
    \tstring public constant INVALID_BORROW_CAP = "201"; // Invalid borrow cap value
    \tstring public constant INVALID_SUPPLY_CAP = "202"; // Invalid supply cap value
    \tstring public constant BORROW_CAP_EXCEEDED = "203"; // Borrow cap is exceeded
    \tstring public constant SUPPLY_CAP_EXCEEDED = "204"; // Supply cap is exceeded
    \tenum CollateralManagerErrors {
    \t\tNO_ERROR,
    \t\tNO_COLLATERAL_AVAILABLE,
    \t\tCOLLATERAL_CANNOT_BE_LIQUIDATED,
    \t\tCURRRENCY_NOT_BORROWED,
    \t\tHEALTH_FACTOR_ABOVE_THRESHOLD,
    \t\tNOT_ENOUGH_LIQUIDITY,
    \t\tNO_ACTIVE_RESERVE,
    \t\tHEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD,
    \t\tINVALID_EQUAL_ASSETS_TO_SWAP,
    \t\tFROZEN_RESERVE
    \t}
    }
    // SPDX-License-Identifier: AGPL-3.0
    pragma solidity 0.8.12;
    import {Errors} from "../helpers/Errors.sol";
    /**
     * @title WadRayMath library
     * @author Aave
     * @dev Provides mul and div function for wads (decimal numbers with 18 digits precision) and rays (decimals with 27 digits)
     **/
    library WadRayMath {
    \tuint256 internal constant WAD = 1e18;
    \tuint256 internal constant halfWAD = WAD / 2;
    \tuint256 internal constant RAY = 1e27;
    \tuint256 internal constant halfRAY = RAY / 2;
    \tuint256 internal constant WAD_RAY_RATIO = 1e9;
    \t/**
    \t * @return One ray, 1e27
    \t **/
    \tfunction ray() internal pure returns (uint256) {
    \t\treturn RAY;
    \t}
    \t/**
    \t * @return One wad, 1e18
    \t **/
    \tfunction wad() internal pure returns (uint256) {
    \t\treturn WAD;
    \t}
    \t/**
    \t * @return Half ray, 1e27/2
    \t **/
    \tfunction halfRay() internal pure returns (uint256) {
    \t\treturn halfRAY;
    \t}
    \t/**
    \t * @return Half ray, 1e18/2
    \t **/
    \tfunction halfWad() internal pure returns (uint256) {
    \t\treturn halfWAD;
    \t}
    \t/**
    \t * @dev Multiplies two wad, rounding half up to the nearest wad
    \t * @param a Wad
    \t * @param b Wad
    \t * @return The result of a*b, in wad
    \t **/
    \tfunction wadMul(uint256 a, uint256 b) internal pure returns (uint256) {
    \t\tif (a == 0 || b == 0) {
    \t\t\treturn 0;
    \t\t}
    \t\trequire(a <= (type(uint256).max - halfWAD) / b, Errors.MATH_MULTIPLICATION_OVERFLOW);
    \t\treturn (a * b + halfWAD) / WAD;
    \t}
    \t/**
    \t * @dev Divides two wad, rounding half up to the nearest wad
    \t * @param a Wad
    \t * @param b Wad
    \t * @return The result of a/b, in wad
    \t **/
    \tfunction wadDiv(uint256 a, uint256 b) internal pure returns (uint256) {
    \t\trequire(b != 0, Errors.MATH_DIVISION_BY_ZERO);
    \t\tuint256 halfB = b / 2;
    \t\trequire(a <= (type(uint256).max - halfB) / WAD, Errors.MATH_MULTIPLICATION_OVERFLOW);
    \t\treturn (a * WAD + halfB) / b;
    \t}
    \t/**
    \t * @dev Multiplies two ray, rounding half up to the nearest ray
    \t * @param a Ray
    \t * @param b Ray
    \t * @return The result of a*b, in ray
    \t **/
    \tfunction rayMul(uint256 a, uint256 b) internal pure returns (uint256) {
    \t\tif (a == 0 || b == 0) {
    \t\t\treturn 0;
    \t\t}
    \t\trequire(a <= (type(uint256).max - halfRAY) / b, Errors.MATH_MULTIPLICATION_OVERFLOW);
    \t\treturn (a * b + halfRAY) / RAY;
    \t}
    \t/**
    \t * @dev Divides two ray, rounding half up to the nearest ray
    \t * @param a Ray
    \t * @param b Ray
    \t * @return The result of a/b, in ray
    \t **/
    \tfunction rayDiv(uint256 a, uint256 b) internal pure returns (uint256) {
    \t\trequire(b != 0, Errors.MATH_DIVISION_BY_ZERO);
    \t\tuint256 halfB = b / 2;
    \t\trequire(a <= (type(uint256).max - halfB) / RAY, Errors.MATH_MULTIPLICATION_OVERFLOW);
    \t\treturn (a * RAY + halfB) / b;
    \t}
    \t/**
    \t * @dev Casts ray down to wad
    \t * @param a Ray
    \t * @return a casted to wad, rounded half up to the nearest wad
    \t **/
    \tfunction rayToWad(uint256 a) internal pure returns (uint256) {
    \t\tuint256 halfRatio = WAD_RAY_RATIO / 2;
    \t\tuint256 result = halfRatio + a;
    \t\trequire(result >= halfRatio, Errors.MATH_ADDITION_OVERFLOW);
    \t\treturn result / WAD_RAY_RATIO;
    \t}
    \t/**
    \t * @dev Converts wad up to ray
    \t * @param a Wad
    \t * @return a converted in ray
    \t **/
    \tfunction wadToRay(uint256 a) internal pure returns (uint256) {
    \t\tuint256 result = a * WAD_RAY_RATIO;
    \t\trequire(result / WAD_RAY_RATIO == a, Errors.MATH_MULTIPLICATION_OVERFLOW);
    \t\treturn result;
    \t}
    }
    // SPDX-License-Identifier: AGPL-3.0
    pragma solidity 0.8.12;
    library DataTypes {
    \t// refer to the whitepaper, section 1.1 basic concepts for a formal description of these properties.
    \tstruct ReserveData {
    \t\t//stores the reserve configuration
    \t\tReserveConfigurationMap configuration;
    \t\t//the liquidity index. Expressed in ray
    \t\tuint128 liquidityIndex;
    \t\t//variable borrow index. Expressed in ray
    \t\tuint128 variableBorrowIndex;
    \t\t//the current supply rate. Expressed in ray
    \t\tuint128 currentLiquidityRate;
    \t\t//the current variable borrow rate. Expressed in ray
    \t\tuint128 currentVariableBorrowRate;
    \t\t//the current stable borrow rate. Expressed in ray
    \t\tuint128 currentStableBorrowRate;
    \t\tuint40 lastUpdateTimestamp;
    \t\t//tokens addresses
    \t\taddress aTokenAddress;
    \t\taddress stableDebtTokenAddress;
    \t\taddress variableDebtTokenAddress;
    \t\t//address of the interest rate strategy
    \t\taddress interestRateStrategyAddress;
    \t\t//the id of the reserve. Represents the position in the list of the active reserves
    \t\tuint8 id;
    \t}
    \tstruct ReserveConfigurationMap {
    \t\t//bit 0-15: LTV
    \t\t//bit 16-31: Liq. threshold
    \t\t//bit 32-47: Liq. bonus
    \t\t//bit 48-55: Decimals
    \t\t//bit 56: Reserve is active
    \t\t//bit 57: reserve is frozen
    \t\t//bit 58: borrowing is enabled
    \t\t//bit 59: stable rate borrowing enabled
    \t\t//bit 60-63: reserved
    \t\t//bit 64-79: reserve factor
    \t\t///@custom:borrow-and-supply-caps
    \t\t//bit 80-115 borrow cap in whole tokens, borrowCap == 0 => no cap
    \t\t//bit 116-151 supply cap in whole tokens, supplyCap == 0 => no cap
    \t\tuint256 data;
    \t}
    \tstruct UserConfigurationMap {
    \t\tuint256 data;
    \t}
    \tenum InterestRateMode {
    \t\tNONE,
    \t\tSTABLE,
    \t\tVARIABLE
    \t}
    }
    // SPDX-License-Identifier: AGPL-3.0
    pragma solidity 0.8.12;
    import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
    import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
    import {ILendingPool} from "../../interfaces/ILendingPool.sol";
    import {IAToken} from "../../interfaces/IAToken.sol";
    import {WadRayMath} from "../libraries/math/WadRayMath.sol";
    import {Errors} from "../libraries/helpers/Errors.sol";
    import {VersionedInitializable} from "../libraries/aave-upgradeability/VersionedInitializable.sol";
    import {IncentivizedERC20} from "./IncentivizedERC20.sol";
    import {IAaveIncentivesController} from "../../interfaces/IAaveIncentivesController.sol";
    import "@openzeppelin/contracts/utils/math/SafeMath.sol";
    import {IMiddleFeeDistribution} from "../../interfaces/IMiddleFeeDistribution.sol";
    import {ILendingPoolAddressesProvider} from "../../interfaces/ILendingPoolAddressesProvider.sol";
    /**
     * @title Aave ERC20 AToken
     * @dev Implementation of the interest bearing token for the Aave protocol
     * @author Aave
     */
    contract AToken is VersionedInitializable, IncentivizedERC20("ATOKEN_IMPL", "ATOKEN_IMPL", 0), IAToken {
    \tusing WadRayMath for uint256;
    \tusing SafeERC20 for IERC20;
    \tusing SafeMath for uint256;
    \tbytes public constant EIP712_REVISION = bytes("1");
    \tbytes32 internal constant EIP712_DOMAIN =
    \t\tkeccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
    \tbytes32 public constant PERMIT_TYPEHASH =
    \t\tkeccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
    \tuint256 public constant ATOKEN_REVISION = 0x2;
    \t/// @dev owner => next valid nonce to submit with permit()
    \tmapping(address => uint256) public _nonces;
    \tbytes32 public DOMAIN_SEPARATOR;
    \taddress internal _treasury;
    \tIAaveIncentivesController internal _incentivesController;
    \terror AddressZero();
    \tevent TreasuryAddressUpdated(address indexed treasury);
    \tmodifier onlyLendingPool() {
    \t\trequire(_msgSender() == address(_pool), Errors.CT_CALLER_MUST_BE_LENDING_POOL);
    \t\t_;
    \t}
    \tmodifier onlyPoolAdmin() {
    \t\tILendingPoolAddressesProvider lpAddressProvider = ILendingPoolAddressesProvider(_pool.getAddressesProvider());
    \t\trequire(lpAddressProvider.getPoolAdmin() == msg.sender, Errors.LP_CALLER_NOT_LENDING_POOL_CONFIGURATOR);
    \t\t_;
    \t}
    \tfunction getRevision() internal pure virtual override returns (uint256) {
    \t\treturn ATOKEN_REVISION;
    \t}
    \tconstructor() {
    \t\t_disableInitializers();
    \t}
    \t/**
    \t * @dev Initializes the aToken
    \t * @param pool The address of the lending pool where this aToken will be used
    \t * @param treasury The address of the Aave treasury, receiving the fees on this aToken
    \t * @param underlyingAsset The address of the underlying asset of this aToken (E.g. WETH for aWETH)
    \t * @param incentivesController The smart contract managing potential incentives distribution
    \t * @param aTokenDecimals The decimals of the aToken, same as the underlying asset's
    \t * @param aTokenName The name of the aToken
    \t * @param aTokenSymbol The symbol of the aToken
    \t */
    \tfunction initialize(
    \t\tILendingPool pool,
    \t\taddress treasury,
    \t\taddress underlyingAsset,
    \t\tIAaveIncentivesController incentivesController,
    \t\tuint8 aTokenDecimals,
    \t\tstring calldata aTokenName,
    \t\tstring calldata aTokenSymbol,
    \t\tbytes calldata params
    \t) external override initializer {
    \t\tuint256 chainId;
    \t\t//solium-disable-next-line
    \t\tassembly {
    \t\t\tchainId := chainid()
    \t\t}
    \t\tDOMAIN_SEPARATOR = keccak256(
    \t\t\tabi.encode(EIP712_DOMAIN, keccak256(bytes(aTokenName)), keccak256(EIP712_REVISION), chainId, address(this))
    \t\t);
    \t\t_setName(aTokenName);
    \t\t_setSymbol(aTokenSymbol);
    \t\t_setDecimals(aTokenDecimals);
    \t\t_pool = pool;
    \t\t_treasury = treasury;
    \t\t_underlyingAsset = underlyingAsset;
    \t\t_incentivesController = incentivesController;
    \t\temit Initialized(
    \t\t\tunderlyingAsset,
    \t\t\taddress(pool),
    \t\t\ttreasury,
    \t\t\taddress(incentivesController),
    \t\t\taTokenDecimals,
    \t\t\taTokenName,
    \t\t\taTokenSymbol,
    \t\t\tparams
    \t\t);
    \t}
    \t/**
    \t * @dev Burns aTokens from `user` and sends the equivalent amount of underlying to `receiverOfUnderlying`
    \t * - Only callable by the LendingPool, as extra state updates there need to be managed
    \t * @param user The owner of the aTokens, getting them burned
    \t * @param receiverOfUnderlying The address that will receive the underlying
    \t * @param amount The amount being burned
    \t * @param index The new liquidity index of the reserve
    \t **/
    \tfunction burn(
    \t\taddress user,
    \t\taddress receiverOfUnderlying,
    \t\tuint256 amount,
    \t\tuint256 index
    \t) external override onlyLendingPool {
    \t\tuint256 amountScaled = amount.rayDiv(index);
    \t\trequire(amountScaled != 0, Errors.CT_INVALID_BURN_AMOUNT);
    \t\t_burn(user, amountScaled);
    \t\tIERC20(_underlyingAsset).safeTransfer(receiverOfUnderlying, amount);
    \t\temit Transfer(user, address(0), amount);
    \t\temit Burn(user, receiverOfUnderlying, amount, index);
    \t}
    \t/**
    \t * @dev Mints `amount` aTokens to `user`
    \t * - Only callable by the LendingPool, as extra state updates there need to be managed
    \t * @param user The address receiving the minted tokens
    \t * @param amount The amount of tokens getting minted
    \t * @param index The new liquidity index of the reserve
    \t * @return `true` if the the previous balance of the user was 0
    \t */
    \tfunction mint(address user, uint256 amount, uint256 index) external override onlyLendingPool returns (bool) {
    \t\tuint256 previousBalance = super.balanceOf(user);
    \t\tuint256 amountScaled = amount.rayDiv(index);
    \t\trequire(amountScaled != 0, Errors.CT_INVALID_MINT_AMOUNT);
    \t\t_mint(user, amountScaled);
    \t\temit Transfer(address(0), user, amount);
    \t\temit Mint(user, amount, index);
    \t\treturn previousBalance == 0;
    \t}
    \t/**
    \t * @dev Mints aTokens to the reserve treasury
    \t * - Only callable by the LendingPool
    \t * @param amount The amount of tokens getting minted
    \t * @param index The new liquidity index of the reserve
    \t */
    \tfunction mintToTreasury(uint256 amount, uint256 index) external override onlyLendingPool {
    \t\tif (amount == 0) {
    \t\t\treturn;
    \t\t}
    \t\taddress treasury = _treasury;
    \t\t// Compared to the normal mint, we don't check for rounding errors.
    \t\t// The amount to mint can easily be very small since it is a fraction of the interest ccrued.
    \t\t// In that case, the treasury will experience a (very small) loss, but it
    \t\t// wont cause potentially valid transactions to fail.
    \t\t_mint(treasury, amount.rayDiv(index));
    \t\temit Transfer(address(0), treasury, amount);
    \t\temit Mint(treasury, amount, index);
    \t}
    \t/**
    \t * @dev Transfers aTokens in the event of a borrow being liquidated, in case the liquidators reclaims the aToken
    \t * - Only callable by the LendingPool
    \t * @param from The address getting liquidated, current owner of the aTokens
    \t * @param to The recipient
    \t * @param value The amount of tokens getting transferred
    \t **/
    \tfunction transferOnLiquidation(address from, address to, uint256 value) external override onlyLendingPool {
    \t\t// Being a normal transfer, the Transfer() and BalanceTransfer() are emitted
    \t\t// so no need to emit a specific event here
    \t\t_transfer(from, to, value, false);
    \t\temit Transfer(from, to, value);
    \t}
    \t/**
    \t * @dev Calculates the balance of the user: principal balance + interest generated by the principal
    \t * @param user The user whose balance is calculated
    \t * @return The balance of the user
    \t **/
    \tfunction balanceOf(address user) public view override(IncentivizedERC20, IERC20) returns (uint256) {
    \t\treturn super.balanceOf(user).rayMul(_pool.getReserveNormalizedIncome(_underlyingAsset));
    \t}
    \t/**
    \t * @dev Returns the scaled balance of the user. The scaled balance is the sum of all the
    \t * updated stored balance divided by the reserve's liquidity index at the moment of the update
    \t * @param user The user whose balance is calculated
    \t * @return The scaled balance of the user
    \t **/
    \tfunction scaledBalanceOf(address user) external view override returns (uint256) {
    \t\treturn super.balanceOf(user);
    \t}
    \t/**
    \t * @dev Returns the scaled balance of the user and the scaled total supply.
    \t * @param user The address of the user
    \t * @return The scaled balance of the user
    \t * @return The scaled balance and the scaled total supply
    \t **/
    \tfunction getScaledUserBalanceAndSupply(address user) external view override returns (uint256, uint256) {
    \t\treturn (super.balanceOf(user), super.totalSupply());
    \t}
    \t/**
    \t * @dev calculates the total supply of the specific aToken
    \t * since the balance of every single user increases over time, the total supply
    \t * does that too.
    \t * @return the current total supply
    \t **/
    \tfunction totalSupply() public view override(IncentivizedERC20, IERC20) returns (uint256) {
    \t\tuint256 currentSupplyScaled = super.totalSupply();
    \t\tif (currentSupplyScaled == 0) {
    \t\t\treturn 0;
    \t\t}
    \t\treturn currentSupplyScaled.rayMul(_pool.getReserveNormalizedIncome(_underlyingAsset));
    \t}
    \t/**
    \t * @dev Returns the scaled total supply of the variable debt token. Represents sum(debt/index)
    \t * @return the scaled total supply
    \t **/
    \tfunction scaledTotalSupply() public view virtual override returns (uint256) {
    \t\treturn super.totalSupply();
    \t}
    \t/**
    \t * @dev Returns the address of the Aave treasury, receiving the fees on this aToken
    \t **/
    \tfunction RESERVE_TREASURY_ADDRESS() public view returns (address) {
    \t\treturn _treasury;
    \t}
    \t/**
    \t * @dev Returns the address of the underlying asset of this aToken (E.g. WETH for aWETH)
    \t **/
    \tfunction UNDERLYING_ASSET_ADDRESS() public view override returns (address) {
    \t\treturn _underlyingAsset;
    \t}
    \t/**
    \t * @dev Returns the address of the lending pool where this aToken is used
    \t **/
    \tfunction POOL() public view returns (ILendingPool) {
    \t\treturn _pool;
    \t}
    \t/**
    \t * @dev For internal usage in the logic of the parent contract IncentivizedERC20
    \t **/
    \tfunction _getIncentivesController() internal view override returns (IAaveIncentivesController) {
    \t\treturn _incentivesController;
    \t}
    \t/**
    \t * @dev Returns the address of the incentives controller contract
    \t **/
    \tfunction getIncentivesController() external view override returns (IAaveIncentivesController) {
    \t\treturn _getIncentivesController();
    \t}
    \t/**
    \t * @dev Updates the treasury address
    \t * @param treasury The new treasury address
    \t */
    \tfunction setTreasuryAddress(address treasury) external onlyPoolAdmin {
    \t\tif (treasury == address(0)) revert AddressZero();
    \t\t_treasury = treasury;
    \t\temit TreasuryAddressUpdated(treasury);
    \t}
    \t/**
    \t * @dev Transfers the underlying asset to `target`. Used by the LendingPool to transfer
    \t * assets in borrow(), withdraw() and flashLoan()
    \t * @param target The recipient of the aTokens
    \t * @param amount The amount getting transferred
    \t * @return The amount transferred
    \t **/
    \tfunction transferUnderlyingTo(address target, uint256 amount) external override onlyLendingPool returns (uint256) {
    \t\tIERC20(_underlyingAsset).safeTransfer(target, amount);
    \t\treturn amount;
    \t}
    \t/**
    \t * @dev Invoked to execute actions on the aToken side after a repayment.
    \t * @param user The user executing the repayment
    \t * @param amount The amount getting repaid
    \t **/
    \tfunction handleRepayment(address user, uint256 amount) external override onlyLendingPool {}
    \t/**
    \t * @dev implements the permit function as for
    \t * https://github.com/ethereum/EIPs/blob/8a34d644aacf0f9f8f00815307fd7dd5da07655f/EIPS/eip-2612.md
    \t * @param owner The owner of the funds
    \t * @param spender The spender
    \t * @param value The amount
    \t * @param deadline The deadline timestamp, type(uint256).max for max deadline
    \t * @param v Signature param
    \t * @param s Signature param
    \t * @param r Signature param
    \t */
    \tfunction permit(
    \t\taddress owner,
    \t\taddress spender,
    \t\tuint256 value,
    \t\tuint256 deadline,
    \t\tuint8 v,
    \t\tbytes32 r,
    \t\tbytes32 s
    \t) external {
    \t\trequire(owner != address(0), "INVALID_OWNER");
    \t\t//solium-disable-next-line
    \t\trequire(block.timestamp <= deadline, "INVALID_EXPIRATION");
    \t\tuint256 currentValidNonce = _nonces[owner];
    \t\tbytes32 digest = keccak256(
    \t\t\tabi.encodePacked(
    \t\t\t\t"\\x19\\x01",
    \t\t\t\tDOMAIN_SEPARATOR,
    \t\t\t\tkeccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, currentValidNonce, deadline))
    \t\t\t)
    \t\t);
    \t\trequire(owner == ecrecover(digest, v, r, s), "INVALID_SIGNATURE");
    \t\t_nonces[owner] = currentValidNonce.add(1);
    \t\t_approve(owner, spender, value);
    \t}
    \t/**
    \t * @dev Transfers the aTokens between two users. Validates the transfer
    \t * (ie checks for valid HF after the transfer) if required
    \t * @param from The source address
    \t * @param to The destination address
    \t * @param amount The amount getting transferred
    \t * @param validate `true` if the transfer needs to be validated
    \t **/
    \tfunction _transfer(address from, address to, uint256 amount, bool validate) internal {
    \t\taddress underlyingAsset = _underlyingAsset;
    \t\tILendingPool pool = _pool;
    \t\tuint256 index = pool.getReserveNormalizedIncome(underlyingAsset);
    \t\tuint256 fromBalanceBefore = super.balanceOf(from).rayMul(index);
    \t\tuint256 toBalanceBefore = super.balanceOf(to).rayMul(index);
    \t\tsuper._transfer(from, to, amount.rayDiv(index));
    \t\tif (validate) {
    \t\t\tpool.finalizeTransfer(underlyingAsset, from, to, amount, fromBalanceBefore, toBalanceBefore);
    \t\t}
    \t\temit BalanceTransfer(from, to, amount, index);
    \t}
    \t/**
    \t * @dev Overrides the parent _transfer to force validated transfer() and transferFrom()
    \t * @param from The source address
    \t * @param to The destination address
    \t * @param amount The amount getting transferred
    \t **/
    \tfunction _transfer(address from, address to, uint256 amount) internal override {
    \t\t_transfer(from, to, amount, true);
    \t}
    }
    // SPDX-License-Identifier: AGPL-3.0
    pragma solidity 0.8.12;
    import {Context} from "../../dependencies/openzeppelin/contracts/Context.sol";
    import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
    import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
    import "@openzeppelin/contracts/utils/math/SafeMath.sol";
    import {IAaveIncentivesController} from "../../interfaces/IAaveIncentivesController.sol";
    import {ILendingPoolAddressesProvider} from "../../interfaces/ILendingPoolAddressesProvider.sol";
    import {IPriceOracle} from "../../interfaces/IPriceOracle.sol";
    import {ILendingPool} from "../../interfaces/ILendingPool.sol";
    /**
     * @title ERC20
     * @notice Basic ERC20 implementation
     * @author Aave, inspired by the Openzeppelin ERC20 implementation
     **/
    abstract contract IncentivizedERC20 is Context, IERC20, IERC20Metadata {
    \tusing SafeMath for uint256;
    \tmapping(address => uint256) internal _balances;
    \tmapping(address => mapping(address => uint256)) private _allowances;
    \tuint256 internal _totalSupply;
    \tstring private _name;
    \tstring private _symbol;
    \tuint8 private _decimals;
    \tILendingPool internal _pool;
    \taddress internal _underlyingAsset;
    \tconstructor(string memory name_, string memory symbol_, uint8 decimals_) {
    \t\t_name = name_;
    \t\t_symbol = symbol_;
    \t\t_decimals = decimals_;
    \t}
    \t/**
    \t * @return The name of the token
    \t **/
    \tfunction name() public view returns (string memory) {
    \t\treturn _name;
    \t}
    \t/**
    \t * @return The symbol of the token
    \t **/
    \tfunction symbol() public view returns (string memory) {
    \t\treturn _symbol;
    \t}
    \t/**
    \t * @return The decimals of the token
    \t **/
    \tfunction decimals() public view returns (uint8) {
    \t\treturn _decimals;
    \t}
    \t/**
    \t * @return The total supply of the token
    \t **/
    \tfunction totalSupply() public view virtual returns (uint256) {
    \t\treturn _totalSupply;
    \t}
    \t/**
    \t * @return The balance of the token
    \t **/
    \tfunction balanceOf(address account) public view virtual returns (uint256) {
    \t\treturn _balances[account];
    \t}
    \t/**
    \t * @return Abstract function implemented by the child aToken/debtToken.
    \t * Done this way in order to not break compatibility with previous versions of aTokens/debtTokens
    \t **/
    \tfunction _getIncentivesController() internal view virtual returns (IAaveIncentivesController);
    \t/**
    \t * @dev Executes a transfer of tokens from _msgSender() to recipient
    \t * @param recipient The recipient of the tokens
    \t * @param amount The amount of tokens being transferred
    \t * @return `true` if the transfer succeeds, `false` otherwise
    \t **/
    \tfunction transfer(address recipient, uint256 amount) public virtual returns (bool) {
    \t\t_transfer(_msgSender(), recipient, amount);
    \t\temit Transfer(_msgSender(), recipient, amount);
    \t\treturn true;
    \t}
    \t/**
    \t * @dev Returns the allowance of spender on the tokens owned by owner
    \t * @param owner The owner of the tokens
    \t * @param spender The user allowed to spend the owner's tokens
    \t * @return The amount of owner's tokens spender is allowed to spend
    \t **/
    \tfunction allowance(address owner, address spender) public view virtual returns (uint256) {
    \t\treturn _allowances[owner][spender];
    \t}
    \t/**
    \t * @dev Allows `spender` to spend the tokens owned by _msgSender()
    \t * @param spender The user allowed to spend _msgSender() tokens
    \t * @return `true`
    \t **/
    \tfunction approve(address spender, uint256 amount) public virtual returns (bool) {
    \t\t_approve(_msgSender(), spender, amount);
    \t\treturn true;
    \t}
    \t/**
    \t * @dev Executes a transfer of token from sender to recipient, if _msgSender() is allowed to do so
    \t * @param sender The owner of the tokens
    \t * @param recipient The recipient of the tokens
    \t * @param amount The amount of tokens being transferred
    \t * @return `true` if the transfer succeeds, `false` otherwise
    \t **/
    \tfunction transferFrom(address sender, address recipient, uint256 amount) public virtual returns (bool) {
    \t\t_transfer(sender, recipient, amount);
    \t\t_approve(
    \t\t\tsender,
    \t\t\t_msgSender(),
    \t\t\t_allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")
    \t\t);
    \t\temit Transfer(sender, recipient, amount);
    \t\treturn true;
    \t}
    \t/**
    \t * @dev Increases the allowance of spender to spend _msgSender() tokens
    \t * @param spender The user allowed to spend on behalf of _msgSender()
    \t * @param addedValue The amount being added to the allowance
    \t * @return `true`
    \t **/
    \tfunction increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
    \t\t_approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
    \t\treturn true;
    \t}
    \t/**
    \t * @dev Decreases the allowance of spender to spend _msgSender() tokens
    \t * @param spender The user allowed to spend on behalf of _msgSender()
    \t * @param subtractedValue The amount being subtracted to the allowance
    \t * @return `true`
    \t **/
    \tfunction decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
    \t\t_approve(
    \t\t\t_msgSender(),
    \t\t\tspender,
    \t\t\t_allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")
    \t\t);
    \t\treturn true;
    \t}
    \tfunction _transfer(address sender, address recipient, uint256 amount) internal virtual {
    \t\trequire(sender != address(0), "ERC20: transfer from the zero address");
    \t\trequire(recipient != address(0), "ERC20: transfer to the zero address");
    \t\t_beforeTokenTransfer(sender, recipient, amount);
    \t\tuint256 senderBalance = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
    \t\tif (address(_getIncentivesController()) != address(0)) {
    \t\t\t// uint256 currentTotalSupply = _totalSupply;
    \t\t\t_getIncentivesController().handleActionBefore(sender);
    \t\t\tif (sender != recipient) {
    \t\t\t\t_getIncentivesController().handleActionBefore(recipient);
    \t\t\t}
    \t\t}
    \t\t_balances[sender] = senderBalance;
    \t\tuint256 recipientBalance = _balances[recipient].add(amount);
    \t\t_balances[recipient] = recipientBalance;
    \t\tif (address(_getIncentivesController()) != address(0)) {
    \t\t\tuint256 currentTotalSupply = _totalSupply;
    \t\t\t_getIncentivesController().handleActionAfter(sender, _balances[sender], currentTotalSupply);
    \t\t\tif (sender != recipient) {
    \t\t\t\t_getIncentivesController().handleActionAfter(recipient, _balances[recipient], currentTotalSupply);
    \t\t\t}
    \t\t}
    \t}
    \tfunction _mint(address account, uint256 amount) internal virtual {
    \t\trequire(account != address(0), "ERC20: mint to the zero address");
    \t\t_beforeTokenTransfer(address(0), account, amount);
    \t\tuint256 currentTotalSupply = _totalSupply.add(amount);
    \t\tuint256 accountBalance = _balances[account].add(amount);
    \t\tif (address(_getIncentivesController()) != address(0)) {
    \t\t\t_getIncentivesController().handleActionBefore(account);
    \t\t}
    \t\t_totalSupply = currentTotalSupply;
    \t\t_balances[account] = accountBalance;
    \t\tif (address(_getIncentivesController()) != address(0)) {
    \t\t\t_getIncentivesController().handleActionAfter(account, accountBalance, currentTotalSupply);
    \t\t}
    \t}
    \tfunction _burn(address account, uint256 amount) internal virtual {
    \t\trequire(account != address(0), "ERC20: burn from the zero address");
    \t\t_beforeTokenTransfer(account, address(0), amount);
    \t\tuint256 currentTotalSupply = _totalSupply.sub(amount);
    \t\tuint256 accountBalance = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
    \t\tif (address(_getIncentivesController()) != address(0)) {
    \t\t\t_getIncentivesController().handleActionBefore(account);
    \t\t}
    \t\t_totalSupply = currentTotalSupply;
    \t\t_balances[account] = accountBalance;
    \t\tif (address(_getIncentivesController()) != address(0)) {
    \t\t\t_getIncentivesController().handleActionAfter(account, accountBalance, currentTotalSupply);
    \t\t}
    \t}
    \tfunction _approve(address owner, address spender, uint256 amount) internal virtual {
    \t\trequire(owner != address(0), "ERC20: approve from the zero address");
    \t\trequire(spender != address(0), "ERC20: approve to the zero address");
    \t\t_allowances[owner][spender] = amount;
    \t\temit Approval(owner, spender, amount);
    \t}
    \tfunction _setName(string memory newName) internal {
    \t\t_name = newName;
    \t}
    \tfunction _setSymbol(string memory newSymbol) internal {
    \t\t_symbol = newSymbol;
    \t}
    \tfunction _setDecimals(uint8 newDecimals) internal {
    \t\t_decimals = newDecimals;
    \t}
    \tfunction _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}
    \tfunction getAssetPrice() external view returns (uint256) {
    \t\tILendingPoolAddressesProvider provider = _pool.getAddressesProvider();
    \t\taddress oracle = provider.getPriceOracle();
    \t\treturn IPriceOracle(oracle).getAssetPrice(_underlyingAsset);
    \t}
    }