ETH Price: $2,072.99 (+4.10%)
Gas: 0.13 Gwei

Transaction Decoder

Block:
24317970 at Jan-26-2026 09:00:23 AM +UTC
Transaction Fee:
0.00000441609914219 ETH $0.009155
Gas Used:
78,695 Gas / 0.056116642 Gwei

Account State Difference:

  Address   Before After State Difference Code
(Titan Builder)
12.100791884015464816 Eth12.100792284655644566 Eth0.00000040064017975
0xC75fE7Fd...644d1F7d8
0.221874595193429797 Eth
Nonce: 31511
0.221870179094287607 Eth
Nonce: 31512
0.00000441609914219

Execution Trace

InitializableImmutableAdminUpgradeabilityProxy.ab9c4b5d( )
  • 0x8147b99df7672a21809c9093e6f6ce1a60f119bd.ab9c4b5d( )
    • PoolAddressesProvider.STATICCALL( )
    • ACLManager.isFlashBorrower( borrower=0xC75fE7Fd2aa834EfBC522a71Ae1BDC5644d1F7d8 ) => ( False )
    • 0xe66adcf153d0bd67a74e5d23e23f90b4011024ec.2e7263ea( )
      • InitializableImmutableAdminUpgradeabilityProxy.STATICCALL( )
        • 0xadc45df3cf1584624c97338bef33363bf5b97ada.DELEGATECALL( )
          • InitializableImmutableAdminUpgradeabilityProxy.d15e0053( )
            • 0x8147b99df7672a21809c9093e6f6ce1a60f119bd.d15e0053( )
              File 1 of 4: InitializableImmutableAdminUpgradeabilityProxy
              // SPDX-License-Identifier: AGPL-3.0
              pragma solidity 0.8.10;
              /**
               * @dev Collection of functions related to the address type
               */
              library Address {
                /**
                 * @dev Returns true if `account` is a contract.
                 *
                 * [IMPORTANT]
                 * ====
                 * It is unsafe to assume that an address for which this function returns
                 * false is an externally-owned account (EOA) and not a contract.
                 *
                 * Among others, `isContract` will return false for the following
                 * types of addresses:
                 *
                 *  - an externally-owned account
                 *  - a contract in construction
                 *  - an address where a contract will be created
                 *  - an address where a contract lived, but was destroyed
                 * ====
                 */
                function isContract(address account) internal view returns (bool) {
                  // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
                  // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
                  // for accounts without code, i.e. `keccak256('')`
                  bytes32 codehash;
                  bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
                  // solhint-disable-next-line no-inline-assembly
                  assembly {
                    codehash := extcodehash(account)
                  }
                  return (codehash != accountHash && codehash != 0x0);
                }
                /**
                 * @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://diligence.consensys.net/posts/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.5.11/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');
                  // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
                  (bool success, ) = recipient.call{value: amount}('');
                  require(success, 'Address: unable to send value, recipient may have reverted');
                }
              }
              // SPDX-License-Identifier: AGPL-3.0
              pragma solidity 0.8.10;
              import './Proxy.sol';
              import '../contracts/Address.sol';
              /**
               * @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)
                  }
                }
              }
              // SPDX-License-Identifier: AGPL-3.0
              pragma solidity 0.8.10;
              import './BaseUpgradeabilityProxy.sol';
              /**
               * @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);
                  }
                }
              }
              // SPDX-License-Identifier: AGPL-3.0
              pragma solidity 0.8.10;
              /**
               * @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.
                 * Will run if no other function in the contract matches the call data.
                 * 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());
                }
              }
              // SPDX-License-Identifier: AGPL-3.0
              pragma solidity 0.8.10;
              import {BaseUpgradeabilityProxy} from '../../../dependencies/openzeppelin/upgradeability/BaseUpgradeabilityProxy.sol';
              /**
               * @title BaseImmutableAdminUpgradeabilityProxy
               * @author Aave, inspired by the OpenZeppelin upgradeability proxy pattern
               * @notice This contract combines an upgradeability proxy with an authorization
               * mechanism for administrative tasks.
               * @dev 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 internal immutable _admin;
                /**
                 * @dev Constructor.
                 * @param admin The address of the admin
                 */
                constructor(address admin) {
                  _admin = admin;
                }
                modifier ifAdmin() {
                  if (msg.sender == _admin) {
                    _;
                  } else {
                    _fallback();
                  }
                }
                /**
                 * @notice Return the admin address
                 * @return The address of the proxy admin.
                 */
                function admin() external ifAdmin returns (address) {
                  return _admin;
                }
                /**
                 * @notice Return the implementation address
                 * @return The address of the implementation.
                 */
                function implementation() external ifAdmin returns (address) {
                  return _implementation();
                }
                /**
                 * @notice Upgrade the backing implementation of the proxy.
                 * @dev Only the admin can call this function.
                 * @param newImplementation The address of the new implementation.
                 */
                function upgradeTo(address newImplementation) external ifAdmin {
                  _upgradeTo(newImplementation);
                }
                /**
                 * @notice Upgrade the backing implementation of the proxy and call a function
                 * on the new implementation.
                 * @dev This is useful to initialize the proxied contract.
                 * @param newImplementation The 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);
                }
                /**
                 * @notice 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();
                }
              }
              // SPDX-License-Identifier: AGPL-3.0
              pragma solidity 0.8.10;
              import {InitializableUpgradeabilityProxy} from '../../../dependencies/openzeppelin/upgradeability/InitializableUpgradeabilityProxy.sol';
              import {Proxy} from '../../../dependencies/openzeppelin/upgradeability/Proxy.sol';
              import {BaseImmutableAdminUpgradeabilityProxy} from './BaseImmutableAdminUpgradeabilityProxy.sol';
              /**
               * @title InitializableAdminUpgradeabilityProxy
               * @author Aave
               * @dev Extends BaseAdminUpgradeabilityProxy with an initializer function
               */
              contract InitializableImmutableAdminUpgradeabilityProxy is
                BaseImmutableAdminUpgradeabilityProxy,
                InitializableUpgradeabilityProxy
              {
                /**
                 * @dev Constructor.
                 * @param admin The address of the admin
                 */
                constructor(address admin) BaseImmutableAdminUpgradeabilityProxy(admin) {
                  // Intentionally left blank
                }
                /// @inheritdoc BaseImmutableAdminUpgradeabilityProxy
                function _willFallback() internal override(BaseImmutableAdminUpgradeabilityProxy, Proxy) {
                  BaseImmutableAdminUpgradeabilityProxy._willFallback();
                }
              }
              

              File 2 of 4: PoolAddressesProvider
              // SPDX-License-Identifier: AGPL-3.0
              pragma solidity 0.8.10;
              /**
               * @dev Collection of functions related to the address type
               */
              library Address {
                /**
                 * @dev Returns true if `account` is a contract.
                 *
                 * [IMPORTANT]
                 * ====
                 * It is unsafe to assume that an address for which this function returns
                 * false is an externally-owned account (EOA) and not a contract.
                 *
                 * Among others, `isContract` will return false for the following
                 * types of addresses:
                 *
                 *  - an externally-owned account
                 *  - a contract in construction
                 *  - an address where a contract will be created
                 *  - an address where a contract lived, but was destroyed
                 * ====
                 */
                function isContract(address account) internal view returns (bool) {
                  // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
                  // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
                  // for accounts without code, i.e. `keccak256('')`
                  bytes32 codehash;
                  bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
                  // solhint-disable-next-line no-inline-assembly
                  assembly {
                    codehash := extcodehash(account)
                  }
                  return (codehash != accountHash && codehash != 0x0);
                }
                /**
                 * @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://diligence.consensys.net/posts/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.5.11/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');
                  // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
                  (bool success, ) = recipient.call{value: amount}('');
                  require(success, 'Address: unable to send value, recipient may have reverted');
                }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity 0.8.10;
              /*
               * @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 {
                function _msgSender() internal view virtual returns (address payable) {
                  return payable(msg.sender);
                }
                function _msgData() internal view virtual returns (bytes memory) {
                  this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                  return msg.data;
                }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity 0.8.10;
              import './Context.sol';
              /**
               * @dev Contract module which provides a basic access control mechanism, where
               * there is an account (an owner) that can be granted exclusive access to
               * specific functions.
               *
               * By default, the owner account will be the one that deploys the contract. This
               * can later be changed with {transferOwnership}.
               *
               * This module is used through inheritance. It will make available the modifier
               * `onlyOwner`, which can be applied to your functions to restrict their use to
               * the owner.
               */
              contract Ownable is Context {
                address private _owner;
                event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
                /**
                 * @dev Initializes the contract setting the deployer as the initial owner.
                 */
                constructor() {
                  address msgSender = _msgSender();
                  _owner = msgSender;
                  emit OwnershipTransferred(address(0), msgSender);
                }
                /**
                 * @dev Returns the address of the current owner.
                 */
                function owner() public view returns (address) {
                  return _owner;
                }
                /**
                 * @dev Throws if called by any account other than the owner.
                 */
                modifier onlyOwner() {
                  require(_owner == _msgSender(), 'Ownable: caller is not the owner');
                  _;
                }
                /**
                 * @dev Leaves the contract without owner. It will not be possible to call
                 * `onlyOwner` functions anymore. Can only be called by the current owner.
                 *
                 * NOTE: Renouncing ownership will leave the contract without an owner,
                 * thereby removing any functionality that is only available to the owner.
                 */
                function renounceOwnership() public virtual onlyOwner {
                  emit OwnershipTransferred(_owner, address(0));
                  _owner = address(0);
                }
                /**
                 * @dev Transfers ownership of the contract to a new account (`newOwner`).
                 * Can only be called by the current owner.
                 */
                function transferOwnership(address newOwner) public virtual onlyOwner {
                  require(newOwner != address(0), 'Ownable: new owner is the zero address');
                  emit OwnershipTransferred(_owner, newOwner);
                  _owner = newOwner;
                }
              }
              // SPDX-License-Identifier: AGPL-3.0
              pragma solidity 0.8.10;
              import './Proxy.sol';
              import '../contracts/Address.sol';
              /**
               * @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)
                  }
                }
              }
              // SPDX-License-Identifier: AGPL-3.0
              pragma solidity 0.8.10;
              import './BaseUpgradeabilityProxy.sol';
              /**
               * @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);
                  }
                }
              }
              // SPDX-License-Identifier: AGPL-3.0
              pragma solidity 0.8.10;
              /**
               * @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.
                 * Will run if no other function in the contract matches the call data.
                 * 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());
                }
              }
              // SPDX-License-Identifier: AGPL-3.0
              pragma solidity ^0.8.0;
              /**
               * @title IPoolAddressesProvider
               * @author Aave
               * @notice Defines the basic interface for a Pool Addresses Provider.
               */
              interface IPoolAddressesProvider {
                /**
                 * @dev Emitted when the market identifier is updated.
                 * @param oldMarketId The old id of the market
                 * @param newMarketId The new id of the market
                 */
                event MarketIdSet(string indexed oldMarketId, string indexed newMarketId);
                /**
                 * @dev Emitted when the pool is updated.
                 * @param oldAddress The old address of the Pool
                 * @param newAddress The new address of the Pool
                 */
                event PoolUpdated(address indexed oldAddress, address indexed newAddress);
                /**
                 * @dev Emitted when the pool configurator is updated.
                 * @param oldAddress The old address of the PoolConfigurator
                 * @param newAddress The new address of the PoolConfigurator
                 */
                event PoolConfiguratorUpdated(address indexed oldAddress, address indexed newAddress);
                /**
                 * @dev Emitted when the price oracle is updated.
                 * @param oldAddress The old address of the PriceOracle
                 * @param newAddress The new address of the PriceOracle
                 */
                event PriceOracleUpdated(address indexed oldAddress, address indexed newAddress);
                /**
                 * @dev Emitted when the ACL manager is updated.
                 * @param oldAddress The old address of the ACLManager
                 * @param newAddress The new address of the ACLManager
                 */
                event ACLManagerUpdated(address indexed oldAddress, address indexed newAddress);
                /**
                 * @dev Emitted when the ACL admin is updated.
                 * @param oldAddress The old address of the ACLAdmin
                 * @param newAddress The new address of the ACLAdmin
                 */
                event ACLAdminUpdated(address indexed oldAddress, address indexed newAddress);
                /**
                 * @dev Emitted when the price oracle sentinel is updated.
                 * @param oldAddress The old address of the PriceOracleSentinel
                 * @param newAddress The new address of the PriceOracleSentinel
                 */
                event PriceOracleSentinelUpdated(address indexed oldAddress, address indexed newAddress);
                /**
                 * @dev Emitted when the pool data provider is updated.
                 * @param oldAddress The old address of the PoolDataProvider
                 * @param newAddress The new address of the PoolDataProvider
                 */
                event PoolDataProviderUpdated(address indexed oldAddress, address indexed newAddress);
                /**
                 * @dev Emitted when a new proxy is created.
                 * @param id The identifier of the proxy
                 * @param proxyAddress The address of the created proxy contract
                 * @param implementationAddress The address of the implementation contract
                 */
                event ProxyCreated(
                  bytes32 indexed id,
                  address indexed proxyAddress,
                  address indexed implementationAddress
                );
                /**
                 * @dev Emitted when a new non-proxied contract address is registered.
                 * @param id The identifier of the contract
                 * @param oldAddress The address of the old contract
                 * @param newAddress The address of the new contract
                 */
                event AddressSet(bytes32 indexed id, address indexed oldAddress, address indexed newAddress);
                /**
                 * @dev Emitted when the implementation of the proxy registered with id is updated
                 * @param id The identifier of the contract
                 * @param proxyAddress The address of the proxy contract
                 * @param oldImplementationAddress The address of the old implementation contract
                 * @param newImplementationAddress The address of the new implementation contract
                 */
                event AddressSetAsProxy(
                  bytes32 indexed id,
                  address indexed proxyAddress,
                  address oldImplementationAddress,
                  address indexed newImplementationAddress
                );
                /**
                 * @notice Returns the id of the Aave market to which this contract points to.
                 * @return The market id
                 */
                function getMarketId() external view returns (string memory);
                /**
                 * @notice Associates an id with a specific PoolAddressesProvider.
                 * @dev This can be used to create an onchain registry of PoolAddressesProviders to
                 * identify and validate multiple Aave markets.
                 * @param newMarketId The market id
                 */
                function setMarketId(string calldata newMarketId) external;
                /**
                 * @notice Returns an address by its identifier.
                 * @dev The returned address might be an EOA or a contract, potentially proxied
                 * @dev It returns ZERO if there is no registered address with the given id
                 * @param id The id
                 * @return The address of the registered for the specified id
                 */
                function getAddress(bytes32 id) external view returns (address);
                /**
                 * @notice General function to update the implementation of a proxy registered with
                 * certain `id`. If there is no proxy registered, it will instantiate one and
                 * set as implementation the `newImplementationAddress`.
                 * @dev IMPORTANT Use this function carefully, only for ids that don't have an explicit
                 * setter function, in order to avoid unexpected consequences
                 * @param id The id
                 * @param newImplementationAddress The address of the new implementation
                 */
                function setAddressAsProxy(bytes32 id, address newImplementationAddress) external;
                /**
                 * @notice Sets an address for an id replacing the address saved in the addresses map.
                 * @dev IMPORTANT Use this function carefully, as it will do a hard replacement
                 * @param id The id
                 * @param newAddress The address to set
                 */
                function setAddress(bytes32 id, address newAddress) external;
                /**
                 * @notice Returns the address of the Pool proxy.
                 * @return The Pool proxy address
                 */
                function getPool() external view returns (address);
                /**
                 * @notice Updates the implementation of the Pool, or creates a proxy
                 * setting the new `pool` implementation when the function is called for the first time.
                 * @param newPoolImpl The new Pool implementation
                 */
                function setPoolImpl(address newPoolImpl) external;
                /**
                 * @notice Returns the address of the PoolConfigurator proxy.
                 * @return The PoolConfigurator proxy address
                 */
                function getPoolConfigurator() external view returns (address);
                /**
                 * @notice Updates the implementation of the PoolConfigurator, or creates a proxy
                 * setting the new `PoolConfigurator` implementation when the function is called for the first time.
                 * @param newPoolConfiguratorImpl The new PoolConfigurator implementation
                 */
                function setPoolConfiguratorImpl(address newPoolConfiguratorImpl) external;
                /**
                 * @notice Returns the address of the price oracle.
                 * @return The address of the PriceOracle
                 */
                function getPriceOracle() external view returns (address);
                /**
                 * @notice Updates the address of the price oracle.
                 * @param newPriceOracle The address of the new PriceOracle
                 */
                function setPriceOracle(address newPriceOracle) external;
                /**
                 * @notice Returns the address of the ACL manager.
                 * @return The address of the ACLManager
                 */
                function getACLManager() external view returns (address);
                /**
                 * @notice Updates the address of the ACL manager.
                 * @param newAclManager The address of the new ACLManager
                 */
                function setACLManager(address newAclManager) external;
                /**
                 * @notice Returns the address of the ACL admin.
                 * @return The address of the ACL admin
                 */
                function getACLAdmin() external view returns (address);
                /**
                 * @notice Updates the address of the ACL admin.
                 * @param newAclAdmin The address of the new ACL admin
                 */
                function setACLAdmin(address newAclAdmin) external;
                /**
                 * @notice Returns the address of the price oracle sentinel.
                 * @return The address of the PriceOracleSentinel
                 */
                function getPriceOracleSentinel() external view returns (address);
                /**
                 * @notice Updates the address of the price oracle sentinel.
                 * @param newPriceOracleSentinel The address of the new PriceOracleSentinel
                 */
                function setPriceOracleSentinel(address newPriceOracleSentinel) external;
                /**
                 * @notice Returns the address of the data provider.
                 * @return The address of the DataProvider
                 */
                function getPoolDataProvider() external view returns (address);
                /**
                 * @notice Updates the address of the data provider.
                 * @param newDataProvider The address of the new DataProvider
                 */
                function setPoolDataProvider(address newDataProvider) external;
              }
              // SPDX-License-Identifier: BUSL-1.1
              pragma solidity 0.8.10;
              import {Ownable} from '../../dependencies/openzeppelin/contracts/Ownable.sol';
              import {IPoolAddressesProvider} from '../../interfaces/IPoolAddressesProvider.sol';
              import {InitializableImmutableAdminUpgradeabilityProxy} from '../libraries/aave-upgradeability/InitializableImmutableAdminUpgradeabilityProxy.sol';
              /**
               * @title PoolAddressesProvider
               * @author Aave
               * @notice Main registry of addresses part of or connected to the protocol, including permissioned roles
               * @dev Acts as factory of proxies and admin of those, so with right to change its implementations
               * @dev Owned by the Aave Governance
               */
              contract PoolAddressesProvider is Ownable, IPoolAddressesProvider {
                // Identifier of the Aave Market
                string private _marketId;
                // Map of registered addresses (identifier => registeredAddress)
                mapping(bytes32 => address) private _addresses;
                // Main identifiers
                bytes32 private constant POOL = 'POOL';
                bytes32 private constant POOL_CONFIGURATOR = 'POOL_CONFIGURATOR';
                bytes32 private constant PRICE_ORACLE = 'PRICE_ORACLE';
                bytes32 private constant ACL_MANAGER = 'ACL_MANAGER';
                bytes32 private constant ACL_ADMIN = 'ACL_ADMIN';
                bytes32 private constant PRICE_ORACLE_SENTINEL = 'PRICE_ORACLE_SENTINEL';
                bytes32 private constant DATA_PROVIDER = 'DATA_PROVIDER';
                /**
                 * @dev Constructor.
                 * @param marketId The identifier of the market.
                 * @param owner The owner address of this contract.
                 */
                constructor(string memory marketId, address owner) {
                  _setMarketId(marketId);
                  transferOwnership(owner);
                }
                /// @inheritdoc IPoolAddressesProvider
                function getMarketId() external view override returns (string memory) {
                  return _marketId;
                }
                /// @inheritdoc IPoolAddressesProvider
                function setMarketId(string memory newMarketId) external override onlyOwner {
                  _setMarketId(newMarketId);
                }
                /// @inheritdoc IPoolAddressesProvider
                function getAddress(bytes32 id) public view override returns (address) {
                  return _addresses[id];
                }
                /// @inheritdoc IPoolAddressesProvider
                function setAddress(bytes32 id, address newAddress) external override onlyOwner {
                  address oldAddress = _addresses[id];
                  _addresses[id] = newAddress;
                  emit AddressSet(id, oldAddress, newAddress);
                }
                /// @inheritdoc IPoolAddressesProvider
                function setAddressAsProxy(bytes32 id, address newImplementationAddress)
                  external
                  override
                  onlyOwner
                {
                  address proxyAddress = _addresses[id];
                  address oldImplementationAddress = _getProxyImplementation(id);
                  _updateImpl(id, newImplementationAddress);
                  emit AddressSetAsProxy(id, proxyAddress, oldImplementationAddress, newImplementationAddress);
                }
                /// @inheritdoc IPoolAddressesProvider
                function getPool() external view override returns (address) {
                  return getAddress(POOL);
                }
                /// @inheritdoc IPoolAddressesProvider
                function setPoolImpl(address newPoolImpl) external override onlyOwner {
                  address oldPoolImpl = _getProxyImplementation(POOL);
                  _updateImpl(POOL, newPoolImpl);
                  emit PoolUpdated(oldPoolImpl, newPoolImpl);
                }
                /// @inheritdoc IPoolAddressesProvider
                function getPoolConfigurator() external view override returns (address) {
                  return getAddress(POOL_CONFIGURATOR);
                }
                /// @inheritdoc IPoolAddressesProvider
                function setPoolConfiguratorImpl(address newPoolConfiguratorImpl) external override onlyOwner {
                  address oldPoolConfiguratorImpl = _getProxyImplementation(POOL_CONFIGURATOR);
                  _updateImpl(POOL_CONFIGURATOR, newPoolConfiguratorImpl);
                  emit PoolConfiguratorUpdated(oldPoolConfiguratorImpl, newPoolConfiguratorImpl);
                }
                /// @inheritdoc IPoolAddressesProvider
                function getPriceOracle() external view override returns (address) {
                  return getAddress(PRICE_ORACLE);
                }
                /// @inheritdoc IPoolAddressesProvider
                function setPriceOracle(address newPriceOracle) external override onlyOwner {
                  address oldPriceOracle = _addresses[PRICE_ORACLE];
                  _addresses[PRICE_ORACLE] = newPriceOracle;
                  emit PriceOracleUpdated(oldPriceOracle, newPriceOracle);
                }
                /// @inheritdoc IPoolAddressesProvider
                function getACLManager() external view override returns (address) {
                  return getAddress(ACL_MANAGER);
                }
                /// @inheritdoc IPoolAddressesProvider
                function setACLManager(address newAclManager) external override onlyOwner {
                  address oldAclManager = _addresses[ACL_MANAGER];
                  _addresses[ACL_MANAGER] = newAclManager;
                  emit ACLManagerUpdated(oldAclManager, newAclManager);
                }
                /// @inheritdoc IPoolAddressesProvider
                function getACLAdmin() external view override returns (address) {
                  return getAddress(ACL_ADMIN);
                }
                /// @inheritdoc IPoolAddressesProvider
                function setACLAdmin(address newAclAdmin) external override onlyOwner {
                  address oldAclAdmin = _addresses[ACL_ADMIN];
                  _addresses[ACL_ADMIN] = newAclAdmin;
                  emit ACLAdminUpdated(oldAclAdmin, newAclAdmin);
                }
                /// @inheritdoc IPoolAddressesProvider
                function getPriceOracleSentinel() external view override returns (address) {
                  return getAddress(PRICE_ORACLE_SENTINEL);
                }
                /// @inheritdoc IPoolAddressesProvider
                function setPriceOracleSentinel(address newPriceOracleSentinel) external override onlyOwner {
                  address oldPriceOracleSentinel = _addresses[PRICE_ORACLE_SENTINEL];
                  _addresses[PRICE_ORACLE_SENTINEL] = newPriceOracleSentinel;
                  emit PriceOracleSentinelUpdated(oldPriceOracleSentinel, newPriceOracleSentinel);
                }
                /// @inheritdoc IPoolAddressesProvider
                function getPoolDataProvider() external view override returns (address) {
                  return getAddress(DATA_PROVIDER);
                }
                /// @inheritdoc IPoolAddressesProvider
                function setPoolDataProvider(address newDataProvider) external override onlyOwner {
                  address oldDataProvider = _addresses[DATA_PROVIDER];
                  _addresses[DATA_PROVIDER] = newDataProvider;
                  emit PoolDataProviderUpdated(oldDataProvider, newDataProvider);
                }
                /**
                 * @notice Internal function to update the implementation of a specific proxied component of the protocol.
                 * @dev If there is no proxy registered with the given identifier, it creates the proxy setting `newAddress`
                 *   as implementation and calls the initialize() function on the proxy
                 * @dev If there is already a proxy registered, it just updates the implementation to `newAddress` and
                 *   calls the initialize() function via upgradeToAndCall() in the proxy
                 * @param id The id of the proxy to be updated
                 * @param newAddress The address of the new implementation
                 */
                function _updateImpl(bytes32 id, address newAddress) internal {
                  address proxyAddress = _addresses[id];
                  InitializableImmutableAdminUpgradeabilityProxy proxy;
                  bytes memory params = abi.encodeWithSignature('initialize(address)', address(this));
                  if (proxyAddress == address(0)) {
                    proxy = new InitializableImmutableAdminUpgradeabilityProxy(address(this));
                    _addresses[id] = proxyAddress = address(proxy);
                    proxy.initialize(newAddress, params);
                    emit ProxyCreated(id, proxyAddress, newAddress);
                  } else {
                    proxy = InitializableImmutableAdminUpgradeabilityProxy(payable(proxyAddress));
                    proxy.upgradeToAndCall(newAddress, params);
                  }
                }
                /**
                 * @notice Updates the identifier of the Aave market.
                 * @param newMarketId The new id of the market
                 */
                function _setMarketId(string memory newMarketId) internal {
                  string memory oldMarketId = _marketId;
                  _marketId = newMarketId;
                  emit MarketIdSet(oldMarketId, newMarketId);
                }
                /**
                 * @notice Returns the the implementation contract of the proxy contract by its identifier.
                 * @dev It returns ZERO if there is no registered address with the given id
                 * @dev It reverts if the registered address with the given id is not `InitializableImmutableAdminUpgradeabilityProxy`
                 * @param id The id
                 * @return The address of the implementation contract
                 */
                function _getProxyImplementation(bytes32 id) internal returns (address) {
                  address proxyAddress = _addresses[id];
                  if (proxyAddress == address(0)) {
                    return address(0);
                  } else {
                    address payable payableProxyAddress = payable(proxyAddress);
                    return InitializableImmutableAdminUpgradeabilityProxy(payableProxyAddress).implementation();
                  }
                }
              }
              // SPDX-License-Identifier: AGPL-3.0
              pragma solidity 0.8.10;
              import {BaseUpgradeabilityProxy} from '../../../dependencies/openzeppelin/upgradeability/BaseUpgradeabilityProxy.sol';
              /**
               * @title BaseImmutableAdminUpgradeabilityProxy
               * @author Aave, inspired by the OpenZeppelin upgradeability proxy pattern
               * @notice This contract combines an upgradeability proxy with an authorization
               * mechanism for administrative tasks.
               * @dev 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 internal immutable _admin;
                /**
                 * @dev Constructor.
                 * @param admin The address of the admin
                 */
                constructor(address admin) {
                  _admin = admin;
                }
                modifier ifAdmin() {
                  if (msg.sender == _admin) {
                    _;
                  } else {
                    _fallback();
                  }
                }
                /**
                 * @notice Return the admin address
                 * @return The address of the proxy admin.
                 */
                function admin() external ifAdmin returns (address) {
                  return _admin;
                }
                /**
                 * @notice Return the implementation address
                 * @return The address of the implementation.
                 */
                function implementation() external ifAdmin returns (address) {
                  return _implementation();
                }
                /**
                 * @notice Upgrade the backing implementation of the proxy.
                 * @dev Only the admin can call this function.
                 * @param newImplementation The address of the new implementation.
                 */
                function upgradeTo(address newImplementation) external ifAdmin {
                  _upgradeTo(newImplementation);
                }
                /**
                 * @notice Upgrade the backing implementation of the proxy and call a function
                 * on the new implementation.
                 * @dev This is useful to initialize the proxied contract.
                 * @param newImplementation The 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);
                }
                /**
                 * @notice 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();
                }
              }
              // SPDX-License-Identifier: AGPL-3.0
              pragma solidity 0.8.10;
              import {InitializableUpgradeabilityProxy} from '../../../dependencies/openzeppelin/upgradeability/InitializableUpgradeabilityProxy.sol';
              import {Proxy} from '../../../dependencies/openzeppelin/upgradeability/Proxy.sol';
              import {BaseImmutableAdminUpgradeabilityProxy} from './BaseImmutableAdminUpgradeabilityProxy.sol';
              /**
               * @title InitializableAdminUpgradeabilityProxy
               * @author Aave
               * @dev Extends BaseAdminUpgradeabilityProxy with an initializer function
               */
              contract InitializableImmutableAdminUpgradeabilityProxy is
                BaseImmutableAdminUpgradeabilityProxy,
                InitializableUpgradeabilityProxy
              {
                /**
                 * @dev Constructor.
                 * @param admin The address of the admin
                 */
                constructor(address admin) BaseImmutableAdminUpgradeabilityProxy(admin) {
                  // Intentionally left blank
                }
                /// @inheritdoc BaseImmutableAdminUpgradeabilityProxy
                function _willFallback() internal override(BaseImmutableAdminUpgradeabilityProxy, Proxy) {
                  BaseImmutableAdminUpgradeabilityProxy._willFallback();
                }
              }
              

              File 3 of 4: ACLManager
              // SPDX-License-Identifier: MIT
              pragma solidity 0.8.10;
              import './IAccessControl.sol';
              import './Context.sol';
              import './Strings.sol';
              import './ERC165.sol';
              /**
               * @dev Contract module that allows children to implement role-based access
               * control mechanisms. This is a lightweight version that doesn't allow enumerating role
               * members except through off-chain means by accessing the contract event logs. Some
               * applications may benefit from on-chain enumerability, for those cases see
               * {AccessControlEnumerable}.
               *
               * Roles are referred to by their `bytes32` identifier. These should be exposed
               * in the external API and be unique. The best way to achieve this is by
               * using `public constant` hash digests:
               *
               * ```
               * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
               * ```
               *
               * Roles can be used to represent a set of permissions. To restrict access to a
               * function call, use {hasRole}:
               *
               * ```
               * function foo() public {
               *     require(hasRole(MY_ROLE, msg.sender));
               *     ...
               * }
               * ```
               *
               * Roles can be granted and revoked dynamically via the {grantRole} and
               * {revokeRole} functions. Each role has an associated admin role, and only
               * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
               *
               * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
               * that only accounts with this role will be able to grant or revoke other
               * roles. More complex role relationships can be created by using
               * {_setRoleAdmin}.
               *
               * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
               * grant and revoke this role. Extra precautions should be taken to secure
               * accounts that have been granted it.
               */
              abstract contract AccessControl is Context, IAccessControl, ERC165 {
                struct RoleData {
                  mapping(address => bool) members;
                  bytes32 adminRole;
                }
                mapping(bytes32 => RoleData) private _roles;
                bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
                /**
                 * @dev Modifier that checks that an account has a specific role. Reverts
                 * with a standardized message including the required role.
                 *
                 * The format of the revert reason is given by the following regular expression:
                 *
                 *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
                 *
                 * _Available since v4.1._
                 */
                modifier onlyRole(bytes32 role) {
                  _checkRole(role, _msgSender());
                  _;
                }
                /**
                 * @dev See {IERC165-supportsInterface}.
                 */
                function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                  return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
                }
                /**
                 * @dev Returns `true` if `account` has been granted `role`.
                 */
                function hasRole(bytes32 role, address account) public view override returns (bool) {
                  return _roles[role].members[account];
                }
                /**
                 * @dev Revert with a standard message if `account` is missing `role`.
                 *
                 * The format of the revert reason is given by the following regular expression:
                 *
                 *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
                 */
                function _checkRole(bytes32 role, address account) internal view {
                  if (!hasRole(role, account)) {
                    revert(
                      string(
                        abi.encodePacked(
                          'AccessControl: account ',
                          Strings.toHexString(uint160(account), 20),
                          ' is missing role ',
                          Strings.toHexString(uint256(role), 32)
                        )
                      )
                    );
                  }
                }
                /**
                 * @dev Returns the admin role that controls `role`. See {grantRole} and
                 * {revokeRole}.
                 *
                 * To change a role's admin, use {_setRoleAdmin}.
                 */
                function getRoleAdmin(bytes32 role) public view override returns (bytes32) {
                  return _roles[role].adminRole;
                }
                /**
                 * @dev Grants `role` to `account`.
                 *
                 * If `account` had not been already granted `role`, emits a {RoleGranted}
                 * event.
                 *
                 * Requirements:
                 *
                 * - the caller must have ``role``'s admin role.
                 */
                function grantRole(bytes32 role, address account)
                  public
                  virtual
                  override
                  onlyRole(getRoleAdmin(role))
                {
                  _grantRole(role, account);
                }
                /**
                 * @dev Revokes `role` from `account`.
                 *
                 * If `account` had been granted `role`, emits a {RoleRevoked} event.
                 *
                 * Requirements:
                 *
                 * - the caller must have ``role``'s admin role.
                 */
                function revokeRole(bytes32 role, address account)
                  public
                  virtual
                  override
                  onlyRole(getRoleAdmin(role))
                {
                  _revokeRole(role, account);
                }
                /**
                 * @dev Revokes `role` from the calling account.
                 *
                 * Roles are often managed via {grantRole} and {revokeRole}: this function's
                 * purpose is to provide a mechanism for accounts to lose their privileges
                 * if they are compromised (such as when a trusted device is misplaced).
                 *
                 * If the calling account had been granted `role`, emits a {RoleRevoked}
                 * event.
                 *
                 * Requirements:
                 *
                 * - the caller must be `account`.
                 */
                function renounceRole(bytes32 role, address account) public virtual override {
                  require(account == _msgSender(), 'AccessControl: can only renounce roles for self');
                  _revokeRole(role, account);
                }
                /**
                 * @dev Grants `role` to `account`.
                 *
                 * If `account` had not been already granted `role`, emits a {RoleGranted}
                 * event. Note that unlike {grantRole}, this function doesn't perform any
                 * checks on the calling account.
                 *
                 * [WARNING]
                 * ====
                 * This function should only be called from the constructor when setting
                 * up the initial roles for the system.
                 *
                 * Using this function in any other way is effectively circumventing the admin
                 * system imposed by {AccessControl}.
                 * ====
                 */
                function _setupRole(bytes32 role, address account) internal virtual {
                  _grantRole(role, account);
                }
                /**
                 * @dev Sets `adminRole` as ``role``'s admin role.
                 *
                 * Emits a {RoleAdminChanged} event.
                 */
                function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
                  bytes32 previousAdminRole = getRoleAdmin(role);
                  _roles[role].adminRole = adminRole;
                  emit RoleAdminChanged(role, previousAdminRole, adminRole);
                }
                function _grantRole(bytes32 role, address account) private {
                  if (!hasRole(role, account)) {
                    _roles[role].members[account] = true;
                    emit RoleGranted(role, account, _msgSender());
                  }
                }
                function _revokeRole(bytes32 role, address account) private {
                  if (hasRole(role, account)) {
                    _roles[role].members[account] = false;
                    emit RoleRevoked(role, account, _msgSender());
                  }
                }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity 0.8.10;
              /*
               * @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 {
                function _msgSender() internal view virtual returns (address payable) {
                  return payable(msg.sender);
                }
                function _msgData() internal view virtual returns (bytes memory) {
                  this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                  return msg.data;
                }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity 0.8.10;
              import './IERC165.sol';
              /**
               * @dev Implementation of the {IERC165} interface.
               *
               * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
               * for the additional interface id that will be supported. For example:
               *
               * ```solidity
               * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
               *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
               * }
               * ```
               *
               * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
               */
              abstract contract ERC165 is IERC165 {
                /**
                 * @dev See {IERC165-supportsInterface}.
                 */
                function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                  return interfaceId == type(IERC165).interfaceId;
                }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity 0.8.10;
              /**
               * @dev External interface of AccessControl declared to support ERC165 detection.
               */
              interface IAccessControl {
                /**
                 * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
                 *
                 * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
                 * {RoleAdminChanged} not being emitted signaling this.
                 *
                 * _Available since v3.1._
                 */
                event RoleAdminChanged(
                  bytes32 indexed role,
                  bytes32 indexed previousAdminRole,
                  bytes32 indexed newAdminRole
                );
                /**
                 * @dev Emitted when `account` is granted `role`.
                 *
                 * `sender` is the account that originated the contract call, an admin role
                 * bearer except when using {AccessControl-_setupRole}.
                 */
                event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
                /**
                 * @dev Emitted when `account` is revoked `role`.
                 *
                 * `sender` is the account that originated the contract call:
                 *   - if using `revokeRole`, it is the admin role bearer
                 *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
                 */
                event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
                /**
                 * @dev Returns `true` if `account` has been granted `role`.
                 */
                function hasRole(bytes32 role, address account) external view returns (bool);
                /**
                 * @dev Returns the admin role that controls `role`. See {grantRole} and
                 * {revokeRole}.
                 *
                 * To change a role's admin, use {AccessControl-_setRoleAdmin}.
                 */
                function getRoleAdmin(bytes32 role) external view returns (bytes32);
                /**
                 * @dev Grants `role` to `account`.
                 *
                 * If `account` had not been already granted `role`, emits a {RoleGranted}
                 * event.
                 *
                 * Requirements:
                 *
                 * - the caller must have ``role``'s admin role.
                 */
                function grantRole(bytes32 role, address account) external;
                /**
                 * @dev Revokes `role` from `account`.
                 *
                 * If `account` had been granted `role`, emits a {RoleRevoked} event.
                 *
                 * Requirements:
                 *
                 * - the caller must have ``role``'s admin role.
                 */
                function revokeRole(bytes32 role, address account) external;
                /**
                 * @dev Revokes `role` from the calling account.
                 *
                 * Roles are often managed via {grantRole} and {revokeRole}: this function's
                 * purpose is to provide a mechanism for accounts to lose their privileges
                 * if they are compromised (such as when a trusted device is misplaced).
                 *
                 * If the calling account had been granted `role`, emits a {RoleRevoked}
                 * event.
                 *
                 * Requirements:
                 *
                 * - the caller must be `account`.
                 */
                function renounceRole(bytes32 role, address account) external;
              }
              // SPDX-License-Identifier: MIT
              pragma solidity 0.8.10;
              /**
               * @dev Interface of the ERC165 standard, as defined in the
               * https://eips.ethereum.org/EIPS/eip-165[EIP].
               *
               * Implementers can declare support of contract interfaces, which can then be
               * queried by others ({ERC165Checker}).
               *
               * For an implementation, see {ERC165}.
               */
              interface IERC165 {
                /**
                 * @dev Returns true if this contract implements the interface defined by
                 * `interfaceId`. See the corresponding
                 * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
                 * to learn more about how these ids are created.
                 *
                 * This function call must use less than 30 000 gas.
                 */
                function supportsInterface(bytes4 interfaceId) external view returns (bool);
              }
              // SPDX-License-Identifier: MIT
              pragma solidity 0.8.10;
              /**
               * @dev String operations.
               */
              library Strings {
                bytes16 private constant _HEX_SYMBOLS = '0123456789abcdef';
                /**
                 * @dev Converts a `uint256` to its ASCII `string` decimal representation.
                 */
                function toString(uint256 value) internal pure returns (string memory) {
                  // Inspired by OraclizeAPI's implementation - MIT licence
                  // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
                  if (value == 0) {
                    return '0';
                  }
                  uint256 temp = value;
                  uint256 digits;
                  while (temp != 0) {
                    digits++;
                    temp /= 10;
                  }
                  bytes memory buffer = new bytes(digits);
                  while (value != 0) {
                    digits -= 1;
                    buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
                    value /= 10;
                  }
                  return string(buffer);
                }
                /**
                 * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
                 */
                function toHexString(uint256 value) internal pure returns (string memory) {
                  if (value == 0) {
                    return '0x00';
                  }
                  uint256 temp = value;
                  uint256 length = 0;
                  while (temp != 0) {
                    length++;
                    temp >>= 8;
                  }
                  return toHexString(value, length);
                }
                /**
                 * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
                 */
                function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
                  bytes memory buffer = new bytes(2 * length + 2);
                  buffer[0] = '0';
                  buffer[1] = 'x';
                  for (uint256 i = 2 * length + 1; i > 1; --i) {
                    buffer[i] = _HEX_SYMBOLS[value & 0xf];
                    value >>= 4;
                  }
                  require(value == 0, 'Strings: hex length insufficient');
                  return string(buffer);
                }
              }
              // SPDX-License-Identifier: AGPL-3.0
              pragma solidity ^0.8.0;
              import {IPoolAddressesProvider} from './IPoolAddressesProvider.sol';
              /**
               * @title IACLManager
               * @author Aave
               * @notice Defines the basic interface for the ACL Manager
               */
              interface IACLManager {
                /**
                 * @notice Returns the contract address of the PoolAddressesProvider
                 * @return The address of the PoolAddressesProvider
                 */
                function ADDRESSES_PROVIDER() external view returns (IPoolAddressesProvider);
                /**
                 * @notice Returns the identifier of the PoolAdmin role
                 * @return The id of the PoolAdmin role
                 */
                function POOL_ADMIN_ROLE() external view returns (bytes32);
                /**
                 * @notice Returns the identifier of the EmergencyAdmin role
                 * @return The id of the EmergencyAdmin role
                 */
                function EMERGENCY_ADMIN_ROLE() external view returns (bytes32);
                /**
                 * @notice Returns the identifier of the RiskAdmin role
                 * @return The id of the RiskAdmin role
                 */
                function RISK_ADMIN_ROLE() external view returns (bytes32);
                /**
                 * @notice Returns the identifier of the FlashBorrower role
                 * @return The id of the FlashBorrower role
                 */
                function FLASH_BORROWER_ROLE() external view returns (bytes32);
                /**
                 * @notice Returns the identifier of the Bridge role
                 * @return The id of the Bridge role
                 */
                function BRIDGE_ROLE() external view returns (bytes32);
                /**
                 * @notice Returns the identifier of the AssetListingAdmin role
                 * @return The id of the AssetListingAdmin role
                 */
                function ASSET_LISTING_ADMIN_ROLE() external view returns (bytes32);
                /**
                 * @notice Set the role as admin of a specific role.
                 * @dev By default the admin role for all roles is `DEFAULT_ADMIN_ROLE`.
                 * @param role The role to be managed by the admin role
                 * @param adminRole The admin role
                 */
                function setRoleAdmin(bytes32 role, bytes32 adminRole) external;
                /**
                 * @notice Adds a new admin as PoolAdmin
                 * @param admin The address of the new admin
                 */
                function addPoolAdmin(address admin) external;
                /**
                 * @notice Removes an admin as PoolAdmin
                 * @param admin The address of the admin to remove
                 */
                function removePoolAdmin(address admin) external;
                /**
                 * @notice Returns true if the address is PoolAdmin, false otherwise
                 * @param admin The address to check
                 * @return True if the given address is PoolAdmin, false otherwise
                 */
                function isPoolAdmin(address admin) external view returns (bool);
                /**
                 * @notice Adds a new admin as EmergencyAdmin
                 * @param admin The address of the new admin
                 */
                function addEmergencyAdmin(address admin) external;
                /**
                 * @notice Removes an admin as EmergencyAdmin
                 * @param admin The address of the admin to remove
                 */
                function removeEmergencyAdmin(address admin) external;
                /**
                 * @notice Returns true if the address is EmergencyAdmin, false otherwise
                 * @param admin The address to check
                 * @return True if the given address is EmergencyAdmin, false otherwise
                 */
                function isEmergencyAdmin(address admin) external view returns (bool);
                /**
                 * @notice Adds a new admin as RiskAdmin
                 * @param admin The address of the new admin
                 */
                function addRiskAdmin(address admin) external;
                /**
                 * @notice Removes an admin as RiskAdmin
                 * @param admin The address of the admin to remove
                 */
                function removeRiskAdmin(address admin) external;
                /**
                 * @notice Returns true if the address is RiskAdmin, false otherwise
                 * @param admin The address to check
                 * @return True if the given address is RiskAdmin, false otherwise
                 */
                function isRiskAdmin(address admin) external view returns (bool);
                /**
                 * @notice Adds a new address as FlashBorrower
                 * @param borrower The address of the new FlashBorrower
                 */
                function addFlashBorrower(address borrower) external;
                /**
                 * @notice Removes an address as FlashBorrower
                 * @param borrower The address of the FlashBorrower to remove
                 */
                function removeFlashBorrower(address borrower) external;
                /**
                 * @notice Returns true if the address is FlashBorrower, false otherwise
                 * @param borrower The address to check
                 * @return True if the given address is FlashBorrower, false otherwise
                 */
                function isFlashBorrower(address borrower) external view returns (bool);
                /**
                 * @notice Adds a new address as Bridge
                 * @param bridge The address of the new Bridge
                 */
                function addBridge(address bridge) external;
                /**
                 * @notice Removes an address as Bridge
                 * @param bridge The address of the bridge to remove
                 */
                function removeBridge(address bridge) external;
                /**
                 * @notice Returns true if the address is Bridge, false otherwise
                 * @param bridge The address to check
                 * @return True if the given address is Bridge, false otherwise
                 */
                function isBridge(address bridge) external view returns (bool);
                /**
                 * @notice Adds a new admin as AssetListingAdmin
                 * @param admin The address of the new admin
                 */
                function addAssetListingAdmin(address admin) external;
                /**
                 * @notice Removes an admin as AssetListingAdmin
                 * @param admin The address of the admin to remove
                 */
                function removeAssetListingAdmin(address admin) external;
                /**
                 * @notice Returns true if the address is AssetListingAdmin, false otherwise
                 * @param admin The address to check
                 * @return True if the given address is AssetListingAdmin, false otherwise
                 */
                function isAssetListingAdmin(address admin) external view returns (bool);
              }
              // SPDX-License-Identifier: AGPL-3.0
              pragma solidity ^0.8.0;
              /**
               * @title IPoolAddressesProvider
               * @author Aave
               * @notice Defines the basic interface for a Pool Addresses Provider.
               */
              interface IPoolAddressesProvider {
                /**
                 * @dev Emitted when the market identifier is updated.
                 * @param oldMarketId The old id of the market
                 * @param newMarketId The new id of the market
                 */
                event MarketIdSet(string indexed oldMarketId, string indexed newMarketId);
                /**
                 * @dev Emitted when the pool is updated.
                 * @param oldAddress The old address of the Pool
                 * @param newAddress The new address of the Pool
                 */
                event PoolUpdated(address indexed oldAddress, address indexed newAddress);
                /**
                 * @dev Emitted when the pool configurator is updated.
                 * @param oldAddress The old address of the PoolConfigurator
                 * @param newAddress The new address of the PoolConfigurator
                 */
                event PoolConfiguratorUpdated(address indexed oldAddress, address indexed newAddress);
                /**
                 * @dev Emitted when the price oracle is updated.
                 * @param oldAddress The old address of the PriceOracle
                 * @param newAddress The new address of the PriceOracle
                 */
                event PriceOracleUpdated(address indexed oldAddress, address indexed newAddress);
                /**
                 * @dev Emitted when the ACL manager is updated.
                 * @param oldAddress The old address of the ACLManager
                 * @param newAddress The new address of the ACLManager
                 */
                event ACLManagerUpdated(address indexed oldAddress, address indexed newAddress);
                /**
                 * @dev Emitted when the ACL admin is updated.
                 * @param oldAddress The old address of the ACLAdmin
                 * @param newAddress The new address of the ACLAdmin
                 */
                event ACLAdminUpdated(address indexed oldAddress, address indexed newAddress);
                /**
                 * @dev Emitted when the price oracle sentinel is updated.
                 * @param oldAddress The old address of the PriceOracleSentinel
                 * @param newAddress The new address of the PriceOracleSentinel
                 */
                event PriceOracleSentinelUpdated(address indexed oldAddress, address indexed newAddress);
                /**
                 * @dev Emitted when the pool data provider is updated.
                 * @param oldAddress The old address of the PoolDataProvider
                 * @param newAddress The new address of the PoolDataProvider
                 */
                event PoolDataProviderUpdated(address indexed oldAddress, address indexed newAddress);
                /**
                 * @dev Emitted when a new proxy is created.
                 * @param id The identifier of the proxy
                 * @param proxyAddress The address of the created proxy contract
                 * @param implementationAddress The address of the implementation contract
                 */
                event ProxyCreated(
                  bytes32 indexed id,
                  address indexed proxyAddress,
                  address indexed implementationAddress
                );
                /**
                 * @dev Emitted when a new non-proxied contract address is registered.
                 * @param id The identifier of the contract
                 * @param oldAddress The address of the old contract
                 * @param newAddress The address of the new contract
                 */
                event AddressSet(bytes32 indexed id, address indexed oldAddress, address indexed newAddress);
                /**
                 * @dev Emitted when the implementation of the proxy registered with id is updated
                 * @param id The identifier of the contract
                 * @param proxyAddress The address of the proxy contract
                 * @param oldImplementationAddress The address of the old implementation contract
                 * @param newImplementationAddress The address of the new implementation contract
                 */
                event AddressSetAsProxy(
                  bytes32 indexed id,
                  address indexed proxyAddress,
                  address oldImplementationAddress,
                  address indexed newImplementationAddress
                );
                /**
                 * @notice Returns the id of the Aave market to which this contract points to.
                 * @return The market id
                 */
                function getMarketId() external view returns (string memory);
                /**
                 * @notice Associates an id with a specific PoolAddressesProvider.
                 * @dev This can be used to create an onchain registry of PoolAddressesProviders to
                 * identify and validate multiple Aave markets.
                 * @param newMarketId The market id
                 */
                function setMarketId(string calldata newMarketId) external;
                /**
                 * @notice Returns an address by its identifier.
                 * @dev The returned address might be an EOA or a contract, potentially proxied
                 * @dev It returns ZERO if there is no registered address with the given id
                 * @param id The id
                 * @return The address of the registered for the specified id
                 */
                function getAddress(bytes32 id) external view returns (address);
                /**
                 * @notice General function to update the implementation of a proxy registered with
                 * certain `id`. If there is no proxy registered, it will instantiate one and
                 * set as implementation the `newImplementationAddress`.
                 * @dev IMPORTANT Use this function carefully, only for ids that don't have an explicit
                 * setter function, in order to avoid unexpected consequences
                 * @param id The id
                 * @param newImplementationAddress The address of the new implementation
                 */
                function setAddressAsProxy(bytes32 id, address newImplementationAddress) external;
                /**
                 * @notice Sets an address for an id replacing the address saved in the addresses map.
                 * @dev IMPORTANT Use this function carefully, as it will do a hard replacement
                 * @param id The id
                 * @param newAddress The address to set
                 */
                function setAddress(bytes32 id, address newAddress) external;
                /**
                 * @notice Returns the address of the Pool proxy.
                 * @return The Pool proxy address
                 */
                function getPool() external view returns (address);
                /**
                 * @notice Updates the implementation of the Pool, or creates a proxy
                 * setting the new `pool` implementation when the function is called for the first time.
                 * @param newPoolImpl The new Pool implementation
                 */
                function setPoolImpl(address newPoolImpl) external;
                /**
                 * @notice Returns the address of the PoolConfigurator proxy.
                 * @return The PoolConfigurator proxy address
                 */
                function getPoolConfigurator() external view returns (address);
                /**
                 * @notice Updates the implementation of the PoolConfigurator, or creates a proxy
                 * setting the new `PoolConfigurator` implementation when the function is called for the first time.
                 * @param newPoolConfiguratorImpl The new PoolConfigurator implementation
                 */
                function setPoolConfiguratorImpl(address newPoolConfiguratorImpl) external;
                /**
                 * @notice Returns the address of the price oracle.
                 * @return The address of the PriceOracle
                 */
                function getPriceOracle() external view returns (address);
                /**
                 * @notice Updates the address of the price oracle.
                 * @param newPriceOracle The address of the new PriceOracle
                 */
                function setPriceOracle(address newPriceOracle) external;
                /**
                 * @notice Returns the address of the ACL manager.
                 * @return The address of the ACLManager
                 */
                function getACLManager() external view returns (address);
                /**
                 * @notice Updates the address of the ACL manager.
                 * @param newAclManager The address of the new ACLManager
                 */
                function setACLManager(address newAclManager) external;
                /**
                 * @notice Returns the address of the ACL admin.
                 * @return The address of the ACL admin
                 */
                function getACLAdmin() external view returns (address);
                /**
                 * @notice Updates the address of the ACL admin.
                 * @param newAclAdmin The address of the new ACL admin
                 */
                function setACLAdmin(address newAclAdmin) external;
                /**
                 * @notice Returns the address of the price oracle sentinel.
                 * @return The address of the PriceOracleSentinel
                 */
                function getPriceOracleSentinel() external view returns (address);
                /**
                 * @notice Updates the address of the price oracle sentinel.
                 * @param newPriceOracleSentinel The address of the new PriceOracleSentinel
                 */
                function setPriceOracleSentinel(address newPriceOracleSentinel) external;
                /**
                 * @notice Returns the address of the data provider.
                 * @return The address of the DataProvider
                 */
                function getPoolDataProvider() external view returns (address);
                /**
                 * @notice Updates the address of the data provider.
                 * @param newDataProvider The address of the new DataProvider
                 */
                function setPoolDataProvider(address newDataProvider) external;
              }
              // SPDX-License-Identifier: BUSL-1.1
              pragma solidity 0.8.10;
              import {AccessControl} from '../../dependencies/openzeppelin/contracts/AccessControl.sol';
              import {IPoolAddressesProvider} from '../../interfaces/IPoolAddressesProvider.sol';
              import {IACLManager} from '../../interfaces/IACLManager.sol';
              import {Errors} from '../libraries/helpers/Errors.sol';
              /**
               * @title ACLManager
               * @author Aave
               * @notice Access Control List Manager. Main registry of system roles and permissions.
               */
              contract ACLManager is AccessControl, IACLManager {
                bytes32 public constant override POOL_ADMIN_ROLE = keccak256('POOL_ADMIN');
                bytes32 public constant override EMERGENCY_ADMIN_ROLE = keccak256('EMERGENCY_ADMIN');
                bytes32 public constant override RISK_ADMIN_ROLE = keccak256('RISK_ADMIN');
                bytes32 public constant override FLASH_BORROWER_ROLE = keccak256('FLASH_BORROWER');
                bytes32 public constant override BRIDGE_ROLE = keccak256('BRIDGE');
                bytes32 public constant override ASSET_LISTING_ADMIN_ROLE = keccak256('ASSET_LISTING_ADMIN');
                IPoolAddressesProvider public immutable ADDRESSES_PROVIDER;
                /**
                 * @dev Constructor
                 * @dev The ACL admin should be initialized at the addressesProvider beforehand
                 * @param provider The address of the PoolAddressesProvider
                 */
                constructor(IPoolAddressesProvider provider) {
                  ADDRESSES_PROVIDER = provider;
                  address aclAdmin = provider.getACLAdmin();
                  require(aclAdmin != address(0), Errors.ACL_ADMIN_CANNOT_BE_ZERO);
                  _setupRole(DEFAULT_ADMIN_ROLE, aclAdmin);
                }
                /// @inheritdoc IACLManager
                function setRoleAdmin(bytes32 role, bytes32 adminRole)
                  external
                  override
                  onlyRole(DEFAULT_ADMIN_ROLE)
                {
                  _setRoleAdmin(role, adminRole);
                }
                /// @inheritdoc IACLManager
                function addPoolAdmin(address admin) external override {
                  grantRole(POOL_ADMIN_ROLE, admin);
                }
                /// @inheritdoc IACLManager
                function removePoolAdmin(address admin) external override {
                  revokeRole(POOL_ADMIN_ROLE, admin);
                }
                /// @inheritdoc IACLManager
                function isPoolAdmin(address admin) external view override returns (bool) {
                  return hasRole(POOL_ADMIN_ROLE, admin);
                }
                /// @inheritdoc IACLManager
                function addEmergencyAdmin(address admin) external override {
                  grantRole(EMERGENCY_ADMIN_ROLE, admin);
                }
                /// @inheritdoc IACLManager
                function removeEmergencyAdmin(address admin) external override {
                  revokeRole(EMERGENCY_ADMIN_ROLE, admin);
                }
                /// @inheritdoc IACLManager
                function isEmergencyAdmin(address admin) external view override returns (bool) {
                  return hasRole(EMERGENCY_ADMIN_ROLE, admin);
                }
                /// @inheritdoc IACLManager
                function addRiskAdmin(address admin) external override {
                  grantRole(RISK_ADMIN_ROLE, admin);
                }
                /// @inheritdoc IACLManager
                function removeRiskAdmin(address admin) external override {
                  revokeRole(RISK_ADMIN_ROLE, admin);
                }
                /// @inheritdoc IACLManager
                function isRiskAdmin(address admin) external view override returns (bool) {
                  return hasRole(RISK_ADMIN_ROLE, admin);
                }
                /// @inheritdoc IACLManager
                function addFlashBorrower(address borrower) external override {
                  grantRole(FLASH_BORROWER_ROLE, borrower);
                }
                /// @inheritdoc IACLManager
                function removeFlashBorrower(address borrower) external override {
                  revokeRole(FLASH_BORROWER_ROLE, borrower);
                }
                /// @inheritdoc IACLManager
                function isFlashBorrower(address borrower) external view override returns (bool) {
                  return hasRole(FLASH_BORROWER_ROLE, borrower);
                }
                /// @inheritdoc IACLManager
                function addBridge(address bridge) external override {
                  grantRole(BRIDGE_ROLE, bridge);
                }
                /// @inheritdoc IACLManager
                function removeBridge(address bridge) external override {
                  revokeRole(BRIDGE_ROLE, bridge);
                }
                /// @inheritdoc IACLManager
                function isBridge(address bridge) external view override returns (bool) {
                  return hasRole(BRIDGE_ROLE, bridge);
                }
                /// @inheritdoc IACLManager
                function addAssetListingAdmin(address admin) external override {
                  grantRole(ASSET_LISTING_ADMIN_ROLE, admin);
                }
                /// @inheritdoc IACLManager
                function removeAssetListingAdmin(address admin) external override {
                  revokeRole(ASSET_LISTING_ADMIN_ROLE, admin);
                }
                /// @inheritdoc IACLManager
                function isAssetListingAdmin(address admin) external view override returns (bool) {
                  return hasRole(ASSET_LISTING_ADMIN_ROLE, admin);
                }
              }
              // SPDX-License-Identifier: BUSL-1.1
              pragma solidity ^0.8.0;
              /**
               * @title Errors library
               * @author Aave
               * @notice Defines the error messages emitted by the different contracts of the Aave protocol
               */
              library Errors {
                string public constant CALLER_NOT_POOL_ADMIN = '1'; // 'The caller of the function is not a pool admin'
                string public constant CALLER_NOT_EMERGENCY_ADMIN = '2'; // 'The caller of the function is not an emergency admin'
                string public constant CALLER_NOT_POOL_OR_EMERGENCY_ADMIN = '3'; // 'The caller of the function is not a pool or emergency admin'
                string public constant CALLER_NOT_RISK_OR_POOL_ADMIN = '4'; // 'The caller of the function is not a risk or pool admin'
                string public constant CALLER_NOT_ASSET_LISTING_OR_POOL_ADMIN = '5'; // 'The caller of the function is not an asset listing or pool admin'
                string public constant CALLER_NOT_BRIDGE = '6'; // 'The caller of the function is not a bridge'
                string public constant ADDRESSES_PROVIDER_NOT_REGISTERED = '7'; // 'Pool addresses provider is not registered'
                string public constant INVALID_ADDRESSES_PROVIDER_ID = '8'; // 'Invalid id for the pool addresses provider'
                string public constant NOT_CONTRACT = '9'; // 'Address is not a contract'
                string public constant CALLER_NOT_POOL_CONFIGURATOR = '10'; // 'The caller of the function is not the pool configurator'
                string public constant CALLER_NOT_ATOKEN = '11'; // 'The caller of the function is not an AToken'
                string public constant INVALID_ADDRESSES_PROVIDER = '12'; // 'The address of the pool addresses provider is invalid'
                string public constant INVALID_FLASHLOAN_EXECUTOR_RETURN = '13'; // 'Invalid return value of the flashloan executor function'
                string public constant RESERVE_ALREADY_ADDED = '14'; // 'Reserve has already been added to reserve list'
                string public constant NO_MORE_RESERVES_ALLOWED = '15'; // 'Maximum amount of reserves in the pool reached'
                string public constant EMODE_CATEGORY_RESERVED = '16'; // 'Zero eMode category is reserved for volatile heterogeneous assets'
                string public constant INVALID_EMODE_CATEGORY_ASSIGNMENT = '17'; // 'Invalid eMode category assignment to asset'
                string public constant RESERVE_LIQUIDITY_NOT_ZERO = '18'; // 'The liquidity of the reserve needs to be 0'
                string public constant FLASHLOAN_PREMIUM_INVALID = '19'; // 'Invalid flashloan premium'
                string public constant INVALID_RESERVE_PARAMS = '20'; // 'Invalid risk parameters for the reserve'
                string public constant INVALID_EMODE_CATEGORY_PARAMS = '21'; // 'Invalid risk parameters for the eMode category'
                string public constant BRIDGE_PROTOCOL_FEE_INVALID = '22'; // 'Invalid bridge protocol fee'
                string public constant CALLER_MUST_BE_POOL = '23'; // 'The caller of this function must be a pool'
                string public constant INVALID_MINT_AMOUNT = '24'; // 'Invalid amount to mint'
                string public constant INVALID_BURN_AMOUNT = '25'; // 'Invalid amount to burn'
                string public constant INVALID_AMOUNT = '26'; // 'Amount must be greater than 0'
                string public constant RESERVE_INACTIVE = '27'; // 'Action requires an active reserve'
                string public constant RESERVE_FROZEN = '28'; // 'Action cannot be performed because the reserve is frozen'
                string public constant RESERVE_PAUSED = '29'; // 'Action cannot be performed because the reserve is paused'
                string public constant BORROWING_NOT_ENABLED = '30'; // 'Borrowing is not enabled'
                string public constant STABLE_BORROWING_NOT_ENABLED = '31'; // 'Stable borrowing is not enabled'
                string public constant NOT_ENOUGH_AVAILABLE_USER_BALANCE = '32'; // 'User cannot withdraw more than the available balance'
                string public constant INVALID_INTEREST_RATE_MODE_SELECTED = '33'; // 'Invalid interest rate mode selected'
                string public constant COLLATERAL_BALANCE_IS_ZERO = '34'; // 'The collateral balance is 0'
                string public constant HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD = '35'; // 'Health factor is lesser than the liquidation threshold'
                string public constant COLLATERAL_CANNOT_COVER_NEW_BORROW = '36'; // 'There is not enough collateral to cover a new borrow'
                string public constant COLLATERAL_SAME_AS_BORROWING_CURRENCY = '37'; // 'Collateral is (mostly) the same currency that is being borrowed'
                string public constant AMOUNT_BIGGER_THAN_MAX_LOAN_SIZE_STABLE = '38'; // 'The requested amount is greater than the max loan size in stable rate mode'
                string public constant NO_DEBT_OF_SELECTED_TYPE = '39'; // 'For repayment of a specific type of debt, the user needs to have debt that type'
                string public constant NO_EXPLICIT_AMOUNT_TO_REPAY_ON_BEHALF = '40'; // 'To repay on behalf of a user an explicit amount to repay is needed'
                string public constant NO_OUTSTANDING_STABLE_DEBT = '41'; // 'User does not have outstanding stable rate debt on this reserve'
                string public constant NO_OUTSTANDING_VARIABLE_DEBT = '42'; // 'User does not have outstanding variable rate debt on this reserve'
                string public constant UNDERLYING_BALANCE_ZERO = '43'; // 'The underlying balance needs to be greater than 0'
                string public constant INTEREST_RATE_REBALANCE_CONDITIONS_NOT_MET = '44'; // 'Interest rate rebalance conditions were not met'
                string public constant HEALTH_FACTOR_NOT_BELOW_THRESHOLD = '45'; // 'Health factor is not below the threshold'
                string public constant COLLATERAL_CANNOT_BE_LIQUIDATED = '46'; // 'The collateral chosen cannot be liquidated'
                string public constant SPECIFIED_CURRENCY_NOT_BORROWED_BY_USER = '47'; // 'User did not borrow the specified currency'
                string public constant INCONSISTENT_FLASHLOAN_PARAMS = '49'; // 'Inconsistent flashloan parameters'
                string public constant BORROW_CAP_EXCEEDED = '50'; // 'Borrow cap is exceeded'
                string public constant SUPPLY_CAP_EXCEEDED = '51'; // 'Supply cap is exceeded'
                string public constant UNBACKED_MINT_CAP_EXCEEDED = '52'; // 'Unbacked mint cap is exceeded'
                string public constant DEBT_CEILING_EXCEEDED = '53'; // 'Debt ceiling is exceeded'
                string public constant UNDERLYING_CLAIMABLE_RIGHTS_NOT_ZERO = '54'; // 'Claimable rights over underlying not zero (aToken supply or accruedToTreasury)'
                string public constant STABLE_DEBT_NOT_ZERO = '55'; // 'Stable debt supply is not zero'
                string public constant VARIABLE_DEBT_SUPPLY_NOT_ZERO = '56'; // 'Variable debt supply is not zero'
                string public constant LTV_VALIDATION_FAILED = '57'; // 'Ltv validation failed'
                string public constant INCONSISTENT_EMODE_CATEGORY = '58'; // 'Inconsistent eMode category'
                string public constant PRICE_ORACLE_SENTINEL_CHECK_FAILED = '59'; // 'Price oracle sentinel validation failed'
                string public constant ASSET_NOT_BORROWABLE_IN_ISOLATION = '60'; // 'Asset is not borrowable in isolation mode'
                string public constant RESERVE_ALREADY_INITIALIZED = '61'; // 'Reserve has already been initialized'
                string public constant USER_IN_ISOLATION_MODE = '62'; // 'User is in isolation mode'
                string public constant INVALID_LTV = '63'; // 'Invalid ltv parameter for the reserve'
                string public constant INVALID_LIQ_THRESHOLD = '64'; // 'Invalid liquidity threshold parameter for the reserve'
                string public constant INVALID_LIQ_BONUS = '65'; // 'Invalid liquidity bonus parameter for the reserve'
                string public constant INVALID_DECIMALS = '66'; // 'Invalid decimals parameter of the underlying asset of the reserve'
                string public constant INVALID_RESERVE_FACTOR = '67'; // 'Invalid reserve factor parameter for the reserve'
                string public constant INVALID_BORROW_CAP = '68'; // 'Invalid borrow cap for the reserve'
                string public constant INVALID_SUPPLY_CAP = '69'; // 'Invalid supply cap for the reserve'
                string public constant INVALID_LIQUIDATION_PROTOCOL_FEE = '70'; // 'Invalid liquidation protocol fee for the reserve'
                string public constant INVALID_EMODE_CATEGORY = '71'; // 'Invalid eMode category for the reserve'
                string public constant INVALID_UNBACKED_MINT_CAP = '72'; // 'Invalid unbacked mint cap for the reserve'
                string public constant INVALID_DEBT_CEILING = '73'; // 'Invalid debt ceiling for the reserve
                string public constant INVALID_RESERVE_INDEX = '74'; // 'Invalid reserve index'
                string public constant ACL_ADMIN_CANNOT_BE_ZERO = '75'; // 'ACL admin cannot be set to the zero address'
                string public constant INCONSISTENT_PARAMS_LENGTH = '76'; // 'Array parameters that should be equal length are not'
                string public constant ZERO_ADDRESS_NOT_VALID = '77'; // 'Zero address not valid'
                string public constant INVALID_EXPIRATION = '78'; // 'Invalid expiration'
                string public constant INVALID_SIGNATURE = '79'; // 'Invalid signature'
                string public constant OPERATION_NOT_SUPPORTED = '80'; // 'Operation not supported'
                string public constant DEBT_CEILING_NOT_ZERO = '81'; // 'Debt ceiling is not zero'
                string public constant ASSET_NOT_LISTED = '82'; // 'Asset is not listed'
                string public constant INVALID_OPTIMAL_USAGE_RATIO = '83'; // 'Invalid optimal usage ratio'
                string public constant INVALID_OPTIMAL_STABLE_TO_TOTAL_DEBT_RATIO = '84'; // 'Invalid optimal stable to total debt ratio'
                string public constant UNDERLYING_CANNOT_BE_RESCUED = '85'; // 'The underlying asset cannot be rescued'
                string public constant ADDRESSES_PROVIDER_ALREADY_ADDED = '86'; // 'Reserve has already been added to reserve list'
                string public constant POOL_ADDRESSES_DO_NOT_MATCH = '87'; // 'The token implementation pool address and the pool address provided by the initializing pool do not match'
                string public constant STABLE_BORROWING_ENABLED = '88'; // 'Stable borrowing is enabled'
                string public constant SILOED_BORROWING_VIOLATION = '89'; // 'User is trying to borrow multiple assets including a siloed one'
                string public constant RESERVE_DEBT_NOT_ZERO = '90'; // the total debt of the reserve needs to be 0
                string public constant FLASHLOAN_DISABLED = '91'; // FlashLoaning for this asset is disabled
              }
              

              File 4 of 4: InitializableImmutableAdminUpgradeabilityProxy
              // SPDX-License-Identifier: AGPL-3.0
              pragma solidity 0.8.10;
              /**
               * @dev Collection of functions related to the address type
               */
              library Address {
                /**
                 * @dev Returns true if `account` is a contract.
                 *
                 * [IMPORTANT]
                 * ====
                 * It is unsafe to assume that an address for which this function returns
                 * false is an externally-owned account (EOA) and not a contract.
                 *
                 * Among others, `isContract` will return false for the following
                 * types of addresses:
                 *
                 *  - an externally-owned account
                 *  - a contract in construction
                 *  - an address where a contract will be created
                 *  - an address where a contract lived, but was destroyed
                 * ====
                 */
                function isContract(address account) internal view returns (bool) {
                  // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
                  // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
                  // for accounts without code, i.e. `keccak256('')`
                  bytes32 codehash;
                  bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
                  // solhint-disable-next-line no-inline-assembly
                  assembly {
                    codehash := extcodehash(account)
                  }
                  return (codehash != accountHash && codehash != 0x0);
                }
                /**
                 * @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://diligence.consensys.net/posts/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.5.11/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');
                  // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
                  (bool success, ) = recipient.call{value: amount}('');
                  require(success, 'Address: unable to send value, recipient may have reverted');
                }
              }
              // SPDX-License-Identifier: AGPL-3.0
              pragma solidity 0.8.10;
              import './Proxy.sol';
              import '../contracts/Address.sol';
              /**
               * @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)
                  }
                }
              }
              // SPDX-License-Identifier: AGPL-3.0
              pragma solidity 0.8.10;
              import './BaseUpgradeabilityProxy.sol';
              /**
               * @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);
                  }
                }
              }
              // SPDX-License-Identifier: AGPL-3.0
              pragma solidity 0.8.10;
              /**
               * @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.
                 * Will run if no other function in the contract matches the call data.
                 * 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());
                }
              }
              // SPDX-License-Identifier: AGPL-3.0
              pragma solidity 0.8.10;
              import {BaseUpgradeabilityProxy} from '../../../dependencies/openzeppelin/upgradeability/BaseUpgradeabilityProxy.sol';
              /**
               * @title BaseImmutableAdminUpgradeabilityProxy
               * @author Aave, inspired by the OpenZeppelin upgradeability proxy pattern
               * @notice This contract combines an upgradeability proxy with an authorization
               * mechanism for administrative tasks.
               * @dev 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 internal immutable _admin;
                /**
                 * @dev Constructor.
                 * @param admin The address of the admin
                 */
                constructor(address admin) {
                  _admin = admin;
                }
                modifier ifAdmin() {
                  if (msg.sender == _admin) {
                    _;
                  } else {
                    _fallback();
                  }
                }
                /**
                 * @notice Return the admin address
                 * @return The address of the proxy admin.
                 */
                function admin() external ifAdmin returns (address) {
                  return _admin;
                }
                /**
                 * @notice Return the implementation address
                 * @return The address of the implementation.
                 */
                function implementation() external ifAdmin returns (address) {
                  return _implementation();
                }
                /**
                 * @notice Upgrade the backing implementation of the proxy.
                 * @dev Only the admin can call this function.
                 * @param newImplementation The address of the new implementation.
                 */
                function upgradeTo(address newImplementation) external ifAdmin {
                  _upgradeTo(newImplementation);
                }
                /**
                 * @notice Upgrade the backing implementation of the proxy and call a function
                 * on the new implementation.
                 * @dev This is useful to initialize the proxied contract.
                 * @param newImplementation The 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);
                }
                /**
                 * @notice 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();
                }
              }
              // SPDX-License-Identifier: AGPL-3.0
              pragma solidity 0.8.10;
              import {InitializableUpgradeabilityProxy} from '../../../dependencies/openzeppelin/upgradeability/InitializableUpgradeabilityProxy.sol';
              import {Proxy} from '../../../dependencies/openzeppelin/upgradeability/Proxy.sol';
              import {BaseImmutableAdminUpgradeabilityProxy} from './BaseImmutableAdminUpgradeabilityProxy.sol';
              /**
               * @title InitializableAdminUpgradeabilityProxy
               * @author Aave
               * @dev Extends BaseAdminUpgradeabilityProxy with an initializer function
               */
              contract InitializableImmutableAdminUpgradeabilityProxy is
                BaseImmutableAdminUpgradeabilityProxy,
                InitializableUpgradeabilityProxy
              {
                /**
                 * @dev Constructor.
                 * @param admin The address of the admin
                 */
                constructor(address admin) BaseImmutableAdminUpgradeabilityProxy(admin) {
                  // Intentionally left blank
                }
                /// @inheritdoc BaseImmutableAdminUpgradeabilityProxy
                function _willFallback() internal override(BaseImmutableAdminUpgradeabilityProxy, Proxy) {
                  BaseImmutableAdminUpgradeabilityProxy._willFallback();
                }
              }