ETH Price: $2,442.28 (+1.35%)

Transaction Decoder

Block:
19951026 at May-26-2024 02:19:59 AM +UTC
Transaction Fee:
0.000239616399343828 ETH $0.59
Gas Used:
86,014 Gas / 2.785783702 Gwei

Emitted Events:

326 InitializableImmutableAdminUpgradeabilityProxy.0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925( 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925, 0x0000000000000000000000008afed901714ac7753c5a410516f2d4396a48e9db, 0x000000000000000000000000893411580e590d62ddbca8a703d61cc4a8c7b2b9, ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff )
327 GnosisSafeProxy.0x442e715f626346e8c54381002da614f62bee8d27386535b2521ec8540898556e( 0x442e715f626346e8c54381002da614f62bee8d27386535b2521ec8540898556e, 4d8e4b9442cfb44e32d37204f6eded669b3af21fc5c728a4ff642a87434da435, 0000000000000000000000000000000000000000000000000000000000000000 )

Account State Difference:

  Address   Before After State Difference Code
(Titan Builder)
5.466982507738163292 Eth5.466982591171743292 Eth0.00000008343358
0x4d5F47FA...C9BC514E8
0x8afEd901...96A48E9DB
0xee357982...87c0db119
0.204590711925079448 Eth
Nonce: 18
0.20435109552573562 Eth
Nonce: 19
0.000239616399343828

Execution Trace

GnosisSafeProxy.6a761202( )
  • GnosisSafe.execTransaction( to=0x4d5F47FA6A74757f35C14fD3a6Ef8E3C9BC514E8, value=0, data=0x095EA7B3000000000000000000000000893411580E590D62DDBCA8A703D61CC4A8C7B2B9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, operation=0, safeTxGas=0, baseGas=0, gasPrice=0, gasToken=0x0000000000000000000000000000000000000000, refundReceiver=0x0000000000000000000000000000000000000000, signatures=0x4AC2FEE22AA9CE4D1E901458611D302523B0807B6051A2111B04185C62A42EAE31F2AEC18E109B00222599301A72796A421142766D435FAFA61FB48C8806DC4220000000000000000000000000EE357982899B66C8D6D07303B16560787C0DB119000000000000000000000000000000000000000000000000000000000000000001 ) => ( success=True )
    • Null: 0x000...001.626c3f25( )
    • InitializableImmutableAdminUpgradeabilityProxy.095ea7b3( )
      • AToken.approve( spender=0x893411580e590D62dDBca8a703d61Cc4A8c7b2b9, amount=115792089237316195423570985008687907853269984665640564039457584007913129639935 ) => ( True )
        File 1 of 4: GnosisSafeProxy
        // SPDX-License-Identifier: LGPL-3.0-only
        pragma solidity >=0.7.0 <0.9.0;
        
        /// @title IProxy - Helper interface to access masterCopy of the Proxy on-chain
        /// @author Richard Meissner - <[email protected]>
        interface IProxy {
            function masterCopy() external view returns (address);
        }
        
        /// @title GnosisSafeProxy - Generic proxy contract allows to execute all transactions applying the code of a master contract.
        /// @author Stefan George - <[email protected]>
        /// @author Richard Meissner - <[email protected]>
        contract GnosisSafeProxy {
            // singleton always needs to be first declared variable, to ensure that it is at the same location in the contracts to which calls are delegated.
            // To reduce deployment costs this variable is internal and needs to be retrieved via `getStorageAt`
            address internal singleton;
        
            /// @dev Constructor function sets address of singleton contract.
            /// @param _singleton Singleton address.
            constructor(address _singleton) {
                require(_singleton != address(0), "Invalid singleton address provided");
                singleton = _singleton;
            }
        
            /// @dev Fallback function forwards all transactions and returns all received return data.
            fallback() external payable {
                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let _singleton := and(sload(0), 0xffffffffffffffffffffffffffffffffffffffff)
                    // 0xa619486e == keccak("masterCopy()"). The value is right padded to 32-bytes with 0s
                    if eq(calldataload(0), 0xa619486e00000000000000000000000000000000000000000000000000000000) {
                        mstore(0, _singleton)
                        return(0, 0x20)
                    }
                    calldatacopy(0, 0, calldatasize())
                    let success := delegatecall(gas(), _singleton, 0, calldatasize(), 0, 0)
                    returndatacopy(0, 0, returndatasize())
                    if eq(success, 0) {
                        revert(0, returndatasize())
                    }
                    return(0, returndatasize())
                }
            }
        }
        
        /// @title Proxy Factory - Allows to create new proxy contact and execute a message call to the new proxy within one transaction.
        /// @author Stefan George - <[email protected]>
        contract GnosisSafeProxyFactory {
            event ProxyCreation(GnosisSafeProxy proxy, address singleton);
        
            /// @dev Allows to create new proxy contact and execute a message call to the new proxy within one transaction.
            /// @param singleton Address of singleton contract.
            /// @param data Payload for message call sent to new proxy contract.
            function createProxy(address singleton, bytes memory data) public returns (GnosisSafeProxy proxy) {
                proxy = new GnosisSafeProxy(singleton);
                if (data.length > 0)
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        if eq(call(gas(), proxy, 0, add(data, 0x20), mload(data), 0, 0), 0) {
                            revert(0, 0)
                        }
                    }
                emit ProxyCreation(proxy, singleton);
            }
        
            /// @dev Allows to retrieve the runtime code of a deployed Proxy. This can be used to check that the expected Proxy was deployed.
            function proxyRuntimeCode() public pure returns (bytes memory) {
                return type(GnosisSafeProxy).runtimeCode;
            }
        
            /// @dev Allows to retrieve the creation code used for the Proxy deployment. With this it is easily possible to calculate predicted address.
            function proxyCreationCode() public pure returns (bytes memory) {
                return type(GnosisSafeProxy).creationCode;
            }
        
            /// @dev Allows to create new proxy contact using CREATE2 but it doesn't run the initializer.
            ///      This method is only meant as an utility to be called from other methods
            /// @param _singleton Address of singleton contract.
            /// @param initializer Payload for message call sent to new proxy contract.
            /// @param saltNonce Nonce that will be used to generate the salt to calculate the address of the new proxy contract.
            function deployProxyWithNonce(
                address _singleton,
                bytes memory initializer,
                uint256 saltNonce
            ) internal returns (GnosisSafeProxy proxy) {
                // If the initializer changes the proxy address should change too. Hashing the initializer data is cheaper than just concatinating it
                bytes32 salt = keccak256(abi.encodePacked(keccak256(initializer), saltNonce));
                bytes memory deploymentData = abi.encodePacked(type(GnosisSafeProxy).creationCode, uint256(uint160(_singleton)));
                // solhint-disable-next-line no-inline-assembly
                assembly {
                    proxy := create2(0x0, add(0x20, deploymentData), mload(deploymentData), salt)
                }
                require(address(proxy) != address(0), "Create2 call failed");
            }
        
            /// @dev Allows to create new proxy contact and execute a message call to the new proxy within one transaction.
            /// @param _singleton Address of singleton contract.
            /// @param initializer Payload for message call sent to new proxy contract.
            /// @param saltNonce Nonce that will be used to generate the salt to calculate the address of the new proxy contract.
            function createProxyWithNonce(
                address _singleton,
                bytes memory initializer,
                uint256 saltNonce
            ) public returns (GnosisSafeProxy proxy) {
                proxy = deployProxyWithNonce(_singleton, initializer, saltNonce);
                if (initializer.length > 0)
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        if eq(call(gas(), proxy, 0, add(initializer, 0x20), mload(initializer), 0, 0), 0) {
                            revert(0, 0)
                        }
                    }
                emit ProxyCreation(proxy, _singleton);
            }
        
            /// @dev Allows to create new proxy contact, execute a message call to the new proxy and call a specified callback within one transaction
            /// @param _singleton Address of singleton contract.
            /// @param initializer Payload for message call sent to new proxy contract.
            /// @param saltNonce Nonce that will be used to generate the salt to calculate the address of the new proxy contract.
            /// @param callback Callback that will be invoced after the new proxy contract has been successfully deployed and initialized.
            function createProxyWithCallback(
                address _singleton,
                bytes memory initializer,
                uint256 saltNonce,
                IProxyCreationCallback callback
            ) public returns (GnosisSafeProxy proxy) {
                uint256 saltNonceWithCallback = uint256(keccak256(abi.encodePacked(saltNonce, callback)));
                proxy = createProxyWithNonce(_singleton, initializer, saltNonceWithCallback);
                if (address(callback) != address(0)) callback.proxyCreated(proxy, _singleton, initializer, saltNonce);
            }
        
            /// @dev Allows to get the address for a new proxy contact created via `createProxyWithNonce`
            ///      This method is only meant for address calculation purpose when you use an initializer that would revert,
            ///      therefore the response is returned with a revert. When calling this method set `from` to the address of the proxy factory.
            /// @param _singleton Address of singleton contract.
            /// @param initializer Payload for message call sent to new proxy contract.
            /// @param saltNonce Nonce that will be used to generate the salt to calculate the address of the new proxy contract.
            function calculateCreateProxyWithNonceAddress(
                address _singleton,
                bytes calldata initializer,
                uint256 saltNonce
            ) external returns (GnosisSafeProxy proxy) {
                proxy = deployProxyWithNonce(_singleton, initializer, saltNonce);
                revert(string(abi.encodePacked(proxy)));
            }
        }
        
        interface IProxyCreationCallback {
            function proxyCreated(
                GnosisSafeProxy proxy,
                address _singleton,
                bytes calldata initializer,
                uint256 saltNonce
            ) external;
        }

        File 2 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 3 of 4: GnosisSafe
        // SPDX-License-Identifier: LGPL-3.0-only
        pragma solidity >=0.7.0 <0.9.0;
        import "./base/ModuleManager.sol";
        import "./base/OwnerManager.sol";
        import "./base/FallbackManager.sol";
        import "./base/GuardManager.sol";
        import "./common/EtherPaymentFallback.sol";
        import "./common/Singleton.sol";
        import "./common/SignatureDecoder.sol";
        import "./common/SecuredTokenTransfer.sol";
        import "./common/StorageAccessible.sol";
        import "./interfaces/ISignatureValidator.sol";
        import "./external/GnosisSafeMath.sol";
        /// @title Gnosis Safe - A multisignature wallet with support for confirmations using signed messages based on ERC191.
        /// @author Stefan George - <[email protected]>
        /// @author Richard Meissner - <[email protected]>
        contract GnosisSafe is
            EtherPaymentFallback,
            Singleton,
            ModuleManager,
            OwnerManager,
            SignatureDecoder,
            SecuredTokenTransfer,
            ISignatureValidatorConstants,
            FallbackManager,
            StorageAccessible,
            GuardManager
        {
            using GnosisSafeMath for uint256;
            string public constant VERSION = "1.3.0";
            // keccak256(
            //     "EIP712Domain(uint256 chainId,address verifyingContract)"
            // );
            bytes32 private constant DOMAIN_SEPARATOR_TYPEHASH = 0x47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a79469218;
            // keccak256(
            //     "SafeTx(address to,uint256 value,bytes data,uint8 operation,uint256 safeTxGas,uint256 baseGas,uint256 gasPrice,address gasToken,address refundReceiver,uint256 nonce)"
            // );
            bytes32 private constant SAFE_TX_TYPEHASH = 0xbb8310d486368db6bd6f849402fdd73ad53d316b5a4b2644ad6efe0f941286d8;
            event SafeSetup(address indexed initiator, address[] owners, uint256 threshold, address initializer, address fallbackHandler);
            event ApproveHash(bytes32 indexed approvedHash, address indexed owner);
            event SignMsg(bytes32 indexed msgHash);
            event ExecutionFailure(bytes32 txHash, uint256 payment);
            event ExecutionSuccess(bytes32 txHash, uint256 payment);
            uint256 public nonce;
            bytes32 private _deprecatedDomainSeparator;
            // Mapping to keep track of all message hashes that have been approve by ALL REQUIRED owners
            mapping(bytes32 => uint256) public signedMessages;
            // Mapping to keep track of all hashes (message or transaction) that have been approve by ANY owners
            mapping(address => mapping(bytes32 => uint256)) public approvedHashes;
            // This constructor ensures that this contract can only be used as a master copy for Proxy contracts
            constructor() {
                // By setting the threshold it is not possible to call setup anymore,
                // so we create a Safe with 0 owners and threshold 1.
                // This is an unusable Safe, perfect for the singleton
                threshold = 1;
            }
            /// @dev Setup function sets initial storage of contract.
            /// @param _owners List of Safe owners.
            /// @param _threshold Number of required confirmations for a Safe transaction.
            /// @param to Contract address for optional delegate call.
            /// @param data Data payload for optional delegate call.
            /// @param fallbackHandler Handler for fallback calls to this contract
            /// @param paymentToken Token that should be used for the payment (0 is ETH)
            /// @param payment Value that should be paid
            /// @param paymentReceiver Adddress that should receive the payment (or 0 if tx.origin)
            function setup(
                address[] calldata _owners,
                uint256 _threshold,
                address to,
                bytes calldata data,
                address fallbackHandler,
                address paymentToken,
                uint256 payment,
                address payable paymentReceiver
            ) external {
                // setupOwners checks if the Threshold is already set, therefore preventing that this method is called twice
                setupOwners(_owners, _threshold);
                if (fallbackHandler != address(0)) internalSetFallbackHandler(fallbackHandler);
                // As setupOwners can only be called if the contract has not been initialized we don't need a check for setupModules
                setupModules(to, data);
                if (payment > 0) {
                    // To avoid running into issues with EIP-170 we reuse the handlePayment function (to avoid adjusting code of that has been verified we do not adjust the method itself)
                    // baseGas = 0, gasPrice = 1 and gas = payment => amount = (payment + 0) * 1 = payment
                    handlePayment(payment, 0, 1, paymentToken, paymentReceiver);
                }
                emit SafeSetup(msg.sender, _owners, _threshold, to, fallbackHandler);
            }
            /// @dev Allows to execute a Safe transaction confirmed by required number of owners and then pays the account that submitted the transaction.
            ///      Note: The fees are always transferred, even if the user transaction fails.
            /// @param to Destination address of Safe transaction.
            /// @param value Ether value of Safe transaction.
            /// @param data Data payload of Safe transaction.
            /// @param operation Operation type of Safe transaction.
            /// @param safeTxGas Gas that should be used for the Safe transaction.
            /// @param baseGas Gas costs that are independent of the transaction execution(e.g. base transaction fee, signature check, payment of the refund)
            /// @param gasPrice Gas price that should be used for the payment calculation.
            /// @param gasToken Token address (or 0 if ETH) that is used for the payment.
            /// @param refundReceiver Address of receiver of gas payment (or 0 if tx.origin).
            /// @param signatures Packed signature data ({bytes32 r}{bytes32 s}{uint8 v})
            function execTransaction(
                address to,
                uint256 value,
                bytes calldata data,
                Enum.Operation operation,
                uint256 safeTxGas,
                uint256 baseGas,
                uint256 gasPrice,
                address gasToken,
                address payable refundReceiver,
                bytes memory signatures
            ) public payable virtual returns (bool success) {
                bytes32 txHash;
                // Use scope here to limit variable lifetime and prevent `stack too deep` errors
                {
                    bytes memory txHashData =
                        encodeTransactionData(
                            // Transaction info
                            to,
                            value,
                            data,
                            operation,
                            safeTxGas,
                            // Payment info
                            baseGas,
                            gasPrice,
                            gasToken,
                            refundReceiver,
                            // Signature info
                            nonce
                        );
                    // Increase nonce and execute transaction.
                    nonce++;
                    txHash = keccak256(txHashData);
                    checkSignatures(txHash, txHashData, signatures);
                }
                address guard = getGuard();
                {
                    if (guard != address(0)) {
                        Guard(guard).checkTransaction(
                            // Transaction info
                            to,
                            value,
                            data,
                            operation,
                            safeTxGas,
                            // Payment info
                            baseGas,
                            gasPrice,
                            gasToken,
                            refundReceiver,
                            // Signature info
                            signatures,
                            msg.sender
                        );
                    }
                }
                // We require some gas to emit the events (at least 2500) after the execution and some to perform code until the execution (500)
                // We also include the 1/64 in the check that is not send along with a call to counteract potential shortings because of EIP-150
                require(gasleft() >= ((safeTxGas * 64) / 63).max(safeTxGas + 2500) + 500, "GS010");
                // Use scope here to limit variable lifetime and prevent `stack too deep` errors
                {
                    uint256 gasUsed = gasleft();
                    // If the gasPrice is 0 we assume that nearly all available gas can be used (it is always more than safeTxGas)
                    // We only substract 2500 (compared to the 3000 before) to ensure that the amount passed is still higher than safeTxGas
                    success = execute(to, value, data, operation, gasPrice == 0 ? (gasleft() - 2500) : safeTxGas);
                    gasUsed = gasUsed.sub(gasleft());
                    // If no safeTxGas and no gasPrice was set (e.g. both are 0), then the internal tx is required to be successful
                    // This makes it possible to use `estimateGas` without issues, as it searches for the minimum gas where the tx doesn't revert
                    require(success || safeTxGas != 0 || gasPrice != 0, "GS013");
                    // We transfer the calculated tx costs to the tx.origin to avoid sending it to intermediate contracts that have made calls
                    uint256 payment = 0;
                    if (gasPrice > 0) {
                        payment = handlePayment(gasUsed, baseGas, gasPrice, gasToken, refundReceiver);
                    }
                    if (success) emit ExecutionSuccess(txHash, payment);
                    else emit ExecutionFailure(txHash, payment);
                }
                {
                    if (guard != address(0)) {
                        Guard(guard).checkAfterExecution(txHash, success);
                    }
                }
            }
            function handlePayment(
                uint256 gasUsed,
                uint256 baseGas,
                uint256 gasPrice,
                address gasToken,
                address payable refundReceiver
            ) private returns (uint256 payment) {
                // solhint-disable-next-line avoid-tx-origin
                address payable receiver = refundReceiver == address(0) ? payable(tx.origin) : refundReceiver;
                if (gasToken == address(0)) {
                    // For ETH we will only adjust the gas price to not be higher than the actual used gas price
                    payment = gasUsed.add(baseGas).mul(gasPrice < tx.gasprice ? gasPrice : tx.gasprice);
                    require(receiver.send(payment), "GS011");
                } else {
                    payment = gasUsed.add(baseGas).mul(gasPrice);
                    require(transferToken(gasToken, receiver, payment), "GS012");
                }
            }
            /**
             * @dev Checks whether the signature provided is valid for the provided data, hash. Will revert otherwise.
             * @param dataHash Hash of the data (could be either a message hash or transaction hash)
             * @param data That should be signed (this is passed to an external validator contract)
             * @param signatures Signature data that should be verified. Can be ECDSA signature, contract signature (EIP-1271) or approved hash.
             */
            function checkSignatures(
                bytes32 dataHash,
                bytes memory data,
                bytes memory signatures
            ) public view {
                // Load threshold to avoid multiple storage loads
                uint256 _threshold = threshold;
                // Check that a threshold is set
                require(_threshold > 0, "GS001");
                checkNSignatures(dataHash, data, signatures, _threshold);
            }
            /**
             * @dev Checks whether the signature provided is valid for the provided data, hash. Will revert otherwise.
             * @param dataHash Hash of the data (could be either a message hash or transaction hash)
             * @param data That should be signed (this is passed to an external validator contract)
             * @param signatures Signature data that should be verified. Can be ECDSA signature, contract signature (EIP-1271) or approved hash.
             * @param requiredSignatures Amount of required valid signatures.
             */
            function checkNSignatures(
                bytes32 dataHash,
                bytes memory data,
                bytes memory signatures,
                uint256 requiredSignatures
            ) public view {
                // Check that the provided signature data is not too short
                require(signatures.length >= requiredSignatures.mul(65), "GS020");
                // There cannot be an owner with address 0.
                address lastOwner = address(0);
                address currentOwner;
                uint8 v;
                bytes32 r;
                bytes32 s;
                uint256 i;
                for (i = 0; i < requiredSignatures; i++) {
                    (v, r, s) = signatureSplit(signatures, i);
                    if (v == 0) {
                        // If v is 0 then it is a contract signature
                        // When handling contract signatures the address of the contract is encoded into r
                        currentOwner = address(uint160(uint256(r)));
                        // Check that signature data pointer (s) is not pointing inside the static part of the signatures bytes
                        // This check is not completely accurate, since it is possible that more signatures than the threshold are send.
                        // Here we only check that the pointer is not pointing inside the part that is being processed
                        require(uint256(s) >= requiredSignatures.mul(65), "GS021");
                        // Check that signature data pointer (s) is in bounds (points to the length of data -> 32 bytes)
                        require(uint256(s).add(32) <= signatures.length, "GS022");
                        // Check if the contract signature is in bounds: start of data is s + 32 and end is start + signature length
                        uint256 contractSignatureLen;
                        // solhint-disable-next-line no-inline-assembly
                        assembly {
                            contractSignatureLen := mload(add(add(signatures, s), 0x20))
                        }
                        require(uint256(s).add(32).add(contractSignatureLen) <= signatures.length, "GS023");
                        // Check signature
                        bytes memory contractSignature;
                        // solhint-disable-next-line no-inline-assembly
                        assembly {
                            // The signature data for contract signatures is appended to the concatenated signatures and the offset is stored in s
                            contractSignature := add(add(signatures, s), 0x20)
                        }
                        require(ISignatureValidator(currentOwner).isValidSignature(data, contractSignature) == EIP1271_MAGIC_VALUE, "GS024");
                    } else if (v == 1) {
                        // If v is 1 then it is an approved hash
                        // When handling approved hashes the address of the approver is encoded into r
                        currentOwner = address(uint160(uint256(r)));
                        // Hashes are automatically approved by the sender of the message or when they have been pre-approved via a separate transaction
                        require(msg.sender == currentOwner || approvedHashes[currentOwner][dataHash] != 0, "GS025");
                    } else if (v > 30) {
                        // If v > 30 then default va (27,28) has been adjusted for eth_sign flow
                        // To support eth_sign and similar we adjust v and hash the messageHash with the Ethereum message prefix before applying ecrecover
                        currentOwner = ecrecover(keccak256(abi.encodePacked("\\x19Ethereum Signed Message:\
        32", dataHash)), v - 4, r, s);
                    } else {
                        // Default is the ecrecover flow with the provided data hash
                        // Use ecrecover with the messageHash for EOA signatures
                        currentOwner = ecrecover(dataHash, v, r, s);
                    }
                    require(currentOwner > lastOwner && owners[currentOwner] != address(0) && currentOwner != SENTINEL_OWNERS, "GS026");
                    lastOwner = currentOwner;
                }
            }
            /// @dev Allows to estimate a Safe transaction.
            ///      This method is only meant for estimation purpose, therefore the call will always revert and encode the result in the revert data.
            ///      Since the `estimateGas` function includes refunds, call this method to get an estimated of the costs that are deducted from the safe with `execTransaction`
            /// @param to Destination address of Safe transaction.
            /// @param value Ether value of Safe transaction.
            /// @param data Data payload of Safe transaction.
            /// @param operation Operation type of Safe transaction.
            /// @return Estimate without refunds and overhead fees (base transaction and payload data gas costs).
            /// @notice Deprecated in favor of common/StorageAccessible.sol and will be removed in next version.
            function requiredTxGas(
                address to,
                uint256 value,
                bytes calldata data,
                Enum.Operation operation
            ) external returns (uint256) {
                uint256 startGas = gasleft();
                // We don't provide an error message here, as we use it to return the estimate
                require(execute(to, value, data, operation, gasleft()));
                uint256 requiredGas = startGas - gasleft();
                // Convert response to string and return via error message
                revert(string(abi.encodePacked(requiredGas)));
            }
            /**
             * @dev Marks a hash as approved. This can be used to validate a hash that is used by a signature.
             * @param hashToApprove The hash that should be marked as approved for signatures that are verified by this contract.
             */
            function approveHash(bytes32 hashToApprove) external {
                require(owners[msg.sender] != address(0), "GS030");
                approvedHashes[msg.sender][hashToApprove] = 1;
                emit ApproveHash(hashToApprove, msg.sender);
            }
            /// @dev Returns the chain id used by this contract.
            function getChainId() public view returns (uint256) {
                uint256 id;
                // solhint-disable-next-line no-inline-assembly
                assembly {
                    id := chainid()
                }
                return id;
            }
            function domainSeparator() public view returns (bytes32) {
                return keccak256(abi.encode(DOMAIN_SEPARATOR_TYPEHASH, getChainId(), this));
            }
            /// @dev Returns the bytes that are hashed to be signed by owners.
            /// @param to Destination address.
            /// @param value Ether value.
            /// @param data Data payload.
            /// @param operation Operation type.
            /// @param safeTxGas Gas that should be used for the safe transaction.
            /// @param baseGas Gas costs for that are independent of the transaction execution(e.g. base transaction fee, signature check, payment of the refund)
            /// @param gasPrice Maximum gas price that should be used for this transaction.
            /// @param gasToken Token address (or 0 if ETH) that is used for the payment.
            /// @param refundReceiver Address of receiver of gas payment (or 0 if tx.origin).
            /// @param _nonce Transaction nonce.
            /// @return Transaction hash bytes.
            function encodeTransactionData(
                address to,
                uint256 value,
                bytes calldata data,
                Enum.Operation operation,
                uint256 safeTxGas,
                uint256 baseGas,
                uint256 gasPrice,
                address gasToken,
                address refundReceiver,
                uint256 _nonce
            ) public view returns (bytes memory) {
                bytes32 safeTxHash =
                    keccak256(
                        abi.encode(
                            SAFE_TX_TYPEHASH,
                            to,
                            value,
                            keccak256(data),
                            operation,
                            safeTxGas,
                            baseGas,
                            gasPrice,
                            gasToken,
                            refundReceiver,
                            _nonce
                        )
                    );
                return abi.encodePacked(bytes1(0x19), bytes1(0x01), domainSeparator(), safeTxHash);
            }
            /// @dev Returns hash to be signed by owners.
            /// @param to Destination address.
            /// @param value Ether value.
            /// @param data Data payload.
            /// @param operation Operation type.
            /// @param safeTxGas Fas that should be used for the safe transaction.
            /// @param baseGas Gas costs for data used to trigger the safe transaction.
            /// @param gasPrice Maximum gas price that should be used for this transaction.
            /// @param gasToken Token address (or 0 if ETH) that is used for the payment.
            /// @param refundReceiver Address of receiver of gas payment (or 0 if tx.origin).
            /// @param _nonce Transaction nonce.
            /// @return Transaction hash.
            function getTransactionHash(
                address to,
                uint256 value,
                bytes calldata data,
                Enum.Operation operation,
                uint256 safeTxGas,
                uint256 baseGas,
                uint256 gasPrice,
                address gasToken,
                address refundReceiver,
                uint256 _nonce
            ) public view returns (bytes32) {
                return keccak256(encodeTransactionData(to, value, data, operation, safeTxGas, baseGas, gasPrice, gasToken, refundReceiver, _nonce));
            }
        }
        // SPDX-License-Identifier: LGPL-3.0-only
        pragma solidity >=0.7.0 <0.9.0;
        import "../common/Enum.sol";
        /// @title Executor - A contract that can execute transactions
        /// @author Richard Meissner - <[email protected]>
        contract Executor {
            function execute(
                address to,
                uint256 value,
                bytes memory data,
                Enum.Operation operation,
                uint256 txGas
            ) internal returns (bool success) {
                if (operation == Enum.Operation.DelegateCall) {
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        success := delegatecall(txGas, to, add(data, 0x20), mload(data), 0, 0)
                    }
                } else {
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        success := call(txGas, to, value, add(data, 0x20), mload(data), 0, 0)
                    }
                }
            }
        }
        // SPDX-License-Identifier: LGPL-3.0-only
        pragma solidity >=0.7.0 <0.9.0;
        import "../common/SelfAuthorized.sol";
        /// @title Fallback Manager - A contract that manages fallback calls made to this contract
        /// @author Richard Meissner - <[email protected]>
        contract FallbackManager is SelfAuthorized {
            event ChangedFallbackHandler(address handler);
            // keccak256("fallback_manager.handler.address")
            bytes32 internal constant FALLBACK_HANDLER_STORAGE_SLOT = 0x6c9a6c4a39284e37ed1cf53d337577d14212a4870fb976a4366c693b939918d5;
            function internalSetFallbackHandler(address handler) internal {
                bytes32 slot = FALLBACK_HANDLER_STORAGE_SLOT;
                // solhint-disable-next-line no-inline-assembly
                assembly {
                    sstore(slot, handler)
                }
            }
            /// @dev Allows to add a contract to handle fallback calls.
            ///      Only fallback calls without value and with data will be forwarded.
            ///      This can only be done via a Safe transaction.
            /// @param handler contract to handle fallbacks calls.
            function setFallbackHandler(address handler) public authorized {
                internalSetFallbackHandler(handler);
                emit ChangedFallbackHandler(handler);
            }
            // solhint-disable-next-line payable-fallback,no-complex-fallback
            fallback() external {
                bytes32 slot = FALLBACK_HANDLER_STORAGE_SLOT;
                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let handler := sload(slot)
                    if iszero(handler) {
                        return(0, 0)
                    }
                    calldatacopy(0, 0, calldatasize())
                    // The msg.sender address is shifted to the left by 12 bytes to remove the padding
                    // Then the address without padding is stored right after the calldata
                    mstore(calldatasize(), shl(96, caller()))
                    // Add 20 bytes for the address appended add the end
                    let success := call(gas(), handler, 0, 0, add(calldatasize(), 20), 0, 0)
                    returndatacopy(0, 0, returndatasize())
                    if iszero(success) {
                        revert(0, returndatasize())
                    }
                    return(0, returndatasize())
                }
            }
        }
        // SPDX-License-Identifier: LGPL-3.0-only
        pragma solidity >=0.7.0 <0.9.0;
        import "../common/Enum.sol";
        import "../common/SelfAuthorized.sol";
        interface Guard {
            function checkTransaction(
                address to,
                uint256 value,
                bytes memory data,
                Enum.Operation operation,
                uint256 safeTxGas,
                uint256 baseGas,
                uint256 gasPrice,
                address gasToken,
                address payable refundReceiver,
                bytes memory signatures,
                address msgSender
            ) external;
            function checkAfterExecution(bytes32 txHash, bool success) external;
        }
        /// @title Fallback Manager - A contract that manages fallback calls made to this contract
        /// @author Richard Meissner - <[email protected]>
        contract GuardManager is SelfAuthorized {
            event ChangedGuard(address guard);
            // keccak256("guard_manager.guard.address")
            bytes32 internal constant GUARD_STORAGE_SLOT = 0x4a204f620c8c5ccdca3fd54d003badd85ba500436a431f0cbda4f558c93c34c8;
            /// @dev Set a guard that checks transactions before execution
            /// @param guard The address of the guard to be used or the 0 address to disable the guard
            function setGuard(address guard) external authorized {
                bytes32 slot = GUARD_STORAGE_SLOT;
                // solhint-disable-next-line no-inline-assembly
                assembly {
                    sstore(slot, guard)
                }
                emit ChangedGuard(guard);
            }
            function getGuard() internal view returns (address guard) {
                bytes32 slot = GUARD_STORAGE_SLOT;
                // solhint-disable-next-line no-inline-assembly
                assembly {
                    guard := sload(slot)
                }
            }
        }
        // SPDX-License-Identifier: LGPL-3.0-only
        pragma solidity >=0.7.0 <0.9.0;
        import "../common/Enum.sol";
        import "../common/SelfAuthorized.sol";
        import "./Executor.sol";
        /// @title Module Manager - A contract that manages modules that can execute transactions via this contract
        /// @author Stefan George - <[email protected]>
        /// @author Richard Meissner - <[email protected]>
        contract ModuleManager is SelfAuthorized, Executor {
            event EnabledModule(address module);
            event DisabledModule(address module);
            event ExecutionFromModuleSuccess(address indexed module);
            event ExecutionFromModuleFailure(address indexed module);
            address internal constant SENTINEL_MODULES = address(0x1);
            mapping(address => address) internal modules;
            function setupModules(address to, bytes memory data) internal {
                require(modules[SENTINEL_MODULES] == address(0), "GS100");
                modules[SENTINEL_MODULES] = SENTINEL_MODULES;
                if (to != address(0))
                    // Setup has to complete successfully or transaction fails.
                    require(execute(to, 0, data, Enum.Operation.DelegateCall, gasleft()), "GS000");
            }
            /// @dev Allows to add a module to the whitelist.
            ///      This can only be done via a Safe transaction.
            /// @notice Enables the module `module` for the Safe.
            /// @param module Module to be whitelisted.
            function enableModule(address module) public authorized {
                // Module address cannot be null or sentinel.
                require(module != address(0) && module != SENTINEL_MODULES, "GS101");
                // Module cannot be added twice.
                require(modules[module] == address(0), "GS102");
                modules[module] = modules[SENTINEL_MODULES];
                modules[SENTINEL_MODULES] = module;
                emit EnabledModule(module);
            }
            /// @dev Allows to remove a module from the whitelist.
            ///      This can only be done via a Safe transaction.
            /// @notice Disables the module `module` for the Safe.
            /// @param prevModule Module that pointed to the module to be removed in the linked list
            /// @param module Module to be removed.
            function disableModule(address prevModule, address module) public authorized {
                // Validate module address and check that it corresponds to module index.
                require(module != address(0) && module != SENTINEL_MODULES, "GS101");
                require(modules[prevModule] == module, "GS103");
                modules[prevModule] = modules[module];
                modules[module] = address(0);
                emit DisabledModule(module);
            }
            /// @dev Allows a Module to execute a Safe transaction without any further confirmations.
            /// @param to Destination address of module transaction.
            /// @param value Ether value of module transaction.
            /// @param data Data payload of module transaction.
            /// @param operation Operation type of module transaction.
            function execTransactionFromModule(
                address to,
                uint256 value,
                bytes memory data,
                Enum.Operation operation
            ) public virtual returns (bool success) {
                // Only whitelisted modules are allowed.
                require(msg.sender != SENTINEL_MODULES && modules[msg.sender] != address(0), "GS104");
                // Execute transaction without further confirmations.
                success = execute(to, value, data, operation, gasleft());
                if (success) emit ExecutionFromModuleSuccess(msg.sender);
                else emit ExecutionFromModuleFailure(msg.sender);
            }
            /// @dev Allows a Module to execute a Safe transaction without any further confirmations and return data
            /// @param to Destination address of module transaction.
            /// @param value Ether value of module transaction.
            /// @param data Data payload of module transaction.
            /// @param operation Operation type of module transaction.
            function execTransactionFromModuleReturnData(
                address to,
                uint256 value,
                bytes memory data,
                Enum.Operation operation
            ) public returns (bool success, bytes memory returnData) {
                success = execTransactionFromModule(to, value, data, operation);
                // solhint-disable-next-line no-inline-assembly
                assembly {
                    // Load free memory location
                    let ptr := mload(0x40)
                    // We allocate memory for the return data by setting the free memory location to
                    // current free memory location + data size + 32 bytes for data size value
                    mstore(0x40, add(ptr, add(returndatasize(), 0x20)))
                    // Store the size
                    mstore(ptr, returndatasize())
                    // Store the data
                    returndatacopy(add(ptr, 0x20), 0, returndatasize())
                    // Point the return data to the correct memory location
                    returnData := ptr
                }
            }
            /// @dev Returns if an module is enabled
            /// @return True if the module is enabled
            function isModuleEnabled(address module) public view returns (bool) {
                return SENTINEL_MODULES != module && modules[module] != address(0);
            }
            /// @dev Returns array of modules.
            /// @param start Start of the page.
            /// @param pageSize Maximum number of modules that should be returned.
            /// @return array Array of modules.
            /// @return next Start of the next page.
            function getModulesPaginated(address start, uint256 pageSize) external view returns (address[] memory array, address next) {
                // Init array with max page size
                array = new address[](pageSize);
                // Populate return array
                uint256 moduleCount = 0;
                address currentModule = modules[start];
                while (currentModule != address(0x0) && currentModule != SENTINEL_MODULES && moduleCount < pageSize) {
                    array[moduleCount] = currentModule;
                    currentModule = modules[currentModule];
                    moduleCount++;
                }
                next = currentModule;
                // Set correct size of returned array
                // solhint-disable-next-line no-inline-assembly
                assembly {
                    mstore(array, moduleCount)
                }
            }
        }
        // SPDX-License-Identifier: LGPL-3.0-only
        pragma solidity >=0.7.0 <0.9.0;
        import "../common/SelfAuthorized.sol";
        /// @title OwnerManager - Manages a set of owners and a threshold to perform actions.
        /// @author Stefan George - <[email protected]>
        /// @author Richard Meissner - <[email protected]>
        contract OwnerManager is SelfAuthorized {
            event AddedOwner(address owner);
            event RemovedOwner(address owner);
            event ChangedThreshold(uint256 threshold);
            address internal constant SENTINEL_OWNERS = address(0x1);
            mapping(address => address) internal owners;
            uint256 internal ownerCount;
            uint256 internal threshold;
            /// @dev Setup function sets initial storage of contract.
            /// @param _owners List of Safe owners.
            /// @param _threshold Number of required confirmations for a Safe transaction.
            function setupOwners(address[] memory _owners, uint256 _threshold) internal {
                // Threshold can only be 0 at initialization.
                // Check ensures that setup function can only be called once.
                require(threshold == 0, "GS200");
                // Validate that threshold is smaller than number of added owners.
                require(_threshold <= _owners.length, "GS201");
                // There has to be at least one Safe owner.
                require(_threshold >= 1, "GS202");
                // Initializing Safe owners.
                address currentOwner = SENTINEL_OWNERS;
                for (uint256 i = 0; i < _owners.length; i++) {
                    // Owner address cannot be null.
                    address owner = _owners[i];
                    require(owner != address(0) && owner != SENTINEL_OWNERS && owner != address(this) && currentOwner != owner, "GS203");
                    // No duplicate owners allowed.
                    require(owners[owner] == address(0), "GS204");
                    owners[currentOwner] = owner;
                    currentOwner = owner;
                }
                owners[currentOwner] = SENTINEL_OWNERS;
                ownerCount = _owners.length;
                threshold = _threshold;
            }
            /// @dev Allows to add a new owner to the Safe and update the threshold at the same time.
            ///      This can only be done via a Safe transaction.
            /// @notice Adds the owner `owner` to the Safe and updates the threshold to `_threshold`.
            /// @param owner New owner address.
            /// @param _threshold New threshold.
            function addOwnerWithThreshold(address owner, uint256 _threshold) public authorized {
                // Owner address cannot be null, the sentinel or the Safe itself.
                require(owner != address(0) && owner != SENTINEL_OWNERS && owner != address(this), "GS203");
                // No duplicate owners allowed.
                require(owners[owner] == address(0), "GS204");
                owners[owner] = owners[SENTINEL_OWNERS];
                owners[SENTINEL_OWNERS] = owner;
                ownerCount++;
                emit AddedOwner(owner);
                // Change threshold if threshold was changed.
                if (threshold != _threshold) changeThreshold(_threshold);
            }
            /// @dev Allows to remove an owner from the Safe and update the threshold at the same time.
            ///      This can only be done via a Safe transaction.
            /// @notice Removes the owner `owner` from the Safe and updates the threshold to `_threshold`.
            /// @param prevOwner Owner that pointed to the owner to be removed in the linked list
            /// @param owner Owner address to be removed.
            /// @param _threshold New threshold.
            function removeOwner(
                address prevOwner,
                address owner,
                uint256 _threshold
            ) public authorized {
                // Only allow to remove an owner, if threshold can still be reached.
                require(ownerCount - 1 >= _threshold, "GS201");
                // Validate owner address and check that it corresponds to owner index.
                require(owner != address(0) && owner != SENTINEL_OWNERS, "GS203");
                require(owners[prevOwner] == owner, "GS205");
                owners[prevOwner] = owners[owner];
                owners[owner] = address(0);
                ownerCount--;
                emit RemovedOwner(owner);
                // Change threshold if threshold was changed.
                if (threshold != _threshold) changeThreshold(_threshold);
            }
            /// @dev Allows to swap/replace an owner from the Safe with another address.
            ///      This can only be done via a Safe transaction.
            /// @notice Replaces the owner `oldOwner` in the Safe with `newOwner`.
            /// @param prevOwner Owner that pointed to the owner to be replaced in the linked list
            /// @param oldOwner Owner address to be replaced.
            /// @param newOwner New owner address.
            function swapOwner(
                address prevOwner,
                address oldOwner,
                address newOwner
            ) public authorized {
                // Owner address cannot be null, the sentinel or the Safe itself.
                require(newOwner != address(0) && newOwner != SENTINEL_OWNERS && newOwner != address(this), "GS203");
                // No duplicate owners allowed.
                require(owners[newOwner] == address(0), "GS204");
                // Validate oldOwner address and check that it corresponds to owner index.
                require(oldOwner != address(0) && oldOwner != SENTINEL_OWNERS, "GS203");
                require(owners[prevOwner] == oldOwner, "GS205");
                owners[newOwner] = owners[oldOwner];
                owners[prevOwner] = newOwner;
                owners[oldOwner] = address(0);
                emit RemovedOwner(oldOwner);
                emit AddedOwner(newOwner);
            }
            /// @dev Allows to update the number of required confirmations by Safe owners.
            ///      This can only be done via a Safe transaction.
            /// @notice Changes the threshold of the Safe to `_threshold`.
            /// @param _threshold New threshold.
            function changeThreshold(uint256 _threshold) public authorized {
                // Validate that threshold is smaller than number of owners.
                require(_threshold <= ownerCount, "GS201");
                // There has to be at least one Safe owner.
                require(_threshold >= 1, "GS202");
                threshold = _threshold;
                emit ChangedThreshold(threshold);
            }
            function getThreshold() public view returns (uint256) {
                return threshold;
            }
            function isOwner(address owner) public view returns (bool) {
                return owner != SENTINEL_OWNERS && owners[owner] != address(0);
            }
            /// @dev Returns array of owners.
            /// @return Array of Safe owners.
            function getOwners() public view returns (address[] memory) {
                address[] memory array = new address[](ownerCount);
                // populate return array
                uint256 index = 0;
                address currentOwner = owners[SENTINEL_OWNERS];
                while (currentOwner != SENTINEL_OWNERS) {
                    array[index] = currentOwner;
                    currentOwner = owners[currentOwner];
                    index++;
                }
                return array;
            }
        }
        // SPDX-License-Identifier: LGPL-3.0-only
        pragma solidity >=0.7.0 <0.9.0;
        /// @title Enum - Collection of enums
        /// @author Richard Meissner - <[email protected]>
        contract Enum {
            enum Operation {Call, DelegateCall}
        }
        // SPDX-License-Identifier: LGPL-3.0-only
        pragma solidity >=0.7.0 <0.9.0;
        /// @title EtherPaymentFallback - A contract that has a fallback to accept ether payments
        /// @author Richard Meissner - <[email protected]>
        contract EtherPaymentFallback {
            event SafeReceived(address indexed sender, uint256 value);
            /// @dev Fallback function accepts Ether transactions.
            receive() external payable {
                emit SafeReceived(msg.sender, msg.value);
            }
        }
        // SPDX-License-Identifier: LGPL-3.0-only
        pragma solidity >=0.7.0 <0.9.0;
        /// @title SecuredTokenTransfer - Secure token transfer
        /// @author Richard Meissner - <[email protected]>
        contract SecuredTokenTransfer {
            /// @dev Transfers a token and returns if it was a success
            /// @param token Token that should be transferred
            /// @param receiver Receiver to whom the token should be transferred
            /// @param amount The amount of tokens that should be transferred
            function transferToken(
                address token,
                address receiver,
                uint256 amount
            ) internal returns (bool transferred) {
                // 0xa9059cbb - keccack("transfer(address,uint256)")
                bytes memory data = abi.encodeWithSelector(0xa9059cbb, receiver, amount);
                // solhint-disable-next-line no-inline-assembly
                assembly {
                    // We write the return value to scratch space.
                    // See https://docs.soliditylang.org/en/v0.7.6/internals/layout_in_memory.html#layout-in-memory
                    let success := call(sub(gas(), 10000), token, 0, add(data, 0x20), mload(data), 0, 0x20)
                    switch returndatasize()
                        case 0 {
                            transferred := success
                        }
                        case 0x20 {
                            transferred := iszero(or(iszero(success), iszero(mload(0))))
                        }
                        default {
                            transferred := 0
                        }
                }
            }
        }
        // SPDX-License-Identifier: LGPL-3.0-only
        pragma solidity >=0.7.0 <0.9.0;
        /// @title SelfAuthorized - authorizes current contract to perform actions
        /// @author Richard Meissner - <[email protected]>
        contract SelfAuthorized {
            function requireSelfCall() private view {
                require(msg.sender == address(this), "GS031");
            }
            modifier authorized() {
                // This is a function call as it minimized the bytecode size
                requireSelfCall();
                _;
            }
        }
        // SPDX-License-Identifier: LGPL-3.0-only
        pragma solidity >=0.7.0 <0.9.0;
        /// @title SignatureDecoder - Decodes signatures that a encoded as bytes
        /// @author Richard Meissner - <[email protected]>
        contract SignatureDecoder {
            /// @dev divides bytes signature into `uint8 v, bytes32 r, bytes32 s`.
            /// @notice Make sure to peform a bounds check for @param pos, to avoid out of bounds access on @param signatures
            /// @param pos which signature to read. A prior bounds check of this parameter should be performed, to avoid out of bounds access
            /// @param signatures concatenated rsv signatures
            function signatureSplit(bytes memory signatures, uint256 pos)
                internal
                pure
                returns (
                    uint8 v,
                    bytes32 r,
                    bytes32 s
                )
            {
                // The signature format is a compact form of:
                //   {bytes32 r}{bytes32 s}{uint8 v}
                // Compact means, uint8 is not padded to 32 bytes.
                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let signaturePos := mul(0x41, pos)
                    r := mload(add(signatures, add(signaturePos, 0x20)))
                    s := mload(add(signatures, add(signaturePos, 0x40)))
                    // Here we are loading the last 32 bytes, including 31 bytes
                    // of 's'. There is no 'mload8' to do this.
                    //
                    // 'byte' is not working due to the Solidity parser, so lets
                    // use the second best option, 'and'
                    v := and(mload(add(signatures, add(signaturePos, 0x41))), 0xff)
                }
            }
        }
        // SPDX-License-Identifier: LGPL-3.0-only
        pragma solidity >=0.7.0 <0.9.0;
        /// @title Singleton - Base for singleton contracts (should always be first super contract)
        ///         This contract is tightly coupled to our proxy contract (see `proxies/GnosisSafeProxy.sol`)
        /// @author Richard Meissner - <[email protected]>
        contract Singleton {
            // singleton always needs to be first declared variable, to ensure that it is at the same location as in the Proxy contract.
            // It should also always be ensured that the address is stored alone (uses a full word)
            address private singleton;
        }
        // SPDX-License-Identifier: LGPL-3.0-only
        pragma solidity >=0.7.0 <0.9.0;
        /// @title StorageAccessible - generic base contract that allows callers to access all internal storage.
        /// @notice See https://github.com/gnosis/util-contracts/blob/bb5fe5fb5df6d8400998094fb1b32a178a47c3a1/contracts/StorageAccessible.sol
        contract StorageAccessible {
            /**
             * @dev Reads `length` bytes of storage in the currents contract
             * @param offset - the offset in the current contract's storage in words to start reading from
             * @param length - the number of words (32 bytes) of data to read
             * @return the bytes that were read.
             */
            function getStorageAt(uint256 offset, uint256 length) public view returns (bytes memory) {
                bytes memory result = new bytes(length * 32);
                for (uint256 index = 0; index < length; index++) {
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        let word := sload(add(offset, index))
                        mstore(add(add(result, 0x20), mul(index, 0x20)), word)
                    }
                }
                return result;
            }
            /**
             * @dev Performs a delegetecall on a targetContract in the context of self.
             * Internally reverts execution to avoid side effects (making it static).
             *
             * This method reverts with data equal to `abi.encode(bool(success), bytes(response))`.
             * Specifically, the `returndata` after a call to this method will be:
             * `success:bool || response.length:uint256 || response:bytes`.
             *
             * @param targetContract Address of the contract containing the code to execute.
             * @param calldataPayload Calldata that should be sent to the target contract (encoded method name and arguments).
             */
            function simulateAndRevert(address targetContract, bytes memory calldataPayload) external {
                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let success := delegatecall(gas(), targetContract, add(calldataPayload, 0x20), mload(calldataPayload), 0, 0)
                    mstore(0x00, success)
                    mstore(0x20, returndatasize())
                    returndatacopy(0x40, 0, returndatasize())
                    revert(0, add(returndatasize(), 0x40))
                }
            }
        }
        // SPDX-License-Identifier: LGPL-3.0-only
        pragma solidity >=0.7.0 <0.9.0;
        /**
         * @title GnosisSafeMath
         * @dev Math operations with safety checks that revert on error
         * Renamed from SafeMath to GnosisSafeMath to avoid conflicts
         * TODO: remove once open zeppelin update to solc 0.5.0
         */
        library GnosisSafeMath {
            /**
             * @dev Multiplies two numbers, reverts on overflow.
             */
            function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                // benefit is lost if 'b' is also tested.
                // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
                if (a == 0) {
                    return 0;
                }
                uint256 c = a * b;
                require(c / a == b);
                return c;
            }
            /**
             * @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).
             */
            function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                require(b <= a);
                uint256 c = a - b;
                return c;
            }
            /**
             * @dev Adds two numbers, reverts on overflow.
             */
            function add(uint256 a, uint256 b) internal pure returns (uint256) {
                uint256 c = a + b;
                require(c >= a);
                return c;
            }
            /**
             * @dev Returns the largest of two numbers.
             */
            function max(uint256 a, uint256 b) internal pure returns (uint256) {
                return a >= b ? a : b;
            }
        }
        // SPDX-License-Identifier: LGPL-3.0-only
        pragma solidity >=0.7.0 <0.9.0;
        contract ISignatureValidatorConstants {
            // bytes4(keccak256("isValidSignature(bytes,bytes)")
            bytes4 internal constant EIP1271_MAGIC_VALUE = 0x20c13b0b;
        }
        abstract contract ISignatureValidator is ISignatureValidatorConstants {
            /**
             * @dev Should return whether the signature provided is valid for the provided data
             * @param _data Arbitrary length data signed on the behalf of address(this)
             * @param _signature Signature byte array associated with _data
             *
             * MUST return the bytes4 magic value 0x20c13b0b when function passes.
             * MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5)
             * MUST allow external calls
             */
            function isValidSignature(bytes memory _data, bytes memory _signature) public view virtual returns (bytes4);
        }
        

        File 4 of 4: AToken
        // SPDX-License-Identifier: LGPL-3.0-or-later
        pragma solidity 0.8.10;
        import {IERC20} from '../../openzeppelin/contracts/IERC20.sol';
        /// @title Gnosis Protocol v2 Safe ERC20 Transfer Library
        /// @author Gnosis Developers
        /// @dev Gas-efficient version of Openzeppelin's SafeERC20 contract.
        library GPv2SafeERC20 {
          /// @dev Wrapper around a call to the ERC20 function `transfer` that reverts
          /// also when the token returns `false`.
          function safeTransfer(
            IERC20 token,
            address to,
            uint256 value
          ) internal {
            bytes4 selector_ = token.transfer.selector;
            // solhint-disable-next-line no-inline-assembly
            assembly {
              let freeMemoryPointer := mload(0x40)
              mstore(freeMemoryPointer, selector_)
              mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff))
              mstore(add(freeMemoryPointer, 36), value)
              if iszero(call(gas(), token, 0, freeMemoryPointer, 68, 0, 0)) {
                returndatacopy(0, 0, returndatasize())
                revert(0, returndatasize())
              }
            }
            require(getLastTransferResult(token), 'GPv2: failed transfer');
          }
          /// @dev Wrapper around a call to the ERC20 function `transferFrom` that
          /// reverts also when the token returns `false`.
          function safeTransferFrom(
            IERC20 token,
            address from,
            address to,
            uint256 value
          ) internal {
            bytes4 selector_ = token.transferFrom.selector;
            // solhint-disable-next-line no-inline-assembly
            assembly {
              let freeMemoryPointer := mload(0x40)
              mstore(freeMemoryPointer, selector_)
              mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff))
              mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff))
              mstore(add(freeMemoryPointer, 68), value)
              if iszero(call(gas(), token, 0, freeMemoryPointer, 100, 0, 0)) {
                returndatacopy(0, 0, returndatasize())
                revert(0, returndatasize())
              }
            }
            require(getLastTransferResult(token), 'GPv2: failed transferFrom');
          }
          /// @dev Verifies that the last return was a successful `transfer*` call.
          /// This is done by checking that the return data is either empty, or
          /// is a valid ABI encoded boolean.
          function getLastTransferResult(IERC20 token) private view returns (bool success) {
            // NOTE: Inspecting previous return data requires assembly. Note that
            // we write the return data to memory 0 in the case where the return
            // data size is 32, this is OK since the first 64 bytes of memory are
            // reserved by Solidy as a scratch space that can be used within
            // assembly blocks.
            // <https://docs.soliditylang.org/en/v0.7.6/internals/layout_in_memory.html>
            // solhint-disable-next-line no-inline-assembly
            assembly {
              /// @dev Revert with an ABI encoded Solidity error with a message
              /// that fits into 32-bytes.
              ///
              /// An ABI encoded Solidity error has the following memory layout:
              ///
              /// ------------+----------------------------------
              ///  byte range | value
              /// ------------+----------------------------------
              ///  0x00..0x04 |        selector("Error(string)")
              ///  0x04..0x24 |      string offset (always 0x20)
              ///  0x24..0x44 |                    string length
              ///  0x44..0x64 | string value, padded to 32-bytes
              function revertWithMessage(length, message) {
                mstore(0x00, '\\x08\\xc3\\x79\\xa0')
                mstore(0x04, 0x20)
                mstore(0x24, length)
                mstore(0x44, message)
                revert(0x00, 0x64)
              }
              switch returndatasize()
              // Non-standard ERC20 transfer without return.
              case 0 {
                // NOTE: When the return data size is 0, verify that there
                // is code at the address. This is done in order to maintain
                // compatibility with Solidity calling conventions.
                // <https://docs.soliditylang.org/en/v0.7.6/control-structures.html#external-function-calls>
                if iszero(extcodesize(token)) {
                  revertWithMessage(20, 'GPv2: not a contract')
                }
                success := 1
              }
              // Standard ERC20 transfer returning boolean success value.
              case 32 {
                returndatacopy(0, 0, returndatasize())
                // NOTE: For ABI encoding v1, any non-zero value is accepted
                // as `true` for a boolean. In order to stay compatible with
                // OpenZeppelin's `SafeERC20` library which is known to work
                // with the existing ERC20 implementation we care about,
                // make sure we return success for any non-zero return value
                // from the `transfer*` call.
                success := iszero(iszero(mload(0)))
              }
              default {
                revertWithMessage(31, 'GPv2: malformed transfer result')
              }
            }
          }
        }
        // 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: AGPL-3.0
        pragma solidity 0.8.10;
        /**
         * @dev Interface of the ERC20 standard as defined in the EIP.
         */
        interface IERC20 {
          /**
           * @dev Returns the amount of tokens in existence.
           */
          function totalSupply() external view returns (uint256);
          /**
           * @dev Returns the amount of tokens owned by `account`.
           */
          function balanceOf(address account) external view returns (uint256);
          /**
           * @dev Moves `amount` tokens from the caller's account to `recipient`.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * Emits a {Transfer} event.
           */
          function transfer(address recipient, uint256 amount) external returns (bool);
          /**
           * @dev Returns the remaining number of tokens that `spender` will be
           * allowed to spend on behalf of `owner` through {transferFrom}. This is
           * zero by default.
           *
           * This value changes when {approve} or {transferFrom} are called.
           */
          function allowance(address owner, address spender) external view returns (uint256);
          /**
           * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * IMPORTANT: Beware that changing an allowance with this method brings the risk
           * that someone may use both the old and the new allowance by unfortunate
           * transaction ordering. One possible solution to mitigate this race
           * condition is to first reduce the spender's allowance to 0 and set the
           * desired value afterwards:
           * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
           *
           * Emits an {Approval} event.
           */
          function approve(address spender, uint256 amount) external returns (bool);
          /**
           * @dev Moves `amount` tokens from `sender` to `recipient` using the
           * allowance mechanism. `amount` is then deducted from the caller's
           * allowance.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * Emits a {Transfer} event.
           */
          function transferFrom(
            address sender,
            address recipient,
            uint256 amount
          ) external returns (bool);
          /**
           * @dev Emitted when `value` tokens are moved from one account (`from`) to
           * another (`to`).
           *
           * Note that `value` may be zero.
           */
          event Transfer(address indexed from, address indexed to, uint256 value);
          /**
           * @dev Emitted when the allowance of a `spender` for an `owner` is set by
           * a call to {approve}. `value` is the new allowance.
           */
          event Approval(address indexed owner, address indexed spender, uint256 value);
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.8.10;
        import {IERC20} from './IERC20.sol';
        interface IERC20Detailed is IERC20 {
          function name() external view returns (string memory);
          function symbol() external view returns (string memory);
          function decimals() external view returns (uint8);
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol)
        pragma solidity 0.8.10;
        /**
         * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
         * checks.
         *
         * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
         * easily result in undesired exploitation or bugs, since developers usually
         * assume that overflows raise errors. `SafeCast` restores this intuition by
         * reverting the transaction when such an operation overflows.
         *
         * Using this library instead of the unchecked operations eliminates an entire
         * class of bugs, so it's recommended to use it always.
         *
         * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
         * all math on `uint256` and `int256` and then downcasting.
         */
        library SafeCast {
          /**
           * @dev Returns the downcasted uint224 from uint256, reverting on
           * overflow (when the input is greater than largest uint224).
           *
           * Counterpart to Solidity's `uint224` operator.
           *
           * Requirements:
           *
           * - input must fit into 224 bits
           */
          function toUint224(uint256 value) internal pure returns (uint224) {
            require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
            return uint224(value);
          }
          /**
           * @dev Returns the downcasted uint128 from uint256, reverting on
           * overflow (when the input is greater than largest uint128).
           *
           * Counterpart to Solidity's `uint128` operator.
           *
           * Requirements:
           *
           * - input must fit into 128 bits
           */
          function toUint128(uint256 value) internal pure returns (uint128) {
            require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
            return uint128(value);
          }
          /**
           * @dev Returns the downcasted uint96 from uint256, reverting on
           * overflow (when the input is greater than largest uint96).
           *
           * Counterpart to Solidity's `uint96` operator.
           *
           * Requirements:
           *
           * - input must fit into 96 bits
           */
          function toUint96(uint256 value) internal pure returns (uint96) {
            require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
            return uint96(value);
          }
          /**
           * @dev Returns the downcasted uint64 from uint256, reverting on
           * overflow (when the input is greater than largest uint64).
           *
           * Counterpart to Solidity's `uint64` operator.
           *
           * Requirements:
           *
           * - input must fit into 64 bits
           */
          function toUint64(uint256 value) internal pure returns (uint64) {
            require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
            return uint64(value);
          }
          /**
           * @dev Returns the downcasted uint32 from uint256, reverting on
           * overflow (when the input is greater than largest uint32).
           *
           * Counterpart to Solidity's `uint32` operator.
           *
           * Requirements:
           *
           * - input must fit into 32 bits
           */
          function toUint32(uint256 value) internal pure returns (uint32) {
            require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
            return uint32(value);
          }
          /**
           * @dev Returns the downcasted uint16 from uint256, reverting on
           * overflow (when the input is greater than largest uint16).
           *
           * Counterpart to Solidity's `uint16` operator.
           *
           * Requirements:
           *
           * - input must fit into 16 bits
           */
          function toUint16(uint256 value) internal pure returns (uint16) {
            require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
            return uint16(value);
          }
          /**
           * @dev Returns the downcasted uint8 from uint256, reverting on
           * overflow (when the input is greater than largest uint8).
           *
           * Counterpart to Solidity's `uint8` operator.
           *
           * Requirements:
           *
           * - input must fit into 8 bits.
           */
          function toUint8(uint256 value) internal pure returns (uint8) {
            require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
            return uint8(value);
          }
          /**
           * @dev Converts a signed int256 into an unsigned uint256.
           *
           * Requirements:
           *
           * - input must be greater than or equal to 0.
           */
          function toUint256(int256 value) internal pure returns (uint256) {
            require(value >= 0, 'SafeCast: value must be positive');
            return uint256(value);
          }
          /**
           * @dev Returns the downcasted int128 from int256, reverting on
           * overflow (when the input is less than smallest int128 or
           * greater than largest int128).
           *
           * Counterpart to Solidity's `int128` operator.
           *
           * Requirements:
           *
           * - input must fit into 128 bits
           *
           * _Available since v3.1._
           */
          function toInt128(int256 value) internal pure returns (int128) {
            require(
              value >= type(int128).min && value <= type(int128).max,
              "SafeCast: value doesn't fit in 128 bits"
            );
            return int128(value);
          }
          /**
           * @dev Returns the downcasted int64 from int256, reverting on
           * overflow (when the input is less than smallest int64 or
           * greater than largest int64).
           *
           * Counterpart to Solidity's `int64` operator.
           *
           * Requirements:
           *
           * - input must fit into 64 bits
           *
           * _Available since v3.1._
           */
          function toInt64(int256 value) internal pure returns (int64) {
            require(
              value >= type(int64).min && value <= type(int64).max,
              "SafeCast: value doesn't fit in 64 bits"
            );
            return int64(value);
          }
          /**
           * @dev Returns the downcasted int32 from int256, reverting on
           * overflow (when the input is less than smallest int32 or
           * greater than largest int32).
           *
           * Counterpart to Solidity's `int32` operator.
           *
           * Requirements:
           *
           * - input must fit into 32 bits
           *
           * _Available since v3.1._
           */
          function toInt32(int256 value) internal pure returns (int32) {
            require(
              value >= type(int32).min && value <= type(int32).max,
              "SafeCast: value doesn't fit in 32 bits"
            );
            return int32(value);
          }
          /**
           * @dev Returns the downcasted int16 from int256, reverting on
           * overflow (when the input is less than smallest int16 or
           * greater than largest int16).
           *
           * Counterpart to Solidity's `int16` operator.
           *
           * Requirements:
           *
           * - input must fit into 16 bits
           *
           * _Available since v3.1._
           */
          function toInt16(int256 value) internal pure returns (int16) {
            require(
              value >= type(int16).min && value <= type(int16).max,
              "SafeCast: value doesn't fit in 16 bits"
            );
            return int16(value);
          }
          /**
           * @dev Returns the downcasted int8 from int256, reverting on
           * overflow (when the input is less than smallest int8 or
           * greater than largest int8).
           *
           * Counterpart to Solidity's `int8` operator.
           *
           * Requirements:
           *
           * - input must fit into 8 bits.
           *
           * _Available since v3.1._
           */
          function toInt8(int256 value) internal pure returns (int8) {
            require(
              value >= type(int8).min && value <= type(int8).max,
              "SafeCast: value doesn't fit in 8 bits"
            );
            return int8(value);
          }
          /**
           * @dev Converts an unsigned uint256 into a signed int256.
           *
           * Requirements:
           *
           * - input must be less than or equal to maxInt256.
           */
          function toInt256(uint256 value) internal pure returns (int256) {
            // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
            require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
            return int256(value);
          }
        }
        // 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;
        import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol';
        import {IScaledBalanceToken} from './IScaledBalanceToken.sol';
        import {IInitializableAToken} from './IInitializableAToken.sol';
        /**
         * @title IAToken
         * @author Aave
         * @notice Defines the basic interface for an AToken.
         */
        interface IAToken is IERC20, IScaledBalanceToken, IInitializableAToken {
          /**
           * @dev Emitted during the transfer action
           * @param from The user whose tokens are being transferred
           * @param to The recipient
           * @param value The scaled amount being transferred
           * @param index The next liquidity index of the reserve
           */
          event BalanceTransfer(address indexed from, address indexed to, uint256 value, uint256 index);
          /**
           * @notice Mints `amount` aTokens to `user`
           * @param caller The address performing the mint
           * @param onBehalfOf The address of the user that will receive the minted aTokens
           * @param amount The amount of tokens getting minted
           * @param index The next liquidity index of the reserve
           * @return `true` if the the previous balance of the user was 0
           */
          function mint(
            address caller,
            address onBehalfOf,
            uint256 amount,
            uint256 index
          ) external returns (bool);
          /**
           * @notice Burns aTokens from `user` and sends the equivalent amount of underlying to `receiverOfUnderlying`
           * @dev In some instances, the mint event could be emitted from a burn transaction
           * if the amount to burn is less than the interest that the user accrued
           * @param from The address from which the aTokens will be burned
           * @param receiverOfUnderlying The address that will receive the underlying
           * @param amount The amount being burned
           * @param index The next liquidity index of the reserve
           */
          function burn(
            address from,
            address receiverOfUnderlying,
            uint256 amount,
            uint256 index
          ) external;
          /**
           * @notice Mints aTokens to the reserve treasury
           * @param amount The amount of tokens getting minted
           * @param index The next liquidity index of the reserve
           */
          function mintToTreasury(uint256 amount, uint256 index) external;
          /**
           * @notice Transfers aTokens in the event of a borrow being liquidated, in case the liquidators reclaims the aToken
           * @param from The address getting liquidated, current owner of the aTokens
           * @param to The recipient
           * @param value The amount of tokens getting transferred
           */
          function transferOnLiquidation(
            address from,
            address to,
            uint256 value
          ) external;
          /**
           * @notice Transfers the underlying asset to `target`.
           * @dev Used by the Pool to transfer assets in borrow(), withdraw() and flashLoan()
           * @param target The recipient of the underlying
           * @param amount The amount getting transferred
           */
          function transferUnderlyingTo(address target, uint256 amount) external;
          /**
           * @notice Handles the underlying received by the aToken after the transfer has been completed.
           * @dev The default implementation is empty as with standard ERC20 tokens, nothing needs to be done after the
           * transfer is concluded. However in the future there may be aTokens that allow for example to stake the underlying
           * to receive LM rewards. In that case, `handleRepayment()` would perform the staking of the underlying asset.
           * @param user The user executing the repayment
           * @param onBehalfOf The address of the user who will get his debt reduced/removed
           * @param amount The amount getting repaid
           */
          function handleRepayment(
            address user,
            address onBehalfOf,
            uint256 amount
          ) external;
          /**
           * @notice Allow passing a signed message to approve spending
           * @dev implements the permit function as for
           * https://github.com/ethereum/EIPs/blob/8a34d644aacf0f9f8f00815307fd7dd5da07655f/EIPS/eip-2612.md
           * @param owner The owner of the funds
           * @param spender The spender
           * @param value The amount
           * @param deadline The deadline timestamp, type(uint256).max for max deadline
           * @param v Signature param
           * @param s Signature param
           * @param r Signature param
           */
          function permit(
            address owner,
            address spender,
            uint256 value,
            uint256 deadline,
            uint8 v,
            bytes32 r,
            bytes32 s
          ) external;
          /**
           * @notice Returns the address of the underlying asset of this aToken (E.g. WETH for aWETH)
           * @return The address of the underlying asset
           */
          function UNDERLYING_ASSET_ADDRESS() external view returns (address);
          /**
           * @notice Returns the address of the Aave treasury, receiving the fees on this aToken.
           * @return Address of the Aave treasury
           */
          function RESERVE_TREASURY_ADDRESS() external view returns (address);
          /**
           * @notice Get the domain separator for the token
           * @dev Return cached value if chainId matches cache, otherwise recomputes separator
           * @return The domain separator of the token at current chain
           */
          function DOMAIN_SEPARATOR() external view returns (bytes32);
          /**
           * @notice Returns the nonce for owner.
           * @param owner The address of the owner
           * @return The nonce of the owner
           */
          function nonces(address owner) external view returns (uint256);
          /**
           * @notice Rescue and transfer tokens locked in this contract
           * @param token The address of the token
           * @param to The address of the recipient
           * @param amount The amount of token to transfer
           */
          function rescueTokens(
            address token,
            address to,
            uint256 amount
          ) external;
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity ^0.8.0;
        /**
         * @title IAaveIncentivesController
         * @author Aave
         * @notice Defines the basic interface for an Aave Incentives Controller.
         * @dev It only contains one single function, needed as a hook on aToken and debtToken transfers.
         */
        interface IAaveIncentivesController {
          /**
           * @dev Called by the corresponding asset on transfer hook in order to update the rewards distribution.
           * @dev The units of `totalSupply` and `userBalance` should be the same.
           * @param user The address of the user whose asset balance has changed
           * @param totalSupply The total supply of the asset prior to user balance change
           * @param userBalance The previous user balance prior to balance change
           */
          function handleAction(
            address user,
            uint256 totalSupply,
            uint256 userBalance
          ) external;
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity ^0.8.0;
        import {IAaveIncentivesController} from './IAaveIncentivesController.sol';
        import {IPool} from './IPool.sol';
        /**
         * @title IInitializableAToken
         * @author Aave
         * @notice Interface for the initialize function on AToken
         */
        interface IInitializableAToken {
          /**
           * @dev Emitted when an aToken is initialized
           * @param underlyingAsset The address of the underlying asset
           * @param pool The address of the associated pool
           * @param treasury The address of the treasury
           * @param incentivesController The address of the incentives controller for this aToken
           * @param aTokenDecimals The decimals of the underlying
           * @param aTokenName The name of the aToken
           * @param aTokenSymbol The symbol of the aToken
           * @param params A set of encoded parameters for additional initialization
           */
          event Initialized(
            address indexed underlyingAsset,
            address indexed pool,
            address treasury,
            address incentivesController,
            uint8 aTokenDecimals,
            string aTokenName,
            string aTokenSymbol,
            bytes params
          );
          /**
           * @notice Initializes the aToken
           * @param pool The pool contract that is initializing this contract
           * @param treasury The address of the Aave treasury, receiving the fees on this aToken
           * @param underlyingAsset The address of the underlying asset of this aToken (E.g. WETH for aWETH)
           * @param incentivesController The smart contract managing potential incentives distribution
           * @param aTokenDecimals The decimals of the aToken, same as the underlying asset's
           * @param aTokenName The name of the aToken
           * @param aTokenSymbol The symbol of the aToken
           * @param params A set of encoded parameters for additional initialization
           */
          function initialize(
            IPool pool,
            address treasury,
            address underlyingAsset,
            IAaveIncentivesController incentivesController,
            uint8 aTokenDecimals,
            string calldata aTokenName,
            string calldata aTokenSymbol,
            bytes calldata params
          ) external;
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity ^0.8.0;
        import {IPoolAddressesProvider} from './IPoolAddressesProvider.sol';
        import {DataTypes} from '../protocol/libraries/types/DataTypes.sol';
        /**
         * @title IPool
         * @author Aave
         * @notice Defines the basic interface for an Aave Pool.
         */
        interface IPool {
          /**
           * @dev Emitted on mintUnbacked()
           * @param reserve The address of the underlying asset of the reserve
           * @param user The address initiating the supply
           * @param onBehalfOf The beneficiary of the supplied assets, receiving the aTokens
           * @param amount The amount of supplied assets
           * @param referralCode The referral code used
           */
          event MintUnbacked(
            address indexed reserve,
            address user,
            address indexed onBehalfOf,
            uint256 amount,
            uint16 indexed referralCode
          );
          /**
           * @dev Emitted on backUnbacked()
           * @param reserve The address of the underlying asset of the reserve
           * @param backer The address paying for the backing
           * @param amount The amount added as backing
           * @param fee The amount paid in fees
           */
          event BackUnbacked(address indexed reserve, address indexed backer, uint256 amount, uint256 fee);
          /**
           * @dev Emitted on supply()
           * @param reserve The address of the underlying asset of the reserve
           * @param user The address initiating the supply
           * @param onBehalfOf The beneficiary of the supply, receiving the aTokens
           * @param amount The amount supplied
           * @param referralCode The referral code used
           */
          event Supply(
            address indexed reserve,
            address user,
            address indexed onBehalfOf,
            uint256 amount,
            uint16 indexed referralCode
          );
          /**
           * @dev Emitted on withdraw()
           * @param reserve The address of the underlying asset being withdrawn
           * @param user The address initiating the withdrawal, owner of aTokens
           * @param to The address that will receive the underlying
           * @param amount The amount to be withdrawn
           */
          event Withdraw(address indexed reserve, address indexed user, address indexed to, uint256 amount);
          /**
           * @dev Emitted on borrow() and flashLoan() when debt needs to be opened
           * @param reserve The address of the underlying asset being borrowed
           * @param user The address of the user initiating the borrow(), receiving the funds on borrow() or just
           * initiator of the transaction on flashLoan()
           * @param onBehalfOf The address that will be getting the debt
           * @param amount The amount borrowed out
           * @param interestRateMode The rate mode: 1 for Stable, 2 for Variable
           * @param borrowRate The numeric rate at which the user has borrowed, expressed in ray
           * @param referralCode The referral code used
           */
          event Borrow(
            address indexed reserve,
            address user,
            address indexed onBehalfOf,
            uint256 amount,
            DataTypes.InterestRateMode interestRateMode,
            uint256 borrowRate,
            uint16 indexed referralCode
          );
          /**
           * @dev Emitted on repay()
           * @param reserve The address of the underlying asset of the reserve
           * @param user The beneficiary of the repayment, getting his debt reduced
           * @param repayer The address of the user initiating the repay(), providing the funds
           * @param amount The amount repaid
           * @param useATokens True if the repayment is done using aTokens, `false` if done with underlying asset directly
           */
          event Repay(
            address indexed reserve,
            address indexed user,
            address indexed repayer,
            uint256 amount,
            bool useATokens
          );
          /**
           * @dev Emitted on swapBorrowRateMode()
           * @param reserve The address of the underlying asset of the reserve
           * @param user The address of the user swapping his rate mode
           * @param interestRateMode The current interest rate mode of the position being swapped: 1 for Stable, 2 for Variable
           */
          event SwapBorrowRateMode(
            address indexed reserve,
            address indexed user,
            DataTypes.InterestRateMode interestRateMode
          );
          /**
           * @dev Emitted on borrow(), repay() and liquidationCall() when using isolated assets
           * @param asset The address of the underlying asset of the reserve
           * @param totalDebt The total isolation mode debt for the reserve
           */
          event IsolationModeTotalDebtUpdated(address indexed asset, uint256 totalDebt);
          /**
           * @dev Emitted when the user selects a certain asset category for eMode
           * @param user The address of the user
           * @param categoryId The category id
           */
          event UserEModeSet(address indexed user, uint8 categoryId);
          /**
           * @dev Emitted on setUserUseReserveAsCollateral()
           * @param reserve The address of the underlying asset of the reserve
           * @param user The address of the user enabling the usage as collateral
           */
          event ReserveUsedAsCollateralEnabled(address indexed reserve, address indexed user);
          /**
           * @dev Emitted on setUserUseReserveAsCollateral()
           * @param reserve The address of the underlying asset of the reserve
           * @param user The address of the user enabling the usage as collateral
           */
          event ReserveUsedAsCollateralDisabled(address indexed reserve, address indexed user);
          /**
           * @dev Emitted on rebalanceStableBorrowRate()
           * @param reserve The address of the underlying asset of the reserve
           * @param user The address of the user for which the rebalance has been executed
           */
          event RebalanceStableBorrowRate(address indexed reserve, address indexed user);
          /**
           * @dev Emitted on flashLoan()
           * @param target The address of the flash loan receiver contract
           * @param initiator The address initiating the flash loan
           * @param asset The address of the asset being flash borrowed
           * @param amount The amount flash borrowed
           * @param interestRateMode The flashloan mode: 0 for regular flashloan, 1 for Stable debt, 2 for Variable debt
           * @param premium The fee flash borrowed
           * @param referralCode The referral code used
           */
          event FlashLoan(
            address indexed target,
            address initiator,
            address indexed asset,
            uint256 amount,
            DataTypes.InterestRateMode interestRateMode,
            uint256 premium,
            uint16 indexed referralCode
          );
          /**
           * @dev Emitted when a borrower is liquidated.
           * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation
           * @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation
           * @param user The address of the borrower getting liquidated
           * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover
           * @param liquidatedCollateralAmount The amount of collateral received by the liquidator
           * @param liquidator The address of the liquidator
           * @param receiveAToken True if the liquidators wants to receive the collateral aTokens, `false` if he wants
           * to receive the underlying collateral asset directly
           */
          event LiquidationCall(
            address indexed collateralAsset,
            address indexed debtAsset,
            address indexed user,
            uint256 debtToCover,
            uint256 liquidatedCollateralAmount,
            address liquidator,
            bool receiveAToken
          );
          /**
           * @dev Emitted when the state of a reserve is updated.
           * @param reserve The address of the underlying asset of the reserve
           * @param liquidityRate The next liquidity rate
           * @param stableBorrowRate The next stable borrow rate
           * @param variableBorrowRate The next variable borrow rate
           * @param liquidityIndex The next liquidity index
           * @param variableBorrowIndex The next variable borrow index
           */
          event ReserveDataUpdated(
            address indexed reserve,
            uint256 liquidityRate,
            uint256 stableBorrowRate,
            uint256 variableBorrowRate,
            uint256 liquidityIndex,
            uint256 variableBorrowIndex
          );
          /**
           * @dev Emitted when the protocol treasury receives minted aTokens from the accrued interest.
           * @param reserve The address of the reserve
           * @param amountMinted The amount minted to the treasury
           */
          event MintedToTreasury(address indexed reserve, uint256 amountMinted);
          /**
           * @notice Mints an `amount` of aTokens to the `onBehalfOf`
           * @param asset The address of the underlying asset to mint
           * @param amount The amount to mint
           * @param onBehalfOf The address that will receive the aTokens
           * @param referralCode Code used to register the integrator originating the operation, for potential rewards.
           *   0 if the action is executed directly by the user, without any middle-man
           */
          function mintUnbacked(
            address asset,
            uint256 amount,
            address onBehalfOf,
            uint16 referralCode
          ) external;
          /**
           * @notice Back the current unbacked underlying with `amount` and pay `fee`.
           * @param asset The address of the underlying asset to back
           * @param amount The amount to back
           * @param fee The amount paid in fees
           * @return The backed amount
           */
          function backUnbacked(
            address asset,
            uint256 amount,
            uint256 fee
          ) external returns (uint256);
          /**
           * @notice Supplies an `amount` of underlying asset into the reserve, receiving in return overlying aTokens.
           * - E.g. User supplies 100 USDC and gets in return 100 aUSDC
           * @param asset The address of the underlying asset to supply
           * @param amount The amount to be supplied
           * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user
           *   wants to receive them on his own wallet, or a different address if the beneficiary of aTokens
           *   is a different wallet
           * @param referralCode Code used to register the integrator originating the operation, for potential rewards.
           *   0 if the action is executed directly by the user, without any middle-man
           */
          function supply(
            address asset,
            uint256 amount,
            address onBehalfOf,
            uint16 referralCode
          ) external;
          /**
           * @notice Supply with transfer approval of asset to be supplied done via permit function
           * see: https://eips.ethereum.org/EIPS/eip-2612 and https://eips.ethereum.org/EIPS/eip-713
           * @param asset The address of the underlying asset to supply
           * @param amount The amount to be supplied
           * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user
           *   wants to receive them on his own wallet, or a different address if the beneficiary of aTokens
           *   is a different wallet
           * @param deadline The deadline timestamp that the permit is valid
           * @param referralCode Code used to register the integrator originating the operation, for potential rewards.
           *   0 if the action is executed directly by the user, without any middle-man
           * @param permitV The V parameter of ERC712 permit sig
           * @param permitR The R parameter of ERC712 permit sig
           * @param permitS The S parameter of ERC712 permit sig
           */
          function supplyWithPermit(
            address asset,
            uint256 amount,
            address onBehalfOf,
            uint16 referralCode,
            uint256 deadline,
            uint8 permitV,
            bytes32 permitR,
            bytes32 permitS
          ) external;
          /**
           * @notice Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned
           * E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC
           * @param asset The address of the underlying asset to withdraw
           * @param amount The underlying amount to be withdrawn
           *   - Send the value type(uint256).max in order to withdraw the whole aToken balance
           * @param to The address that will receive the underlying, same as msg.sender if the user
           *   wants to receive it on his own wallet, or a different address if the beneficiary is a
           *   different wallet
           * @return The final amount withdrawn
           */
          function withdraw(
            address asset,
            uint256 amount,
            address to
          ) external returns (uint256);
          /**
           * @notice Allows users to borrow a specific `amount` of the reserve underlying asset, provided that the borrower
           * already supplied enough collateral, or he was given enough allowance by a credit delegator on the
           * corresponding debt token (StableDebtToken or VariableDebtToken)
           * - E.g. User borrows 100 USDC passing as `onBehalfOf` his own address, receiving the 100 USDC in his wallet
           *   and 100 stable/variable debt tokens, depending on the `interestRateMode`
           * @param asset The address of the underlying asset to borrow
           * @param amount The amount to be borrowed
           * @param interestRateMode The interest rate mode at which the user wants to borrow: 1 for Stable, 2 for Variable
           * @param referralCode The code used to register the integrator originating the operation, for potential rewards.
           *   0 if the action is executed directly by the user, without any middle-man
           * @param onBehalfOf The address of the user who will receive the debt. Should be the address of the borrower itself
           * calling the function if he wants to borrow against his own collateral, or the address of the credit delegator
           * if he has been given credit delegation allowance
           */
          function borrow(
            address asset,
            uint256 amount,
            uint256 interestRateMode,
            uint16 referralCode,
            address onBehalfOf
          ) external;
          /**
           * @notice Repays a borrowed `amount` on a specific reserve, burning the equivalent debt tokens owned
           * - E.g. User repays 100 USDC, burning 100 variable/stable debt tokens of the `onBehalfOf` address
           * @param asset The address of the borrowed underlying asset previously borrowed
           * @param amount The amount to repay
           * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode`
           * @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable
           * @param onBehalfOf The address of the user who will get his debt reduced/removed. Should be the address of the
           * user calling the function if he wants to reduce/remove his own debt, or the address of any other
           * other borrower whose debt should be removed
           * @return The final amount repaid
           */
          function repay(
            address asset,
            uint256 amount,
            uint256 interestRateMode,
            address onBehalfOf
          ) external returns (uint256);
          /**
           * @notice Repay with transfer approval of asset to be repaid done via permit function
           * see: https://eips.ethereum.org/EIPS/eip-2612 and https://eips.ethereum.org/EIPS/eip-713
           * @param asset The address of the borrowed underlying asset previously borrowed
           * @param amount The amount to repay
           * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode`
           * @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable
           * @param onBehalfOf Address of the user who will get his debt reduced/removed. Should be the address of the
           * user calling the function if he wants to reduce/remove his own debt, or the address of any other
           * other borrower whose debt should be removed
           * @param deadline The deadline timestamp that the permit is valid
           * @param permitV The V parameter of ERC712 permit sig
           * @param permitR The R parameter of ERC712 permit sig
           * @param permitS The S parameter of ERC712 permit sig
           * @return The final amount repaid
           */
          function repayWithPermit(
            address asset,
            uint256 amount,
            uint256 interestRateMode,
            address onBehalfOf,
            uint256 deadline,
            uint8 permitV,
            bytes32 permitR,
            bytes32 permitS
          ) external returns (uint256);
          /**
           * @notice Repays a borrowed `amount` on a specific reserve using the reserve aTokens, burning the
           * equivalent debt tokens
           * - E.g. User repays 100 USDC using 100 aUSDC, burning 100 variable/stable debt tokens
           * @dev  Passing uint256.max as amount will clean up any residual aToken dust balance, if the user aToken
           * balance is not enough to cover the whole debt
           * @param asset The address of the borrowed underlying asset previously borrowed
           * @param amount The amount to repay
           * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode`
           * @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable
           * @return The final amount repaid
           */
          function repayWithATokens(
            address asset,
            uint256 amount,
            uint256 interestRateMode
          ) external returns (uint256);
          /**
           * @notice Allows a borrower to swap his debt between stable and variable mode, or vice versa
           * @param asset The address of the underlying asset borrowed
           * @param interestRateMode The current interest rate mode of the position being swapped: 1 for Stable, 2 for Variable
           */
          function swapBorrowRateMode(address asset, uint256 interestRateMode) external;
          /**
           * @notice Rebalances the stable interest rate of a user to the current stable rate defined on the reserve.
           * - Users can be rebalanced if the following conditions are satisfied:
           *     1. Usage ratio is above 95%
           *     2. the current supply APY is below REBALANCE_UP_THRESHOLD * maxVariableBorrowRate, which means that too
           *        much has been borrowed at a stable rate and suppliers are not earning enough
           * @param asset The address of the underlying asset borrowed
           * @param user The address of the user to be rebalanced
           */
          function rebalanceStableBorrowRate(address asset, address user) external;
          /**
           * @notice Allows suppliers to enable/disable a specific supplied asset as collateral
           * @param asset The address of the underlying asset supplied
           * @param useAsCollateral True if the user wants to use the supply as collateral, false otherwise
           */
          function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) external;
          /**
           * @notice Function to liquidate a non-healthy position collateral-wise, with Health Factor below 1
           * - The caller (liquidator) covers `debtToCover` amount of debt of the user getting liquidated, and receives
           *   a proportionally amount of the `collateralAsset` plus a bonus to cover market risk
           * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation
           * @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation
           * @param user The address of the borrower getting liquidated
           * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover
           * @param receiveAToken True if the liquidators wants to receive the collateral aTokens, `false` if he wants
           * to receive the underlying collateral asset directly
           */
          function liquidationCall(
            address collateralAsset,
            address debtAsset,
            address user,
            uint256 debtToCover,
            bool receiveAToken
          ) external;
          /**
           * @notice Allows smartcontracts to access the liquidity of the pool within one transaction,
           * as long as the amount taken plus a fee is returned.
           * @dev IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept
           * into consideration. For further details please visit https://developers.aave.com
           * @param receiverAddress The address of the contract receiving the funds, implementing IFlashLoanReceiver interface
           * @param assets The addresses of the assets being flash-borrowed
           * @param amounts The amounts of the assets being flash-borrowed
           * @param interestRateModes Types of the debt to open if the flash loan is not returned:
           *   0 -> Don't open any debt, just revert if funds can't be transferred from the receiver
           *   1 -> Open debt at stable rate for the value of the amount flash-borrowed to the `onBehalfOf` address
           *   2 -> Open debt at variable rate for the value of the amount flash-borrowed to the `onBehalfOf` address
           * @param onBehalfOf The address  that will receive the debt in the case of using on `modes` 1 or 2
           * @param params Variadic packed params to pass to the receiver as extra information
           * @param referralCode The code used to register the integrator originating the operation, for potential rewards.
           *   0 if the action is executed directly by the user, without any middle-man
           */
          function flashLoan(
            address receiverAddress,
            address[] calldata assets,
            uint256[] calldata amounts,
            uint256[] calldata interestRateModes,
            address onBehalfOf,
            bytes calldata params,
            uint16 referralCode
          ) external;
          /**
           * @notice Allows smartcontracts to access the liquidity of the pool within one transaction,
           * as long as the amount taken plus a fee is returned.
           * @dev IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept
           * into consideration. For further details please visit https://developers.aave.com
           * @param receiverAddress The address of the contract receiving the funds, implementing IFlashLoanSimpleReceiver interface
           * @param asset The address of the asset being flash-borrowed
           * @param amount The amount of the asset being flash-borrowed
           * @param params Variadic packed params to pass to the receiver as extra information
           * @param referralCode The code used to register the integrator originating the operation, for potential rewards.
           *   0 if the action is executed directly by the user, without any middle-man
           */
          function flashLoanSimple(
            address receiverAddress,
            address asset,
            uint256 amount,
            bytes calldata params,
            uint16 referralCode
          ) external;
          /**
           * @notice Returns the user account data across all the reserves
           * @param user The address of the user
           * @return totalCollateralBase The total collateral of the user in the base currency used by the price feed
           * @return totalDebtBase The total debt of the user in the base currency used by the price feed
           * @return availableBorrowsBase The borrowing power left of the user in the base currency used by the price feed
           * @return currentLiquidationThreshold The liquidation threshold of the user
           * @return ltv The loan to value of The user
           * @return healthFactor The current health factor of the user
           */
          function getUserAccountData(address user)
            external
            view
            returns (
              uint256 totalCollateralBase,
              uint256 totalDebtBase,
              uint256 availableBorrowsBase,
              uint256 currentLiquidationThreshold,
              uint256 ltv,
              uint256 healthFactor
            );
          /**
           * @notice Initializes a reserve, activating it, assigning an aToken and debt tokens and an
           * interest rate strategy
           * @dev Only callable by the PoolConfigurator contract
           * @param asset The address of the underlying asset of the reserve
           * @param aTokenAddress The address of the aToken that will be assigned to the reserve
           * @param stableDebtAddress The address of the StableDebtToken that will be assigned to the reserve
           * @param variableDebtAddress The address of the VariableDebtToken that will be assigned to the reserve
           * @param interestRateStrategyAddress The address of the interest rate strategy contract
           */
          function initReserve(
            address asset,
            address aTokenAddress,
            address stableDebtAddress,
            address variableDebtAddress,
            address interestRateStrategyAddress
          ) external;
          /**
           * @notice Drop a reserve
           * @dev Only callable by the PoolConfigurator contract
           * @param asset The address of the underlying asset of the reserve
           */
          function dropReserve(address asset) external;
          /**
           * @notice Updates the address of the interest rate strategy contract
           * @dev Only callable by the PoolConfigurator contract
           * @param asset The address of the underlying asset of the reserve
           * @param rateStrategyAddress The address of the interest rate strategy contract
           */
          function setReserveInterestRateStrategyAddress(address asset, address rateStrategyAddress)
            external;
          /**
           * @notice Sets the configuration bitmap of the reserve as a whole
           * @dev Only callable by the PoolConfigurator contract
           * @param asset The address of the underlying asset of the reserve
           * @param configuration The new configuration bitmap
           */
          function setConfiguration(address asset, DataTypes.ReserveConfigurationMap calldata configuration)
            external;
          /**
           * @notice Returns the configuration of the reserve
           * @param asset The address of the underlying asset of the reserve
           * @return The configuration of the reserve
           */
          function getConfiguration(address asset)
            external
            view
            returns (DataTypes.ReserveConfigurationMap memory);
          /**
           * @notice Returns the configuration of the user across all the reserves
           * @param user The user address
           * @return The configuration of the user
           */
          function getUserConfiguration(address user)
            external
            view
            returns (DataTypes.UserConfigurationMap memory);
          /**
           * @notice Returns the normalized income of the reserve
           * @param asset The address of the underlying asset of the reserve
           * @return The reserve's normalized income
           */
          function getReserveNormalizedIncome(address asset) external view returns (uint256);
          /**
           * @notice Returns the normalized variable debt per unit of asset
           * @dev WARNING: This function is intended to be used primarily by the protocol itself to get a
           * "dynamic" variable index based on time, current stored index and virtual rate at the current
           * moment (approx. a borrower would get if opening a position). This means that is always used in
           * combination with variable debt supply/balances.
           * If using this function externally, consider that is possible to have an increasing normalized
           * variable debt that is not equivalent to how the variable debt index would be updated in storage
           * (e.g. only updates with non-zero variable debt supply)
           * @param asset The address of the underlying asset of the reserve
           * @return The reserve normalized variable debt
           */
          function getReserveNormalizedVariableDebt(address asset) external view returns (uint256);
          /**
           * @notice Returns the state and configuration of the reserve
           * @param asset The address of the underlying asset of the reserve
           * @return The state and configuration data of the reserve
           */
          function getReserveData(address asset) external view returns (DataTypes.ReserveData memory);
          /**
           * @notice Validates and finalizes an aToken transfer
           * @dev Only callable by the overlying aToken of the `asset`
           * @param asset The address of the underlying asset of the aToken
           * @param from The user from which the aTokens are transferred
           * @param to The user receiving the aTokens
           * @param amount The amount being transferred/withdrawn
           * @param balanceFromBefore The aToken balance of the `from` user before the transfer
           * @param balanceToBefore The aToken balance of the `to` user before the transfer
           */
          function finalizeTransfer(
            address asset,
            address from,
            address to,
            uint256 amount,
            uint256 balanceFromBefore,
            uint256 balanceToBefore
          ) external;
          /**
           * @notice Returns the list of the underlying assets of all the initialized reserves
           * @dev It does not include dropped reserves
           * @return The addresses of the underlying assets of the initialized reserves
           */
          function getReservesList() external view returns (address[] memory);
          /**
           * @notice Returns the address of the underlying asset of a reserve by the reserve id as stored in the DataTypes.ReserveData struct
           * @param id The id of the reserve as stored in the DataTypes.ReserveData struct
           * @return The address of the reserve associated with id
           */
          function getReserveAddressById(uint16 id) external view returns (address);
          /**
           * @notice Returns the PoolAddressesProvider connected to this contract
           * @return The address of the PoolAddressesProvider
           */
          function ADDRESSES_PROVIDER() external view returns (IPoolAddressesProvider);
          /**
           * @notice Updates the protocol fee on the bridging
           * @param bridgeProtocolFee The part of the premium sent to the protocol treasury
           */
          function updateBridgeProtocolFee(uint256 bridgeProtocolFee) external;
          /**
           * @notice Updates flash loan premiums. Flash loan premium consists of two parts:
           * - A part is sent to aToken holders as extra, one time accumulated interest
           * - A part is collected by the protocol treasury
           * @dev The total premium is calculated on the total borrowed amount
           * @dev The premium to protocol is calculated on the total premium, being a percentage of `flashLoanPremiumTotal`
           * @dev Only callable by the PoolConfigurator contract
           * @param flashLoanPremiumTotal The total premium, expressed in bps
           * @param flashLoanPremiumToProtocol The part of the premium sent to the protocol treasury, expressed in bps
           */
          function updateFlashloanPremiums(
            uint128 flashLoanPremiumTotal,
            uint128 flashLoanPremiumToProtocol
          ) external;
          /**
           * @notice Configures a new category for the eMode.
           * @dev In eMode, the protocol allows very high borrowing power to borrow assets of the same category.
           * The category 0 is reserved as it's the default for volatile assets
           * @param id The id of the category
           * @param config The configuration of the category
           */
          function configureEModeCategory(uint8 id, DataTypes.EModeCategory memory config) external;
          /**
           * @notice Returns the data of an eMode category
           * @param id The id of the category
           * @return The configuration data of the category
           */
          function getEModeCategoryData(uint8 id) external view returns (DataTypes.EModeCategory memory);
          /**
           * @notice Allows a user to use the protocol in eMode
           * @param categoryId The id of the category
           */
          function setUserEMode(uint8 categoryId) external;
          /**
           * @notice Returns the eMode the user is using
           * @param user The address of the user
           * @return The eMode id
           */
          function getUserEMode(address user) external view returns (uint256);
          /**
           * @notice Resets the isolation mode total debt of the given asset to zero
           * @dev It requires the given asset has zero debt ceiling
           * @param asset The address of the underlying asset to reset the isolationModeTotalDebt
           */
          function resetIsolationModeTotalDebt(address asset) external;
          /**
           * @notice Returns the percentage of available liquidity that can be borrowed at once at stable rate
           * @return The percentage of available liquidity to borrow, expressed in bps
           */
          function MAX_STABLE_RATE_BORROW_SIZE_PERCENT() external view returns (uint256);
          /**
           * @notice Returns the total fee on flash loans
           * @return The total fee on flashloans
           */
          function FLASHLOAN_PREMIUM_TOTAL() external view returns (uint128);
          /**
           * @notice Returns the part of the bridge fees sent to protocol
           * @return The bridge fee sent to the protocol treasury
           */
          function BRIDGE_PROTOCOL_FEE() external view returns (uint256);
          /**
           * @notice Returns the part of the flashloan fees sent to protocol
           * @return The flashloan fee sent to the protocol treasury
           */
          function FLASHLOAN_PREMIUM_TO_PROTOCOL() external view returns (uint128);
          /**
           * @notice Returns the maximum number of reserves supported to be listed in this Pool
           * @return The maximum number of reserves supported
           */
          function MAX_NUMBER_RESERVES() external view returns (uint16);
          /**
           * @notice Mints the assets accrued through the reserve factor to the treasury in the form of aTokens
           * @param assets The list of reserves for which the minting needs to be executed
           */
          function mintToTreasury(address[] calldata assets) external;
          /**
           * @notice Rescue and transfer tokens locked in this contract
           * @param token The address of the token
           * @param to The address of the recipient
           * @param amount The amount of token to transfer
           */
          function rescueTokens(
            address token,
            address to,
            uint256 amount
          ) external;
          /**
           * @notice Supplies an `amount` of underlying asset into the reserve, receiving in return overlying aTokens.
           * - E.g. User supplies 100 USDC and gets in return 100 aUSDC
           * @dev Deprecated: Use the `supply` function instead
           * @param asset The address of the underlying asset to supply
           * @param amount The amount to be supplied
           * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user
           *   wants to receive them on his own wallet, or a different address if the beneficiary of aTokens
           *   is a different wallet
           * @param referralCode Code used to register the integrator originating the operation, for potential rewards.
           *   0 if the action is executed directly by the user, without any middle-man
           */
          function deposit(
            address asset,
            uint256 amount,
            address onBehalfOf,
            uint16 referralCode
          ) external;
        }
        // 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: AGPL-3.0
        pragma solidity ^0.8.0;
        /**
         * @title IScaledBalanceToken
         * @author Aave
         * @notice Defines the basic interface for a scaled-balance token.
         */
        interface IScaledBalanceToken {
          /**
           * @dev Emitted after the mint action
           * @param caller The address performing the mint
           * @param onBehalfOf The address of the user that will receive the minted tokens
           * @param value The scaled-up amount being minted (based on user entered amount and balance increase from interest)
           * @param balanceIncrease The increase in scaled-up balance since the last action of 'onBehalfOf'
           * @param index The next liquidity index of the reserve
           */
          event Mint(
            address indexed caller,
            address indexed onBehalfOf,
            uint256 value,
            uint256 balanceIncrease,
            uint256 index
          );
          /**
           * @dev Emitted after the burn action
           * @dev If the burn function does not involve a transfer of the underlying asset, the target defaults to zero address
           * @param from The address from which the tokens will be burned
           * @param target The address that will receive the underlying, if any
           * @param value The scaled-up amount being burned (user entered amount - balance increase from interest)
           * @param balanceIncrease The increase in scaled-up balance since the last action of 'from'
           * @param index The next liquidity index of the reserve
           */
          event Burn(
            address indexed from,
            address indexed target,
            uint256 value,
            uint256 balanceIncrease,
            uint256 index
          );
          /**
           * @notice Returns the scaled balance of the user.
           * @dev The scaled balance is the sum of all the updated stored balance divided by the reserve's liquidity index
           * at the moment of the update
           * @param user The user whose balance is calculated
           * @return The scaled balance of the user
           */
          function scaledBalanceOf(address user) external view returns (uint256);
          /**
           * @notice Returns the scaled balance of the user and the scaled total supply.
           * @param user The address of the user
           * @return The scaled balance of the user
           * @return The scaled total supply
           */
          function getScaledUserBalanceAndSupply(address user) external view returns (uint256, uint256);
          /**
           * @notice Returns the scaled total supply of the scaled balance token. Represents sum(debt/index)
           * @return The scaled total supply
           */
          function scaledTotalSupply() external view returns (uint256);
          /**
           * @notice Returns last index interest was accrued to the user's balance
           * @param user The address of the user
           * @return The last index interest was accrued to the user's balance, expressed in ray
           */
          function getPreviousIndex(address user) external view returns (uint256);
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.8.10;
        /**
         * @title VersionedInitializable
         * @author Aave, inspired by the OpenZeppelin Initializable contract
         * @notice Helper contract to implement initializer functions. To use it, replace
         * the constructor with a function that has the `initializer` modifier.
         * @dev WARNING: Unlike constructors, initializer functions must be manually
         * invoked. This applies both to deploying an Initializable contract, as well
         * as extending an Initializable contract via inheritance.
         * WARNING: When used with inheritance, manual care must be taken to not invoke
         * a parent initializer twice, or ensure that all initializers are idempotent,
         * because this is not dealt with automatically as with constructors.
         */
        abstract contract VersionedInitializable {
          /**
           * @dev Indicates that the contract has been initialized.
           */
          uint256 private lastInitializedRevision = 0;
          /**
           * @dev Indicates that the contract is in the process of being initialized.
           */
          bool private initializing;
          /**
           * @dev Modifier to use in the initializer function of a contract.
           */
          modifier initializer() {
            uint256 revision = getRevision();
            require(
              initializing || isConstructor() || revision > lastInitializedRevision,
              'Contract instance has already been initialized'
            );
            bool isTopLevelCall = !initializing;
            if (isTopLevelCall) {
              initializing = true;
              lastInitializedRevision = revision;
            }
            _;
            if (isTopLevelCall) {
              initializing = false;
            }
          }
          /**
           * @notice Returns the revision number of the contract
           * @dev Needs to be defined in the inherited class as a constant.
           * @return The revision number
           */
          function getRevision() internal pure virtual returns (uint256);
          /**
           * @notice Returns true if and only if the function is running in the constructor
           * @return True if the function is running in the constructor
           */
          function isConstructor() private view returns (bool) {
            // extcodesize checks the size of the code stored in an address, and
            // address returns the current address. Since the code is still not
            // deployed when running a constructor, any checks on its code size will
            // yield zero, making it an effective way to detect if a contract is
            // under construction or not.
            uint256 cs;
            //solium-disable-next-line
            assembly {
              cs := extcodesize(address())
            }
            return cs == 0;
          }
          // Reserved storage space to allow for layout changes in the future.
          uint256[50] private ______gap;
        }
        // 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
        }
        // SPDX-License-Identifier: BUSL-1.1
        pragma solidity ^0.8.0;
        /**
         * @title WadRayMath library
         * @author Aave
         * @notice Provides functions to perform calculations with Wad and Ray units
         * @dev Provides mul and div function for wads (decimal numbers with 18 digits of precision) and rays (decimal numbers
         * with 27 digits of precision)
         * @dev Operations are rounded. If a value is >=.5, will be rounded up, otherwise rounded down.
         */
        library WadRayMath {
          // HALF_WAD and HALF_RAY expressed with extended notation as constant with operations are not supported in Yul assembly
          uint256 internal constant WAD = 1e18;
          uint256 internal constant HALF_WAD = 0.5e18;
          uint256 internal constant RAY = 1e27;
          uint256 internal constant HALF_RAY = 0.5e27;
          uint256 internal constant WAD_RAY_RATIO = 1e9;
          /**
           * @dev Multiplies two wad, rounding half up to the nearest wad
           * @dev assembly optimized for improved gas savings, see https://twitter.com/transmissions11/status/1451131036377571328
           * @param a Wad
           * @param b Wad
           * @return c = a*b, in wad
           */
          function wadMul(uint256 a, uint256 b) internal pure returns (uint256 c) {
            // to avoid overflow, a <= (type(uint256).max - HALF_WAD) / b
            assembly {
              if iszero(or(iszero(b), iszero(gt(a, div(sub(not(0), HALF_WAD), b))))) {
                revert(0, 0)
              }
              c := div(add(mul(a, b), HALF_WAD), WAD)
            }
          }
          /**
           * @dev Divides two wad, rounding half up to the nearest wad
           * @dev assembly optimized for improved gas savings, see https://twitter.com/transmissions11/status/1451131036377571328
           * @param a Wad
           * @param b Wad
           * @return c = a/b, in wad
           */
          function wadDiv(uint256 a, uint256 b) internal pure returns (uint256 c) {
            // to avoid overflow, a <= (type(uint256).max - halfB) / WAD
            assembly {
              if or(iszero(b), iszero(iszero(gt(a, div(sub(not(0), div(b, 2)), WAD))))) {
                revert(0, 0)
              }
              c := div(add(mul(a, WAD), div(b, 2)), b)
            }
          }
          /**
           * @notice Multiplies two ray, rounding half up to the nearest ray
           * @dev assembly optimized for improved gas savings, see https://twitter.com/transmissions11/status/1451131036377571328
           * @param a Ray
           * @param b Ray
           * @return c = a raymul b
           */
          function rayMul(uint256 a, uint256 b) internal pure returns (uint256 c) {
            // to avoid overflow, a <= (type(uint256).max - HALF_RAY) / b
            assembly {
              if iszero(or(iszero(b), iszero(gt(a, div(sub(not(0), HALF_RAY), b))))) {
                revert(0, 0)
              }
              c := div(add(mul(a, b), HALF_RAY), RAY)
            }
          }
          /**
           * @notice Divides two ray, rounding half up to the nearest ray
           * @dev assembly optimized for improved gas savings, see https://twitter.com/transmissions11/status/1451131036377571328
           * @param a Ray
           * @param b Ray
           * @return c = a raydiv b
           */
          function rayDiv(uint256 a, uint256 b) internal pure returns (uint256 c) {
            // to avoid overflow, a <= (type(uint256).max - halfB) / RAY
            assembly {
              if or(iszero(b), iszero(iszero(gt(a, div(sub(not(0), div(b, 2)), RAY))))) {
                revert(0, 0)
              }
              c := div(add(mul(a, RAY), div(b, 2)), b)
            }
          }
          /**
           * @dev Casts ray down to wad
           * @dev assembly optimized for improved gas savings, see https://twitter.com/transmissions11/status/1451131036377571328
           * @param a Ray
           * @return b = a converted to wad, rounded half up to the nearest wad
           */
          function rayToWad(uint256 a) internal pure returns (uint256 b) {
            assembly {
              b := div(a, WAD_RAY_RATIO)
              let remainder := mod(a, WAD_RAY_RATIO)
              if iszero(lt(remainder, div(WAD_RAY_RATIO, 2))) {
                b := add(b, 1)
              }
            }
          }
          /**
           * @dev Converts wad up to ray
           * @dev assembly optimized for improved gas savings, see https://twitter.com/transmissions11/status/1451131036377571328
           * @param a Wad
           * @return b = a converted in ray
           */
          function wadToRay(uint256 a) internal pure returns (uint256 b) {
            // to avoid overflow, b/WAD_RAY_RATIO == a
            assembly {
              b := mul(a, WAD_RAY_RATIO)
              if iszero(eq(div(b, WAD_RAY_RATIO), a)) {
                revert(0, 0)
              }
            }
          }
        }
        // SPDX-License-Identifier: BUSL-1.1
        pragma solidity ^0.8.0;
        library DataTypes {
          struct ReserveData {
            //stores the reserve configuration
            ReserveConfigurationMap configuration;
            //the liquidity index. Expressed in ray
            uint128 liquidityIndex;
            //the current supply rate. Expressed in ray
            uint128 currentLiquidityRate;
            //variable borrow index. Expressed in ray
            uint128 variableBorrowIndex;
            //the current variable borrow rate. Expressed in ray
            uint128 currentVariableBorrowRate;
            //the current stable borrow rate. Expressed in ray
            uint128 currentStableBorrowRate;
            //timestamp of last update
            uint40 lastUpdateTimestamp;
            //the id of the reserve. Represents the position in the list of the active reserves
            uint16 id;
            //aToken address
            address aTokenAddress;
            //stableDebtToken address
            address stableDebtTokenAddress;
            //variableDebtToken address
            address variableDebtTokenAddress;
            //address of the interest rate strategy
            address interestRateStrategyAddress;
            //the current treasury balance, scaled
            uint128 accruedToTreasury;
            //the outstanding unbacked aTokens minted through the bridging feature
            uint128 unbacked;
            //the outstanding debt borrowed against this asset in isolation mode
            uint128 isolationModeTotalDebt;
          }
          struct ReserveConfigurationMap {
            //bit 0-15: LTV
            //bit 16-31: Liq. threshold
            //bit 32-47: Liq. bonus
            //bit 48-55: Decimals
            //bit 56: reserve is active
            //bit 57: reserve is frozen
            //bit 58: borrowing is enabled
            //bit 59: stable rate borrowing enabled
            //bit 60: asset is paused
            //bit 61: borrowing in isolation mode is enabled
            //bit 62-63: reserved
            //bit 64-79: reserve factor
            //bit 80-115 borrow cap in whole tokens, borrowCap == 0 => no cap
            //bit 116-151 supply cap in whole tokens, supplyCap == 0 => no cap
            //bit 152-167 liquidation protocol fee
            //bit 168-175 eMode category
            //bit 176-211 unbacked mint cap in whole tokens, unbackedMintCap == 0 => minting disabled
            //bit 212-251 debt ceiling for isolation mode with (ReserveConfiguration::DEBT_CEILING_DECIMALS) decimals
            //bit 252-255 unused
            uint256 data;
          }
          struct UserConfigurationMap {
            /**
             * @dev Bitmap of the users collaterals and borrows. It is divided in pairs of bits, one pair per asset.
             * The first bit indicates if an asset is used as collateral by the user, the second whether an
             * asset is borrowed by the user.
             */
            uint256 data;
          }
          struct EModeCategory {
            // each eMode category has a custom ltv and liquidation threshold
            uint16 ltv;
            uint16 liquidationThreshold;
            uint16 liquidationBonus;
            // each eMode category may or may not have a custom oracle to override the individual assets price oracles
            address priceSource;
            string label;
          }
          enum InterestRateMode {
            NONE,
            STABLE,
            VARIABLE
          }
          struct ReserveCache {
            uint256 currScaledVariableDebt;
            uint256 nextScaledVariableDebt;
            uint256 currPrincipalStableDebt;
            uint256 currAvgStableBorrowRate;
            uint256 currTotalStableDebt;
            uint256 nextAvgStableBorrowRate;
            uint256 nextTotalStableDebt;
            uint256 currLiquidityIndex;
            uint256 nextLiquidityIndex;
            uint256 currVariableBorrowIndex;
            uint256 nextVariableBorrowIndex;
            uint256 currLiquidityRate;
            uint256 currVariableBorrowRate;
            uint256 reserveFactor;
            ReserveConfigurationMap reserveConfiguration;
            address aTokenAddress;
            address stableDebtTokenAddress;
            address variableDebtTokenAddress;
            uint40 reserveLastUpdateTimestamp;
            uint40 stableDebtLastUpdateTimestamp;
          }
          struct ExecuteLiquidationCallParams {
            uint256 reservesCount;
            uint256 debtToCover;
            address collateralAsset;
            address debtAsset;
            address user;
            bool receiveAToken;
            address priceOracle;
            uint8 userEModeCategory;
            address priceOracleSentinel;
          }
          struct ExecuteSupplyParams {
            address asset;
            uint256 amount;
            address onBehalfOf;
            uint16 referralCode;
          }
          struct ExecuteBorrowParams {
            address asset;
            address user;
            address onBehalfOf;
            uint256 amount;
            InterestRateMode interestRateMode;
            uint16 referralCode;
            bool releaseUnderlying;
            uint256 maxStableRateBorrowSizePercent;
            uint256 reservesCount;
            address oracle;
            uint8 userEModeCategory;
            address priceOracleSentinel;
          }
          struct ExecuteRepayParams {
            address asset;
            uint256 amount;
            InterestRateMode interestRateMode;
            address onBehalfOf;
            bool useATokens;
          }
          struct ExecuteWithdrawParams {
            address asset;
            uint256 amount;
            address to;
            uint256 reservesCount;
            address oracle;
            uint8 userEModeCategory;
          }
          struct ExecuteSetUserEModeParams {
            uint256 reservesCount;
            address oracle;
            uint8 categoryId;
          }
          struct FinalizeTransferParams {
            address asset;
            address from;
            address to;
            uint256 amount;
            uint256 balanceFromBefore;
            uint256 balanceToBefore;
            uint256 reservesCount;
            address oracle;
            uint8 fromEModeCategory;
          }
          struct FlashloanParams {
            address receiverAddress;
            address[] assets;
            uint256[] amounts;
            uint256[] interestRateModes;
            address onBehalfOf;
            bytes params;
            uint16 referralCode;
            uint256 flashLoanPremiumToProtocol;
            uint256 flashLoanPremiumTotal;
            uint256 maxStableRateBorrowSizePercent;
            uint256 reservesCount;
            address addressesProvider;
            uint8 userEModeCategory;
            bool isAuthorizedFlashBorrower;
          }
          struct FlashloanSimpleParams {
            address receiverAddress;
            address asset;
            uint256 amount;
            bytes params;
            uint16 referralCode;
            uint256 flashLoanPremiumToProtocol;
            uint256 flashLoanPremiumTotal;
          }
          struct FlashLoanRepaymentParams {
            uint256 amount;
            uint256 totalPremium;
            uint256 flashLoanPremiumToProtocol;
            address asset;
            address receiverAddress;
            uint16 referralCode;
          }
          struct CalculateUserAccountDataParams {
            UserConfigurationMap userConfig;
            uint256 reservesCount;
            address user;
            address oracle;
            uint8 userEModeCategory;
          }
          struct ValidateBorrowParams {
            ReserveCache reserveCache;
            UserConfigurationMap userConfig;
            address asset;
            address userAddress;
            uint256 amount;
            InterestRateMode interestRateMode;
            uint256 maxStableLoanPercent;
            uint256 reservesCount;
            address oracle;
            uint8 userEModeCategory;
            address priceOracleSentinel;
            bool isolationModeActive;
            address isolationModeCollateralAddress;
            uint256 isolationModeDebtCeiling;
          }
          struct ValidateLiquidationCallParams {
            ReserveCache debtReserveCache;
            uint256 totalDebt;
            uint256 healthFactor;
            address priceOracleSentinel;
          }
          struct CalculateInterestRatesParams {
            uint256 unbacked;
            uint256 liquidityAdded;
            uint256 liquidityTaken;
            uint256 totalStableDebt;
            uint256 totalVariableDebt;
            uint256 averageStableBorrowRate;
            uint256 reserveFactor;
            address reserve;
            address aToken;
          }
          struct InitReserveParams {
            address asset;
            address aTokenAddress;
            address stableDebtAddress;
            address variableDebtAddress;
            address interestRateStrategyAddress;
            uint16 reservesCount;
            uint16 maxNumberReserves;
          }
        }
        // SPDX-License-Identifier: BUSL-1.1
        pragma solidity 0.8.10;
        import {IERC20} from '../../dependencies/openzeppelin/contracts/IERC20.sol';
        import {GPv2SafeERC20} from '../../dependencies/gnosis/contracts/GPv2SafeERC20.sol';
        import {SafeCast} from '../../dependencies/openzeppelin/contracts/SafeCast.sol';
        import {VersionedInitializable} from '../libraries/aave-upgradeability/VersionedInitializable.sol';
        import {Errors} from '../libraries/helpers/Errors.sol';
        import {WadRayMath} from '../libraries/math/WadRayMath.sol';
        import {IPool} from '../../interfaces/IPool.sol';
        import {IAToken} from '../../interfaces/IAToken.sol';
        import {IAaveIncentivesController} from '../../interfaces/IAaveIncentivesController.sol';
        import {IInitializableAToken} from '../../interfaces/IInitializableAToken.sol';
        import {ScaledBalanceTokenBase} from './base/ScaledBalanceTokenBase.sol';
        import {IncentivizedERC20} from './base/IncentivizedERC20.sol';
        import {EIP712Base} from './base/EIP712Base.sol';
        /**
         * @title Aave ERC20 AToken
         * @author Aave
         * @notice Implementation of the interest bearing token for the Aave protocol
         */
        contract AToken is VersionedInitializable, ScaledBalanceTokenBase, EIP712Base, IAToken {
          using WadRayMath for uint256;
          using SafeCast for uint256;
          using GPv2SafeERC20 for IERC20;
          bytes32 public constant PERMIT_TYPEHASH =
            keccak256('Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)');
          uint256 public constant ATOKEN_REVISION = 0x1;
          address internal _treasury;
          address internal _underlyingAsset;
          /// @inheritdoc VersionedInitializable
          function getRevision() internal pure virtual override returns (uint256) {
            return ATOKEN_REVISION;
          }
          /**
           * @dev Constructor.
           * @param pool The address of the Pool contract
           */
          constructor(IPool pool)
            ScaledBalanceTokenBase(pool, 'ATOKEN_IMPL', 'ATOKEN_IMPL', 0)
            EIP712Base()
          {
            // Intentionally left blank
          }
          /// @inheritdoc IInitializableAToken
          function initialize(
            IPool initializingPool,
            address treasury,
            address underlyingAsset,
            IAaveIncentivesController incentivesController,
            uint8 aTokenDecimals,
            string calldata aTokenName,
            string calldata aTokenSymbol,
            bytes calldata params
          ) public virtual override initializer {
            require(initializingPool == POOL, Errors.POOL_ADDRESSES_DO_NOT_MATCH);
            _setName(aTokenName);
            _setSymbol(aTokenSymbol);
            _setDecimals(aTokenDecimals);
            _treasury = treasury;
            _underlyingAsset = underlyingAsset;
            _incentivesController = incentivesController;
            _domainSeparator = _calculateDomainSeparator();
            emit Initialized(
              underlyingAsset,
              address(POOL),
              treasury,
              address(incentivesController),
              aTokenDecimals,
              aTokenName,
              aTokenSymbol,
              params
            );
          }
          /// @inheritdoc IAToken
          function mint(
            address caller,
            address onBehalfOf,
            uint256 amount,
            uint256 index
          ) external virtual override onlyPool returns (bool) {
            return _mintScaled(caller, onBehalfOf, amount, index);
          }
          /// @inheritdoc IAToken
          function burn(
            address from,
            address receiverOfUnderlying,
            uint256 amount,
            uint256 index
          ) external virtual override onlyPool {
            _burnScaled(from, receiverOfUnderlying, amount, index);
            if (receiverOfUnderlying != address(this)) {
              IERC20(_underlyingAsset).safeTransfer(receiverOfUnderlying, amount);
            }
          }
          /// @inheritdoc IAToken
          function mintToTreasury(uint256 amount, uint256 index) external virtual override onlyPool {
            if (amount == 0) {
              return;
            }
            _mintScaled(address(POOL), _treasury, amount, index);
          }
          /// @inheritdoc IAToken
          function transferOnLiquidation(
            address from,
            address to,
            uint256 value
          ) external virtual override onlyPool {
            // Being a normal transfer, the Transfer() and BalanceTransfer() are emitted
            // so no need to emit a specific event here
            _transfer(from, to, value, false);
          }
          /// @inheritdoc IERC20
          function balanceOf(address user)
            public
            view
            virtual
            override(IncentivizedERC20, IERC20)
            returns (uint256)
          {
            return super.balanceOf(user).rayMul(POOL.getReserveNormalizedIncome(_underlyingAsset));
          }
          /// @inheritdoc IERC20
          function totalSupply() public view virtual override(IncentivizedERC20, IERC20) returns (uint256) {
            uint256 currentSupplyScaled = super.totalSupply();
            if (currentSupplyScaled == 0) {
              return 0;
            }
            return currentSupplyScaled.rayMul(POOL.getReserveNormalizedIncome(_underlyingAsset));
          }
          /// @inheritdoc IAToken
          function RESERVE_TREASURY_ADDRESS() external view override returns (address) {
            return _treasury;
          }
          /// @inheritdoc IAToken
          function UNDERLYING_ASSET_ADDRESS() external view override returns (address) {
            return _underlyingAsset;
          }
          /// @inheritdoc IAToken
          function transferUnderlyingTo(address target, uint256 amount) external virtual override onlyPool {
            IERC20(_underlyingAsset).safeTransfer(target, amount);
          }
          /// @inheritdoc IAToken
          function handleRepayment(
            address user,
            address onBehalfOf,
            uint256 amount
          ) external virtual override onlyPool {
            // Intentionally left blank
          }
          /// @inheritdoc IAToken
          function permit(
            address owner,
            address spender,
            uint256 value,
            uint256 deadline,
            uint8 v,
            bytes32 r,
            bytes32 s
          ) external override {
            require(owner != address(0), Errors.ZERO_ADDRESS_NOT_VALID);
            //solium-disable-next-line
            require(block.timestamp <= deadline, Errors.INVALID_EXPIRATION);
            uint256 currentValidNonce = _nonces[owner];
            bytes32 digest = keccak256(
              abi.encodePacked(
                '\\x19\\x01',
                DOMAIN_SEPARATOR(),
                keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, currentValidNonce, deadline))
              )
            );
            require(owner == ecrecover(digest, v, r, s), Errors.INVALID_SIGNATURE);
            _nonces[owner] = currentValidNonce + 1;
            _approve(owner, spender, value);
          }
          /**
           * @notice Transfers the aTokens between two users. Validates the transfer
           * (ie checks for valid HF after the transfer) if required
           * @param from The source address
           * @param to The destination address
           * @param amount The amount getting transferred
           * @param validate True if the transfer needs to be validated, false otherwise
           */
          function _transfer(
            address from,
            address to,
            uint256 amount,
            bool validate
          ) internal virtual {
            address underlyingAsset = _underlyingAsset;
            uint256 index = POOL.getReserveNormalizedIncome(underlyingAsset);
            uint256 fromBalanceBefore = super.balanceOf(from).rayMul(index);
            uint256 toBalanceBefore = super.balanceOf(to).rayMul(index);
            super._transfer(from, to, amount, index);
            if (validate) {
              POOL.finalizeTransfer(underlyingAsset, from, to, amount, fromBalanceBefore, toBalanceBefore);
            }
            emit BalanceTransfer(from, to, amount.rayDiv(index), index);
          }
          /**
           * @notice Overrides the parent _transfer to force validated transfer() and transferFrom()
           * @param from The source address
           * @param to The destination address
           * @param amount The amount getting transferred
           */
          function _transfer(
            address from,
            address to,
            uint128 amount
          ) internal virtual override {
            _transfer(from, to, amount, true);
          }
          /**
           * @dev Overrides the base function to fully implement IAToken
           * @dev see `EIP712Base.DOMAIN_SEPARATOR()` for more detailed documentation
           */
          function DOMAIN_SEPARATOR() public view override(IAToken, EIP712Base) returns (bytes32) {
            return super.DOMAIN_SEPARATOR();
          }
          /**
           * @dev Overrides the base function to fully implement IAToken
           * @dev see `EIP712Base.nonces()` for more detailed documentation
           */
          function nonces(address owner) public view override(IAToken, EIP712Base) returns (uint256) {
            return super.nonces(owner);
          }
          /// @inheritdoc EIP712Base
          function _EIP712BaseId() internal view override returns (string memory) {
            return name();
          }
          /// @inheritdoc IAToken
          function rescueTokens(
            address token,
            address to,
            uint256 amount
          ) external override onlyPoolAdmin {
            require(token != _underlyingAsset, Errors.UNDERLYING_CANNOT_BE_RESCUED);
            IERC20(token).safeTransfer(to, amount);
          }
        }
        // SPDX-License-Identifier: BUSL-1.1
        pragma solidity 0.8.10;
        /**
         * @title EIP712Base
         * @author Aave
         * @notice Base contract implementation of EIP712.
         */
        abstract contract EIP712Base {
          bytes public constant EIP712_REVISION = bytes('1');
          bytes32 internal constant EIP712_DOMAIN =
            keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)');
          // Map of address nonces (address => nonce)
          mapping(address => uint256) internal _nonces;
          bytes32 internal _domainSeparator;
          uint256 internal immutable _chainId;
          /**
           * @dev Constructor.
           */
          constructor() {
            _chainId = block.chainid;
          }
          /**
           * @notice Get the domain separator for the token
           * @dev Return cached value if chainId matches cache, otherwise recomputes separator
           * @return The domain separator of the token at current chain
           */
          function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
            if (block.chainid == _chainId) {
              return _domainSeparator;
            }
            return _calculateDomainSeparator();
          }
          /**
           * @notice Returns the nonce value for address specified as parameter
           * @param owner The address for which the nonce is being returned
           * @return The nonce value for the input address`
           */
          function nonces(address owner) public view virtual returns (uint256) {
            return _nonces[owner];
          }
          /**
           * @notice Compute the current domain separator
           * @return The domain separator for the token
           */
          function _calculateDomainSeparator() internal view returns (bytes32) {
            return
              keccak256(
                abi.encode(
                  EIP712_DOMAIN,
                  keccak256(bytes(_EIP712BaseId())),
                  keccak256(EIP712_REVISION),
                  block.chainid,
                  address(this)
                )
              );
          }
          /**
           * @notice Returns the user readable name of signing domain (e.g. token name)
           * @return The name of the signing domain
           */
          function _EIP712BaseId() internal view virtual returns (string memory);
        }
        // SPDX-License-Identifier: BUSL-1.1
        pragma solidity 0.8.10;
        import {Context} from '../../../dependencies/openzeppelin/contracts/Context.sol';
        import {IERC20} from '../../../dependencies/openzeppelin/contracts/IERC20.sol';
        import {IERC20Detailed} from '../../../dependencies/openzeppelin/contracts/IERC20Detailed.sol';
        import {SafeCast} from '../../../dependencies/openzeppelin/contracts/SafeCast.sol';
        import {WadRayMath} from '../../libraries/math/WadRayMath.sol';
        import {Errors} from '../../libraries/helpers/Errors.sol';
        import {IAaveIncentivesController} from '../../../interfaces/IAaveIncentivesController.sol';
        import {IPoolAddressesProvider} from '../../../interfaces/IPoolAddressesProvider.sol';
        import {IPool} from '../../../interfaces/IPool.sol';
        import {IACLManager} from '../../../interfaces/IACLManager.sol';
        /**
         * @title IncentivizedERC20
         * @author Aave, inspired by the Openzeppelin ERC20 implementation
         * @notice Basic ERC20 implementation
         */
        abstract contract IncentivizedERC20 is Context, IERC20Detailed {
          using WadRayMath for uint256;
          using SafeCast for uint256;
          /**
           * @dev Only pool admin can call functions marked by this modifier.
           */
          modifier onlyPoolAdmin() {
            IACLManager aclManager = IACLManager(_addressesProvider.getACLManager());
            require(aclManager.isPoolAdmin(msg.sender), Errors.CALLER_NOT_POOL_ADMIN);
            _;
          }
          /**
           * @dev Only pool can call functions marked by this modifier.
           */
          modifier onlyPool() {
            require(_msgSender() == address(POOL), Errors.CALLER_MUST_BE_POOL);
            _;
          }
          /**
           * @dev UserState - additionalData is a flexible field.
           * ATokens and VariableDebtTokens use this field store the index of the
           * user's last supply/withdrawal/borrow/repayment. StableDebtTokens use
           * this field to store the user's stable rate.
           */
          struct UserState {
            uint128 balance;
            uint128 additionalData;
          }
          // Map of users address and their state data (userAddress => userStateData)
          mapping(address => UserState) internal _userState;
          // Map of allowances (delegator => delegatee => allowanceAmount)
          mapping(address => mapping(address => uint256)) private _allowances;
          uint256 internal _totalSupply;
          string private _name;
          string private _symbol;
          uint8 private _decimals;
          IAaveIncentivesController internal _incentivesController;
          IPoolAddressesProvider internal immutable _addressesProvider;
          IPool public immutable POOL;
          /**
           * @dev Constructor.
           * @param pool The reference to the main Pool contract
           * @param name The name of the token
           * @param symbol The symbol of the token
           * @param decimals The number of decimals of the token
           */
          constructor(
            IPool pool,
            string memory name,
            string memory symbol,
            uint8 decimals
          ) {
            _addressesProvider = pool.ADDRESSES_PROVIDER();
            _name = name;
            _symbol = symbol;
            _decimals = decimals;
            POOL = pool;
          }
          /// @inheritdoc IERC20Detailed
          function name() public view override returns (string memory) {
            return _name;
          }
          /// @inheritdoc IERC20Detailed
          function symbol() external view override returns (string memory) {
            return _symbol;
          }
          /// @inheritdoc IERC20Detailed
          function decimals() external view override returns (uint8) {
            return _decimals;
          }
          /// @inheritdoc IERC20
          function totalSupply() public view virtual override returns (uint256) {
            return _totalSupply;
          }
          /// @inheritdoc IERC20
          function balanceOf(address account) public view virtual override returns (uint256) {
            return _userState[account].balance;
          }
          /**
           * @notice Returns the address of the Incentives Controller contract
           * @return The address of the Incentives Controller
           */
          function getIncentivesController() external view virtual returns (IAaveIncentivesController) {
            return _incentivesController;
          }
          /**
           * @notice Sets a new Incentives Controller
           * @param controller the new Incentives controller
           */
          function setIncentivesController(IAaveIncentivesController controller) external onlyPoolAdmin {
            _incentivesController = controller;
          }
          /// @inheritdoc IERC20
          function transfer(address recipient, uint256 amount) external virtual override returns (bool) {
            uint128 castAmount = amount.toUint128();
            _transfer(_msgSender(), recipient, castAmount);
            return true;
          }
          /// @inheritdoc IERC20
          function allowance(address owner, address spender)
            external
            view
            virtual
            override
            returns (uint256)
          {
            return _allowances[owner][spender];
          }
          /// @inheritdoc IERC20
          function approve(address spender, uint256 amount) external virtual override returns (bool) {
            _approve(_msgSender(), spender, amount);
            return true;
          }
          /// @inheritdoc IERC20
          function transferFrom(
            address sender,
            address recipient,
            uint256 amount
          ) external virtual override returns (bool) {
            uint128 castAmount = amount.toUint128();
            _approve(sender, _msgSender(), _allowances[sender][_msgSender()] - castAmount);
            _transfer(sender, recipient, castAmount);
            return true;
          }
          /**
           * @notice Increases the allowance of spender to spend _msgSender() tokens
           * @param spender The user allowed to spend on behalf of _msgSender()
           * @param addedValue The amount being added to the allowance
           * @return `true`
           */
          function increaseAllowance(address spender, uint256 addedValue) external virtual returns (bool) {
            _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);
            return true;
          }
          /**
           * @notice Decreases the allowance of spender to spend _msgSender() tokens
           * @param spender The user allowed to spend on behalf of _msgSender()
           * @param subtractedValue The amount being subtracted to the allowance
           * @return `true`
           */
          function decreaseAllowance(address spender, uint256 subtractedValue)
            external
            virtual
            returns (bool)
          {
            _approve(_msgSender(), spender, _allowances[_msgSender()][spender] - subtractedValue);
            return true;
          }
          /**
           * @notice Transfers tokens between two users and apply incentives if defined.
           * @param sender The source address
           * @param recipient The destination address
           * @param amount The amount getting transferred
           */
          function _transfer(
            address sender,
            address recipient,
            uint128 amount
          ) internal virtual {
            uint128 oldSenderBalance = _userState[sender].balance;
            _userState[sender].balance = oldSenderBalance - amount;
            uint128 oldRecipientBalance = _userState[recipient].balance;
            _userState[recipient].balance = oldRecipientBalance + amount;
            IAaveIncentivesController incentivesControllerLocal = _incentivesController;
            if (address(incentivesControllerLocal) != address(0)) {
              uint256 currentTotalSupply = _totalSupply;
              incentivesControllerLocal.handleAction(sender, currentTotalSupply, oldSenderBalance);
              if (sender != recipient) {
                incentivesControllerLocal.handleAction(recipient, currentTotalSupply, oldRecipientBalance);
              }
            }
          }
          /**
           * @notice Approve `spender` to use `amount` of `owner`s balance
           * @param owner The address owning the tokens
           * @param spender The address approved for spending
           * @param amount The amount of tokens to approve spending of
           */
          function _approve(
            address owner,
            address spender,
            uint256 amount
          ) internal virtual {
            _allowances[owner][spender] = amount;
            emit Approval(owner, spender, amount);
          }
          /**
           * @notice Update the name of the token
           * @param newName The new name for the token
           */
          function _setName(string memory newName) internal {
            _name = newName;
          }
          /**
           * @notice Update the symbol for the token
           * @param newSymbol The new symbol for the token
           */
          function _setSymbol(string memory newSymbol) internal {
            _symbol = newSymbol;
          }
          /**
           * @notice Update the number of decimals for the token
           * @param newDecimals The new number of decimals for the token
           */
          function _setDecimals(uint8 newDecimals) internal {
            _decimals = newDecimals;
          }
        }
        // SPDX-License-Identifier: BUSL-1.1
        pragma solidity 0.8.10;
        import {IAaveIncentivesController} from '../../../interfaces/IAaveIncentivesController.sol';
        import {IPool} from '../../../interfaces/IPool.sol';
        import {IncentivizedERC20} from './IncentivizedERC20.sol';
        /**
         * @title MintableIncentivizedERC20
         * @author Aave
         * @notice Implements mint and burn functions for IncentivizedERC20
         */
        abstract contract MintableIncentivizedERC20 is IncentivizedERC20 {
          /**
           * @dev Constructor.
           * @param pool The reference to the main Pool contract
           * @param name The name of the token
           * @param symbol The symbol of the token
           * @param decimals The number of decimals of the token
           */
          constructor(
            IPool pool,
            string memory name,
            string memory symbol,
            uint8 decimals
          ) IncentivizedERC20(pool, name, symbol, decimals) {
            // Intentionally left blank
          }
          /**
           * @notice Mints tokens to an account and apply incentives if defined
           * @param account The address receiving tokens
           * @param amount The amount of tokens to mint
           */
          function _mint(address account, uint128 amount) internal virtual {
            uint256 oldTotalSupply = _totalSupply;
            _totalSupply = oldTotalSupply + amount;
            uint128 oldAccountBalance = _userState[account].balance;
            _userState[account].balance = oldAccountBalance + amount;
            IAaveIncentivesController incentivesControllerLocal = _incentivesController;
            if (address(incentivesControllerLocal) != address(0)) {
              incentivesControllerLocal.handleAction(account, oldTotalSupply, oldAccountBalance);
            }
          }
          /**
           * @notice Burns tokens from an account and apply incentives if defined
           * @param account The account whose tokens are burnt
           * @param amount The amount of tokens to burn
           */
          function _burn(address account, uint128 amount) internal virtual {
            uint256 oldTotalSupply = _totalSupply;
            _totalSupply = oldTotalSupply - amount;
            uint128 oldAccountBalance = _userState[account].balance;
            _userState[account].balance = oldAccountBalance - amount;
            IAaveIncentivesController incentivesControllerLocal = _incentivesController;
            if (address(incentivesControllerLocal) != address(0)) {
              incentivesControllerLocal.handleAction(account, oldTotalSupply, oldAccountBalance);
            }
          }
        }
        // SPDX-License-Identifier: BUSL-1.1
        pragma solidity 0.8.10;
        import {SafeCast} from '../../../dependencies/openzeppelin/contracts/SafeCast.sol';
        import {Errors} from '../../libraries/helpers/Errors.sol';
        import {WadRayMath} from '../../libraries/math/WadRayMath.sol';
        import {IPool} from '../../../interfaces/IPool.sol';
        import {IScaledBalanceToken} from '../../../interfaces/IScaledBalanceToken.sol';
        import {MintableIncentivizedERC20} from './MintableIncentivizedERC20.sol';
        /**
         * @title ScaledBalanceTokenBase
         * @author Aave
         * @notice Basic ERC20 implementation of scaled balance token
         */
        abstract contract ScaledBalanceTokenBase is MintableIncentivizedERC20, IScaledBalanceToken {
          using WadRayMath for uint256;
          using SafeCast for uint256;
          /**
           * @dev Constructor.
           * @param pool The reference to the main Pool contract
           * @param name The name of the token
           * @param symbol The symbol of the token
           * @param decimals The number of decimals of the token
           */
          constructor(
            IPool pool,
            string memory name,
            string memory symbol,
            uint8 decimals
          ) MintableIncentivizedERC20(pool, name, symbol, decimals) {
            // Intentionally left blank
          }
          /// @inheritdoc IScaledBalanceToken
          function scaledBalanceOf(address user) external view override returns (uint256) {
            return super.balanceOf(user);
          }
          /// @inheritdoc IScaledBalanceToken
          function getScaledUserBalanceAndSupply(address user)
            external
            view
            override
            returns (uint256, uint256)
          {
            return (super.balanceOf(user), super.totalSupply());
          }
          /// @inheritdoc IScaledBalanceToken
          function scaledTotalSupply() public view virtual override returns (uint256) {
            return super.totalSupply();
          }
          /// @inheritdoc IScaledBalanceToken
          function getPreviousIndex(address user) external view virtual override returns (uint256) {
            return _userState[user].additionalData;
          }
          /**
           * @notice Implements the basic logic to mint a scaled balance token.
           * @param caller The address performing the mint
           * @param onBehalfOf The address of the user that will receive the scaled tokens
           * @param amount The amount of tokens getting minted
           * @param index The next liquidity index of the reserve
           * @return `true` if the the previous balance of the user was 0
           */
          function _mintScaled(
            address caller,
            address onBehalfOf,
            uint256 amount,
            uint256 index
          ) internal returns (bool) {
            uint256 amountScaled = amount.rayDiv(index);
            require(amountScaled != 0, Errors.INVALID_MINT_AMOUNT);
            uint256 scaledBalance = super.balanceOf(onBehalfOf);
            uint256 balanceIncrease = scaledBalance.rayMul(index) -
              scaledBalance.rayMul(_userState[onBehalfOf].additionalData);
            _userState[onBehalfOf].additionalData = index.toUint128();
            _mint(onBehalfOf, amountScaled.toUint128());
            uint256 amountToMint = amount + balanceIncrease;
            emit Transfer(address(0), onBehalfOf, amountToMint);
            emit Mint(caller, onBehalfOf, amountToMint, balanceIncrease, index);
            return (scaledBalance == 0);
          }
          /**
           * @notice Implements the basic logic to burn a scaled balance token.
           * @dev In some instances, a burn transaction will emit a mint event
           * if the amount to burn is less than the interest that the user accrued
           * @param user The user which debt is burnt
           * @param target The address that will receive the underlying, if any
           * @param amount The amount getting burned
           * @param index The variable debt index of the reserve
           */
          function _burnScaled(
            address user,
            address target,
            uint256 amount,
            uint256 index
          ) internal {
            uint256 amountScaled = amount.rayDiv(index);
            require(amountScaled != 0, Errors.INVALID_BURN_AMOUNT);
            uint256 scaledBalance = super.balanceOf(user);
            uint256 balanceIncrease = scaledBalance.rayMul(index) -
              scaledBalance.rayMul(_userState[user].additionalData);
            _userState[user].additionalData = index.toUint128();
            _burn(user, amountScaled.toUint128());
            if (balanceIncrease > amount) {
              uint256 amountToMint = balanceIncrease - amount;
              emit Transfer(address(0), user, amountToMint);
              emit Mint(user, user, amountToMint, balanceIncrease, index);
            } else {
              uint256 amountToBurn = amount - balanceIncrease;
              emit Transfer(user, address(0), amountToBurn);
              emit Burn(user, target, amountToBurn, balanceIncrease, index);
            }
          }
          /**
           * @notice Implements the basic logic to transfer scaled balance tokens between two users
           * @dev It emits a mint event with the interest accrued per user
           * @param sender The source address
           * @param recipient The destination address
           * @param amount The amount getting transferred
           * @param index The next liquidity index of the reserve
           */
          function _transfer(
            address sender,
            address recipient,
            uint256 amount,
            uint256 index
          ) internal {
            uint256 senderScaledBalance = super.balanceOf(sender);
            uint256 senderBalanceIncrease = senderScaledBalance.rayMul(index) -
              senderScaledBalance.rayMul(_userState[sender].additionalData);
            uint256 recipientScaledBalance = super.balanceOf(recipient);
            uint256 recipientBalanceIncrease = recipientScaledBalance.rayMul(index) -
              recipientScaledBalance.rayMul(_userState[recipient].additionalData);
            _userState[sender].additionalData = index.toUint128();
            _userState[recipient].additionalData = index.toUint128();
            super._transfer(sender, recipient, amount.rayDiv(index).toUint128());
            if (senderBalanceIncrease > 0) {
              emit Transfer(address(0), sender, senderBalanceIncrease);
              emit Mint(_msgSender(), sender, senderBalanceIncrease, senderBalanceIncrease, index);
            }
            if (sender != recipient && recipientBalanceIncrease > 0) {
              emit Transfer(address(0), recipient, recipientBalanceIncrease);
              emit Mint(_msgSender(), recipient, recipientBalanceIncrease, recipientBalanceIncrease, index);
            }
            emit Transfer(sender, recipient, amount);
          }
        }