ETH Price: $1,949.26 (-1.90%)

Transaction Decoder

Block:
24507295 at Feb-21-2026 07:20:47 PM +UTC
Transaction Fee:
0.00001311854584265 ETH $0.03
Gas Used:
295,775 Gas / 0.044353126 Gwei

Emitted Events:

591 InitializableImmutableAdminUpgradeabilityProxy.0x804c9b842b2748a22bb64b345453a3de7ca54a6ca45ce00d415894979e22897a( 0x804c9b842b2748a22bb64b345453a3de7ca54a6ca45ce00d415894979e22897a, 0x000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7, 00000000000000000000000000000000000000000012cf4a490ef6c7f878a7fc, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000001ea6f6c806863a619a7c88, 000000000000000000000000000000000000000003bbfc92e1a2c4e2df70e3f6, 000000000000000000000000000000000000000003ee6262b9a5ec70a03a4015 )
592 InitializableImmutableAdminUpgradeabilityProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x0000000000000000000000000000000000000000000000000000000000000000, 0x0000000000000000000000002b817b822b0ddd4597a92dbed1bd0a6796ca37e0, 0000000000000000000000000000000000000000000000000000000006331a6e )
593 InitializableImmutableAdminUpgradeabilityProxy.0x458f5fa412d0f69b08dd84872b0215675cc67bc1d5b6fd93300a1c3878b86196( 0x458f5fa412d0f69b08dd84872b0215675cc67bc1d5b6fd93300a1c3878b86196, 0x0000000000000000000000002b817b822b0ddd4597a92dbed1bd0a6796ca37e0, 0x0000000000000000000000002b817b822b0ddd4597a92dbed1bd0a6796ca37e0, 0000000000000000000000000000000000000000000000000000000006331a6e, 0000000000000000000000000000000000000000000000000000000006e372b3, 000000000000000000000000000000000000000003bbfc92e1a2c4e2df70e3f6 )
594 TetherToken.Transfer( from=InitializableImmutableAdminUpgradeabilityProxy, to=MapleTreasury, value=11556933 )
595 InitializableImmutableAdminUpgradeabilityProxy.0x3115d1449a7b732c986cba18244e897a450f61e1bb8d589cd2e69e6c8924f9f7( 0x3115d1449a7b732c986cba18244e897a450f61e1bb8d589cd2e69e6c8924f9f7, 0x000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7, 0x0000000000000000000000002b817b822b0ddd4597a92dbed1bd0a6796ca37e0, 0x000000000000000000000000a9466eabd096449d650d5aeb0dd3da6f52fd0b19, 0000000000000000000000000000000000000000000000000000000000b05845 )
596 0x2b817b822b0ddd4597a92dbed1bd0a6796ca37e0.0x9276f1867fd63028a391b04a7ea7ad4772dd6eb3c65b9d84d43a4191deafa585( 0x9276f1867fd63028a391b04a7ea7ad4772dd6eb3c65b9d84d43a4191deafa585, 0000000000000000000000000000000000000000000000000000000000b05845 )
597 InitializableImmutableAdminUpgradeabilityProxy.0x804c9b842b2748a22bb64b345453a3de7ca54a6ca45ce00d415894979e22897a( 0x804c9b842b2748a22bb64b345453a3de7ca54a6ca45ce00d415894979e22897a, 0x000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7, 00000000000000000000000000000000000000000012cf9b1f5b4d7c0cae1897, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000001ea738a568da25baae47a9, 000000000000000000000000000000000000000003bbfc92e1a2c4e2df70e3f6, 000000000000000000000000000000000000000003ee6262b9a5ec70a03a4015 )
598 InitializableImmutableAdminUpgradeabilityProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x0000000000000000000000002b817b822b0ddd4597a92dbed1bd0a6796ca37e0, 0x0000000000000000000000000000000000000000000000000000000000000000, 000000000000000000000000000000000000000000000000000000266e37c392 )
599 InitializableImmutableAdminUpgradeabilityProxy.0x4cf25bc1d991c17529c25213d3cc0cda295eeaad5f13f361969b12ea48015f90( 0x4cf25bc1d991c17529c25213d3cc0cda295eeaad5f13f361969b12ea48015f90, 0x0000000000000000000000002b817b822b0ddd4597a92dbed1bd0a6796ca37e0, 0x000000000000000000000000356b8d89c1e1239cbbb9de4815c39a1474d5ba7d, 000000000000000000000000000000000000000000000000000000266e37c392, 0000000000000000000000000000000000000000000000000000000000000000, 000000000000000000000000000000000000000003bbfc92e1a2c4e2df70e3f6 )
600 TetherToken.Transfer( from=InitializableImmutableAdminUpgradeabilityProxy, to=MaplePool, value=165057905553 )
601 InitializableImmutableAdminUpgradeabilityProxy.0x3115d1449a7b732c986cba18244e897a450f61e1bb8d589cd2e69e6c8924f9f7( 0x3115d1449a7b732c986cba18244e897a450f61e1bb8d589cd2e69e6c8924f9f7, 0x000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7, 0x0000000000000000000000002b817b822b0ddd4597a92dbed1bd0a6796ca37e0, 0x000000000000000000000000356b8d89c1e1239cbbb9de4815c39a1474d5ba7d, 000000000000000000000000000000000000000000000000000000266e37c391 )
602 0x2b817b822b0ddd4597a92dbed1bd0a6796ca37e0.0x1e3b88c775a5ef3ca37ef9424a3dde5b6328b543e7ea0d0250804698030bf29a( 0x1e3b88c775a5ef3ca37ef9424a3dde5b6328b543e7ea0d0250804698030bf29a, 000000000000000000000000000000000000000000000000000000266e37c391 )

Account State Difference:

  Address   Before After State Difference Code
0x23878914...A74D4086a
0x2b817B82...796CA37E0
(quasarbuilder)
20.85011031507206426 Eth20.850110329343503785 Eth0.000000014271439525
0x87870Bca...50B4fA4E2
(Aave: Pool V3)
0xdAC17F95...13D831ec7
0xfB2C579c...26bd22b62
0.833402588113448211 Eth
Nonce: 23137
0.833389469567605561 Eth
Nonce: 23138
0.00001311854584265

Execution Trace

0x2b817b822b0ddd4597a92dbed1bd0a6796ca37e0.48b19335( )
  • MapleAaveStrategy.withdrawFromStrategy( assetsOut_=165057905553 )
    • 0x01ab799f77f9a9f4dd0d2b6e7c83dcf3f48d5650.STATICCALL( )
    • NonTransparentProxy.4c532de1( )
      • MapleGlobals.isFunctionPaused( sig_=System.Byte[] ) => ( functionIsPaused_=False )
      • Proxy.STATICCALL( )
        • MaplePoolManager.DELEGATECALL( )
        • 0x01ab799f77f9a9f4dd0d2b6e7c83dcf3f48d5650.STATICCALL( )
        • NonTransparentProxy.305c9e05( )
          • MapleGlobals.isInstanceOf( 53545241544547595F4D414E4147455200000000000000000000000000000000, 0xfB2C579c1D5f82C7b0f2a3479e5F9bC26bd22b62 ) => ( True )
          • InitializableImmutableAdminUpgradeabilityProxy.70a08231( )
            • 0xadc45df3cf1584624c97338bef33363bf5b97ada.70a08231( )
              • InitializableImmutableAdminUpgradeabilityProxy.d15e0053( )
                • 0x8147b99df7672a21809c9093e6f6ce1a60f119bd.d15e0053( )
                • InitializableImmutableAdminUpgradeabilityProxy.70a08231( )
                  • 0xadc45df3cf1584624c97338bef33363bf5b97ada.70a08231( )
                    • InitializableImmutableAdminUpgradeabilityProxy.d15e0053( )
                      • 0x8147b99df7672a21809c9093e6f6ce1a60f119bd.d15e0053( )
                      • 0x01ab799f77f9a9f4dd0d2b6e7c83dcf3f48d5650.STATICCALL( )
                      • NonTransparentProxy.STATICCALL( )
                        • MapleGlobals.DELEGATECALL( )
                        • InitializableImmutableAdminUpgradeabilityProxy.69328dec( )
                          • 0x8147b99df7672a21809c9093e6f6ce1a60f119bd.69328dec( )
                            • PoolAddressesProvider.STATICCALL( )
                            • 0x33654b16a4de97bce05d7dd06803bf1066f3123c.186dea44( )
                              • InitializableImmutableAdminUpgradeabilityProxy.STATICCALL( )
                                • 0xb27c52c7f84819e3157993489741cb60786ae330.DELEGATECALL( )
                                • InitializableImmutableAdminUpgradeabilityProxy.1da24f3e( )
                                  • 0xadc45df3cf1584624c97338bef33363bf5b97ada.1da24f3e( )
                                  • DefaultReserveInterestRateStrategyV2.calculateInterestRates( params=[{name:unbacked, type:uint256, order:1, indexed:false, value:10153484192, valueString:10153484192}, {name:liquidityAdded, type:uint256, order:2, indexed:false, value:0, valueString:0}, {name:liquidityTaken, type:uint256, order:3, indexed:false, value:11556933, valueString:11556933}, {name:totalDebt, type:uint256, order:4, indexed:false, value:3432559771843756, valueString:3432559771843756}, {name:reserveFactor, type:uint256, order:5, indexed:false, value:1000, valueString:1000}, {name:reserve, type:address, order:6, indexed:false, value:0xdAC17F958D2ee523a2206206994597C13D831ec7, valueString:0xdAC17F958D2ee523a2206206994597C13D831ec7}, {name:usingVirtualBalance, type:bool, order:7, indexed:false, value:true, valueString:True}, {name:virtualUnderlyingBalance, type:uint256, order:8, indexed:false, value:1601738453382595, valueString:1601738453382595}] ) => ( 22739564938495149381036028, 37056239736992611645947016 )
                                  • InitializableImmutableAdminUpgradeabilityProxy.b18d6afd( )
                                    • 0xadc45df3cf1584624c97338bef33363bf5b97ada.b18d6afd( )
                                    • InitializableImmutableAdminUpgradeabilityProxy.69328dec( )
                                      • 0x8147b99df7672a21809c9093e6f6ce1a60f119bd.69328dec( )
                                        • PoolAddressesProvider.STATICCALL( )
                                        • 0x33654b16a4de97bce05d7dd06803bf1066f3123c.186dea44( )
                                          • InitializableImmutableAdminUpgradeabilityProxy.STATICCALL( )
                                            • 0xb27c52c7f84819e3157993489741cb60786ae330.DELEGATECALL( )
                                            • InitializableImmutableAdminUpgradeabilityProxy.1da24f3e( )
                                              • 0xadc45df3cf1584624c97338bef33363bf5b97ada.1da24f3e( )
                                              • DefaultReserveInterestRateStrategyV2.calculateInterestRates( params=[{name:unbacked, type:uint256, order:1, indexed:false, value:10153484192, valueString:10153484192}, {name:liquidityAdded, type:uint256, order:2, indexed:false, value:0, valueString:0}, {name:liquidityTaken, type:uint256, order:3, indexed:false, value:165057905553, valueString:165057905553}, {name:totalDebt, type:uint256, order:4, indexed:false, value:3432559771843756, valueString:3432559771843756}, {name:reserveFactor, type:uint256, order:5, indexed:false, value:1000, valueString:1000}, {name:reserve, type:address, order:6, indexed:false, value:0xdAC17F958D2ee523a2206206994597C13D831ec7, valueString:0xdAC17F958D2ee523a2206206994597C13D831ec7}, {name:usingVirtualBalance, type:bool, order:7, indexed:false, value:true, valueString:True}, {name:virtualUnderlyingBalance, type:uint256, order:8, indexed:false, value:1601738441825662, valueString:1601738441825662}] ) => ( 22741056119833599924902039, 37057454727762503143409577 )
                                              • InitializableImmutableAdminUpgradeabilityProxy.b18d6afd( )
                                                • 0xadc45df3cf1584624c97338bef33363bf5b97ada.b18d6afd( )
                                                • InitializableImmutableAdminUpgradeabilityProxy.70a08231( )
                                                  • 0xadc45df3cf1584624c97338bef33363bf5b97ada.70a08231( )
                                                    • InitializableImmutableAdminUpgradeabilityProxy.d15e0053( )
                                                      • 0x8147b99df7672a21809c9093e6f6ce1a60f119bd.d15e0053( )
                                                        File 1 of 13: InitializableImmutableAdminUpgradeabilityProxy
                                                        // SPDX-License-Identifier: AGPL-3.0
                                                        pragma solidity 0.8.10;
                                                        /**
                                                         * @dev Collection of functions related to the address type
                                                         */
                                                        library Address {
                                                          /**
                                                           * @dev Returns true if `account` is a contract.
                                                           *
                                                           * [IMPORTANT]
                                                           * ====
                                                           * It is unsafe to assume that an address for which this function returns
                                                           * false is an externally-owned account (EOA) and not a contract.
                                                           *
                                                           * Among others, `isContract` will return false for the following
                                                           * types of addresses:
                                                           *
                                                           *  - an externally-owned account
                                                           *  - a contract in construction
                                                           *  - an address where a contract will be created
                                                           *  - an address where a contract lived, but was destroyed
                                                           * ====
                                                           */
                                                          function isContract(address account) internal view returns (bool) {
                                                            // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
                                                            // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
                                                            // for accounts without code, i.e. `keccak256('')`
                                                            bytes32 codehash;
                                                            bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
                                                            // solhint-disable-next-line no-inline-assembly
                                                            assembly {
                                                              codehash := extcodehash(account)
                                                            }
                                                            return (codehash != accountHash && codehash != 0x0);
                                                          }
                                                          /**
                                                           * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                                                           * `recipient`, forwarding all available gas and reverting on errors.
                                                           *
                                                           * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                                                           * of certain opcodes, possibly making contracts go over the 2300 gas limit
                                                           * imposed by `transfer`, making them unable to receive funds via
                                                           * `transfer`. {sendValue} removes this limitation.
                                                           *
                                                           * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                                                           *
                                                           * IMPORTANT: because control is transferred to `recipient`, care must be
                                                           * taken to not create reentrancy vulnerabilities. Consider using
                                                           * {ReentrancyGuard} or the
                                                           * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                                                           */
                                                          function sendValue(address payable recipient, uint256 amount) internal {
                                                            require(address(this).balance >= amount, 'Address: insufficient balance');
                                                            // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
                                                            (bool success, ) = recipient.call{value: amount}('');
                                                            require(success, 'Address: unable to send value, recipient may have reverted');
                                                          }
                                                        }
                                                        // SPDX-License-Identifier: AGPL-3.0
                                                        pragma solidity 0.8.10;
                                                        import './Proxy.sol';
                                                        import '../contracts/Address.sol';
                                                        /**
                                                         * @title BaseUpgradeabilityProxy
                                                         * @dev This contract implements a proxy that allows to change the
                                                         * implementation address to which it will delegate.
                                                         * Such a change is called an implementation upgrade.
                                                         */
                                                        contract BaseUpgradeabilityProxy is Proxy {
                                                          /**
                                                           * @dev Emitted when the implementation is upgraded.
                                                           * @param implementation Address of the new implementation.
                                                           */
                                                          event Upgraded(address indexed implementation);
                                                          /**
                                                           * @dev Storage slot with the address of the current implementation.
                                                           * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
                                                           * validated in the constructor.
                                                           */
                                                          bytes32 internal constant IMPLEMENTATION_SLOT =
                                                            0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                                                          /**
                                                           * @dev Returns the current implementation.
                                                           * @return impl Address of the current implementation
                                                           */
                                                          function _implementation() internal view override returns (address impl) {
                                                            bytes32 slot = IMPLEMENTATION_SLOT;
                                                            //solium-disable-next-line
                                                            assembly {
                                                              impl := sload(slot)
                                                            }
                                                          }
                                                          /**
                                                           * @dev Upgrades the proxy to a new implementation.
                                                           * @param newImplementation Address of the new implementation.
                                                           */
                                                          function _upgradeTo(address newImplementation) internal {
                                                            _setImplementation(newImplementation);
                                                            emit Upgraded(newImplementation);
                                                          }
                                                          /**
                                                           * @dev Sets the implementation address of the proxy.
                                                           * @param newImplementation Address of the new implementation.
                                                           */
                                                          function _setImplementation(address newImplementation) internal {
                                                            require(
                                                              Address.isContract(newImplementation),
                                                              'Cannot set a proxy implementation to a non-contract address'
                                                            );
                                                            bytes32 slot = IMPLEMENTATION_SLOT;
                                                            //solium-disable-next-line
                                                            assembly {
                                                              sstore(slot, newImplementation)
                                                            }
                                                          }
                                                        }
                                                        // SPDX-License-Identifier: AGPL-3.0
                                                        pragma solidity 0.8.10;
                                                        import './BaseUpgradeabilityProxy.sol';
                                                        /**
                                                         * @title InitializableUpgradeabilityProxy
                                                         * @dev Extends BaseUpgradeabilityProxy with an initializer for initializing
                                                         * implementation and init data.
                                                         */
                                                        contract InitializableUpgradeabilityProxy is BaseUpgradeabilityProxy {
                                                          /**
                                                           * @dev Contract initializer.
                                                           * @param _logic Address of the initial implementation.
                                                           * @param _data Data to send as msg.data to the implementation to initialize the proxied contract.
                                                           * It should include the signature and the parameters of the function to be called, as described in
                                                           * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
                                                           * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.
                                                           */
                                                          function initialize(address _logic, bytes memory _data) public payable {
                                                            require(_implementation() == address(0));
                                                            assert(IMPLEMENTATION_SLOT == bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1));
                                                            _setImplementation(_logic);
                                                            if (_data.length > 0) {
                                                              (bool success, ) = _logic.delegatecall(_data);
                                                              require(success);
                                                            }
                                                          }
                                                        }
                                                        // SPDX-License-Identifier: AGPL-3.0
                                                        pragma solidity 0.8.10;
                                                        /**
                                                         * @title Proxy
                                                         * @dev Implements delegation of calls to other contracts, with proper
                                                         * forwarding of return values and bubbling of failures.
                                                         * It defines a fallback function that delegates all calls to the address
                                                         * returned by the abstract _implementation() internal function.
                                                         */
                                                        abstract contract Proxy {
                                                          /**
                                                           * @dev Fallback function.
                                                           * Will run if no other function in the contract matches the call data.
                                                           * Implemented entirely in `_fallback`.
                                                           */
                                                          fallback() external payable {
                                                            _fallback();
                                                          }
                                                          /**
                                                           * @return The Address of the implementation.
                                                           */
                                                          function _implementation() internal view virtual returns (address);
                                                          /**
                                                           * @dev Delegates execution to an implementation contract.
                                                           * This is a low level function that doesn't return to its internal call site.
                                                           * It will return to the external caller whatever the implementation returns.
                                                           * @param implementation Address to delegate.
                                                           */
                                                          function _delegate(address implementation) internal {
                                                            //solium-disable-next-line
                                                            assembly {
                                                              // Copy msg.data. We take full control of memory in this inline assembly
                                                              // block because it will not return to Solidity code. We overwrite the
                                                              // Solidity scratch pad at memory position 0.
                                                              calldatacopy(0, 0, calldatasize())
                                                              // Call the implementation.
                                                              // out and outsize are 0 because we don't know the size yet.
                                                              let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                                                              // Copy the returned data.
                                                              returndatacopy(0, 0, returndatasize())
                                                              switch result
                                                              // delegatecall returns 0 on error.
                                                              case 0 {
                                                                revert(0, returndatasize())
                                                              }
                                                              default {
                                                                return(0, returndatasize())
                                                              }
                                                            }
                                                          }
                                                          /**
                                                           * @dev Function that is run as the first thing in the fallback function.
                                                           * Can be redefined in derived contracts to add functionality.
                                                           * Redefinitions must call super._willFallback().
                                                           */
                                                          function _willFallback() internal virtual {}
                                                          /**
                                                           * @dev fallback implementation.
                                                           * Extracted to enable manual triggering.
                                                           */
                                                          function _fallback() internal {
                                                            _willFallback();
                                                            _delegate(_implementation());
                                                          }
                                                        }
                                                        // SPDX-License-Identifier: AGPL-3.0
                                                        pragma solidity 0.8.10;
                                                        import {BaseUpgradeabilityProxy} from '../../../dependencies/openzeppelin/upgradeability/BaseUpgradeabilityProxy.sol';
                                                        /**
                                                         * @title BaseImmutableAdminUpgradeabilityProxy
                                                         * @author Aave, inspired by the OpenZeppelin upgradeability proxy pattern
                                                         * @notice This contract combines an upgradeability proxy with an authorization
                                                         * mechanism for administrative tasks.
                                                         * @dev The admin role is stored in an immutable, which helps saving transactions costs
                                                         * All external functions in this contract must be guarded by the
                                                         * `ifAdmin` modifier. See ethereum/solidity#3864 for a Solidity
                                                         * feature proposal that would enable this to be done automatically.
                                                         */
                                                        contract BaseImmutableAdminUpgradeabilityProxy is BaseUpgradeabilityProxy {
                                                          address internal immutable _admin;
                                                          /**
                                                           * @dev Constructor.
                                                           * @param admin The address of the admin
                                                           */
                                                          constructor(address admin) {
                                                            _admin = admin;
                                                          }
                                                          modifier ifAdmin() {
                                                            if (msg.sender == _admin) {
                                                              _;
                                                            } else {
                                                              _fallback();
                                                            }
                                                          }
                                                          /**
                                                           * @notice Return the admin address
                                                           * @return The address of the proxy admin.
                                                           */
                                                          function admin() external ifAdmin returns (address) {
                                                            return _admin;
                                                          }
                                                          /**
                                                           * @notice Return the implementation address
                                                           * @return The address of the implementation.
                                                           */
                                                          function implementation() external ifAdmin returns (address) {
                                                            return _implementation();
                                                          }
                                                          /**
                                                           * @notice Upgrade the backing implementation of the proxy.
                                                           * @dev Only the admin can call this function.
                                                           * @param newImplementation The address of the new implementation.
                                                           */
                                                          function upgradeTo(address newImplementation) external ifAdmin {
                                                            _upgradeTo(newImplementation);
                                                          }
                                                          /**
                                                           * @notice Upgrade the backing implementation of the proxy and call a function
                                                           * on the new implementation.
                                                           * @dev This is useful to initialize the proxied contract.
                                                           * @param newImplementation The address of the new implementation.
                                                           * @param data Data to send as msg.data in the low level call.
                                                           * It should include the signature and the parameters of the function to be called, as described in
                                                           * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
                                                           */
                                                          function upgradeToAndCall(address newImplementation, bytes calldata data)
                                                            external
                                                            payable
                                                            ifAdmin
                                                          {
                                                            _upgradeTo(newImplementation);
                                                            (bool success, ) = newImplementation.delegatecall(data);
                                                            require(success);
                                                          }
                                                          /**
                                                           * @notice Only fall back when the sender is not the admin.
                                                           */
                                                          function _willFallback() internal virtual override {
                                                            require(msg.sender != _admin, 'Cannot call fallback function from the proxy admin');
                                                            super._willFallback();
                                                          }
                                                        }
                                                        // SPDX-License-Identifier: AGPL-3.0
                                                        pragma solidity 0.8.10;
                                                        import {InitializableUpgradeabilityProxy} from '../../../dependencies/openzeppelin/upgradeability/InitializableUpgradeabilityProxy.sol';
                                                        import {Proxy} from '../../../dependencies/openzeppelin/upgradeability/Proxy.sol';
                                                        import {BaseImmutableAdminUpgradeabilityProxy} from './BaseImmutableAdminUpgradeabilityProxy.sol';
                                                        /**
                                                         * @title InitializableAdminUpgradeabilityProxy
                                                         * @author Aave
                                                         * @dev Extends BaseAdminUpgradeabilityProxy with an initializer function
                                                         */
                                                        contract InitializableImmutableAdminUpgradeabilityProxy is
                                                          BaseImmutableAdminUpgradeabilityProxy,
                                                          InitializableUpgradeabilityProxy
                                                        {
                                                          /**
                                                           * @dev Constructor.
                                                           * @param admin The address of the admin
                                                           */
                                                          constructor(address admin) BaseImmutableAdminUpgradeabilityProxy(admin) {
                                                            // Intentionally left blank
                                                          }
                                                          /// @inheritdoc BaseImmutableAdminUpgradeabilityProxy
                                                          function _willFallback() internal override(BaseImmutableAdminUpgradeabilityProxy, Proxy) {
                                                            BaseImmutableAdminUpgradeabilityProxy._willFallback();
                                                          }
                                                        }
                                                        

                                                        File 2 of 13: 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 13: MapleTreasury
                                                        // SPDX-License-Identifier:  AGPL-3.0-or-later // hevm: flattened sources of contracts/MapleTreasury.sol
                                                        pragma solidity =0.6.11 >=0.6.0 <0.8.0 >=0.6.2 <0.8.0;
                                                        
                                                        ////// lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol
                                                        /* pragma solidity >=0.6.0 <0.8.0; */
                                                        
                                                        /**
                                                         * @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);
                                                        }
                                                        
                                                        ////// contracts/interfaces/IERC20Details.sol
                                                        /* pragma solidity 0.6.11; */
                                                        
                                                        /* import "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; */
                                                        
                                                        interface IERC20Details is IERC20 {
                                                        
                                                            function name() external view returns (string memory);
                                                        
                                                            function symbol() external view returns (string memory);
                                                        
                                                            function decimals() external view returns (uint256);
                                                        
                                                        }
                                                        
                                                        ////// contracts/interfaces/IMapleGlobals.sol
                                                        /* pragma solidity 0.6.11; */
                                                        
                                                        interface IMapleGlobals {
                                                        
                                                            function pendingGovernor() external view returns (address);
                                                        
                                                            function governor() external view returns (address);
                                                        
                                                            function globalAdmin() external view returns (address);
                                                        
                                                            function mpl() external view returns (address);
                                                        
                                                            function mapleTreasury() external view returns (address);
                                                        
                                                            function isValidBalancerPool(address) external view returns (bool);
                                                        
                                                            function treasuryFee() external view returns (uint256);
                                                        
                                                            function investorFee() external view returns (uint256);
                                                        
                                                            function defaultGracePeriod() external view returns (uint256);
                                                        
                                                            function fundingPeriod() external view returns (uint256);
                                                        
                                                            function swapOutRequired() external view returns (uint256);
                                                        
                                                            function isValidLiquidityAsset(address) external view returns (bool);
                                                        
                                                            function isValidCollateralAsset(address) external view returns (bool);
                                                        
                                                            function isValidPoolDelegate(address) external view returns (bool);
                                                        
                                                            function validCalcs(address) external view returns (bool);
                                                        
                                                            function isValidCalc(address, uint8) external view returns (bool);
                                                        
                                                            function getLpCooldownParams() external view returns (uint256, uint256);
                                                        
                                                            function isValidLoanFactory(address) external view returns (bool);
                                                        
                                                            function isValidSubFactory(address, address, uint8) external view returns (bool);
                                                        
                                                            function isValidPoolFactory(address) external view returns (bool);
                                                            
                                                            function getLatestPrice(address) external view returns (uint256);
                                                            
                                                            function defaultUniswapPath(address, address) external view returns (address);
                                                        
                                                            function minLoanEquity() external view returns (uint256);
                                                            
                                                            function maxSwapSlippage() external view returns (uint256);
                                                        
                                                            function protocolPaused() external view returns (bool);
                                                        
                                                            function stakerCooldownPeriod() external view returns (uint256);
                                                        
                                                            function lpCooldownPeriod() external view returns (uint256);
                                                        
                                                            function stakerUnstakeWindow() external view returns (uint256);
                                                        
                                                            function lpWithdrawWindow() external view returns (uint256);
                                                        
                                                            function oracleFor(address) external view returns (address);
                                                        
                                                            function validSubFactories(address, address) external view returns (bool);
                                                        
                                                            function setStakerCooldownPeriod(uint256) external;
                                                        
                                                            function setLpCooldownPeriod(uint256) external;
                                                        
                                                            function setStakerUnstakeWindow(uint256) external;
                                                        
                                                            function setLpWithdrawWindow(uint256) external;
                                                        
                                                            function setMaxSwapSlippage(uint256) external;
                                                        
                                                            function setGlobalAdmin(address) external;
                                                        
                                                            function setValidBalancerPool(address, bool) external;
                                                        
                                                            function setProtocolPause(bool) external;
                                                        
                                                            function setValidPoolFactory(address, bool) external;
                                                        
                                                            function setValidLoanFactory(address, bool) external;
                                                        
                                                            function setValidSubFactory(address, address, bool) external;
                                                        
                                                            function setDefaultUniswapPath(address, address, address) external;
                                                        
                                                            function setPoolDelegateAllowlist(address, bool) external;
                                                        
                                                            function setCollateralAsset(address, bool) external;
                                                        
                                                            function setLiquidityAsset(address, bool) external;
                                                        
                                                            function setCalc(address, bool) external;
                                                        
                                                            function setInvestorFee(uint256) external;
                                                        
                                                            function setTreasuryFee(uint256) external;
                                                        
                                                            function setMapleTreasury(address) external;
                                                        
                                                            function setDefaultGracePeriod(uint256) external;
                                                        
                                                            function setMinLoanEquity(uint256) external;
                                                        
                                                            function setFundingPeriod(uint256) external;
                                                        
                                                            function setSwapOutRequired(uint256) external;
                                                        
                                                            function setPriceOracle(address, address) external;
                                                        
                                                            function setPendingGovernor(address) external;
                                                        
                                                            function acceptGovernor() external;
                                                        
                                                        }
                                                        
                                                        ////// contracts/interfaces/IMapleToken.sol
                                                        /* pragma solidity 0.6.11; */
                                                        
                                                        interface IMapleToken {
                                                        
                                                            function updateFundsReceived() external;
                                                        
                                                        }
                                                        
                                                        ////// contracts/interfaces/IUniswapRouter.sol
                                                        /* pragma solidity 0.6.11; */
                                                        
                                                        interface IUniswapRouter {
                                                        
                                                            function swapExactTokensForTokens(
                                                                uint256 amountIn,
                                                                uint256 amountOutMin,
                                                                address[] calldata path,
                                                                address to,
                                                                uint256 deadline
                                                            ) external returns (uint256[] memory amounts);
                                                        
                                                            function swapETHForExactTokens(
                                                                uint256 amountOut,
                                                                address[] calldata path,
                                                                address to,
                                                                uint256 deadline
                                                            ) external payable returns (uint256[] memory amounts);
                                                        
                                                            function quote(
                                                                uint256 amountA,
                                                                uint256 reserveA,
                                                                uint256 reserveB
                                                            ) external pure returns (uint256 amountB);
                                                        
                                                            function WETH() external pure returns (address);
                                                        
                                                        }
                                                        
                                                        ////// lib/openzeppelin-contracts/contracts/math/SafeMath.sol
                                                        /* pragma solidity >=0.6.0 <0.8.0; */
                                                        
                                                        /**
                                                         * @dev Wrappers over Solidity's arithmetic operations with added overflow
                                                         * checks.
                                                         *
                                                         * Arithmetic operations in Solidity wrap on overflow. This can easily result
                                                         * in bugs, because programmers usually assume that an overflow raises an
                                                         * error, which is the standard behavior in high level programming languages.
                                                         * `SafeMath` restores this intuition by reverting the transaction when 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.
                                                         */
                                                        library SafeMath {
                                                            /**
                                                             * @dev Returns the addition of two unsigned integers, reverting on
                                                             * overflow.
                                                             *
                                                             * Counterpart to Solidity's `+` operator.
                                                             *
                                                             * Requirements:
                                                             *
                                                             * - Addition cannot overflow.
                                                             */
                                                            function add(uint256 a, uint256 b) internal pure returns (uint256) {
                                                                uint256 c = a + b;
                                                                require(c >= a, "SafeMath: addition overflow");
                                                        
                                                                return c;
                                                            }
                                                        
                                                            /**
                                                             * @dev Returns the subtraction of two unsigned integers, reverting on
                                                             * overflow (when the result is negative).
                                                             *
                                                             * Counterpart to Solidity's `-` operator.
                                                             *
                                                             * Requirements:
                                                             *
                                                             * - Subtraction cannot overflow.
                                                             */
                                                            function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                                                                return sub(a, b, "SafeMath: subtraction overflow");
                                                            }
                                                        
                                                            /**
                                                             * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
                                                             * overflow (when the result is negative).
                                                             *
                                                             * Counterpart to Solidity's `-` operator.
                                                             *
                                                             * Requirements:
                                                             *
                                                             * - Subtraction cannot overflow.
                                                             */
                                                            function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                                                                require(b <= a, errorMessage);
                                                                uint256 c = a - b;
                                                        
                                                                return c;
                                                            }
                                                        
                                                            /**
                                                             * @dev Returns the multiplication of two unsigned integers, reverting on
                                                             * overflow.
                                                             *
                                                             * Counterpart to Solidity's `*` operator.
                                                             *
                                                             * Requirements:
                                                             *
                                                             * - Multiplication cannot overflow.
                                                             */
                                                            function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                                                                // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                                                                // benefit is lost if 'b' is also tested.
                                                                // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
                                                                if (a == 0) {
                                                                    return 0;
                                                                }
                                                        
                                                                uint256 c = a * b;
                                                                require(c / a == b, "SafeMath: multiplication overflow");
                                                        
                                                                return c;
                                                            }
                                                        
                                                            /**
                                                             * @dev Returns the integer division of two unsigned integers. Reverts on
                                                             * division by zero. The result is rounded towards zero.
                                                             *
                                                             * Counterpart to Solidity's `/` operator. Note: this function uses a
                                                             * `revert` opcode (which leaves remaining gas untouched) while Solidity
                                                             * uses an invalid opcode to revert (consuming all remaining gas).
                                                             *
                                                             * Requirements:
                                                             *
                                                             * - The divisor cannot be zero.
                                                             */
                                                            function div(uint256 a, uint256 b) internal pure returns (uint256) {
                                                                return div(a, b, "SafeMath: division by zero");
                                                            }
                                                        
                                                            /**
                                                             * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
                                                             * division by zero. The result is rounded towards zero.
                                                             *
                                                             * Counterpart to Solidity's `/` operator. Note: this function uses a
                                                             * `revert` opcode (which leaves remaining gas untouched) while Solidity
                                                             * uses an invalid opcode to revert (consuming all remaining gas).
                                                             *
                                                             * Requirements:
                                                             *
                                                             * - The divisor cannot be zero.
                                                             */
                                                            function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                                                                require(b > 0, errorMessage);
                                                                uint256 c = a / b;
                                                                // assert(a == b * c + a % b); // There is no case in which this doesn't hold
                                                        
                                                                return c;
                                                            }
                                                        
                                                            /**
                                                             * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                                                             * Reverts when dividing by zero.
                                                             *
                                                             * Counterpart to Solidity's `%` operator. This function uses a `revert`
                                                             * opcode (which leaves remaining gas untouched) while Solidity uses an
                                                             * invalid opcode to revert (consuming all remaining gas).
                                                             *
                                                             * Requirements:
                                                             *
                                                             * - The divisor cannot be zero.
                                                             */
                                                            function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                                                                return mod(a, b, "SafeMath: modulo by zero");
                                                            }
                                                        
                                                            /**
                                                             * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                                                             * Reverts with custom message when dividing by zero.
                                                             *
                                                             * Counterpart to Solidity's `%` operator. This function uses a `revert`
                                                             * opcode (which leaves remaining gas untouched) while Solidity uses an
                                                             * invalid opcode to revert (consuming all remaining gas).
                                                             *
                                                             * Requirements:
                                                             *
                                                             * - The divisor cannot be zero.
                                                             */
                                                            function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                                                                require(b != 0, errorMessage);
                                                                return a % b;
                                                            }
                                                        }
                                                        
                                                        ////// contracts/library/Util.sol
                                                        /* pragma solidity 0.6.11; */
                                                        
                                                        /* import "../interfaces/IERC20Details.sol"; */
                                                        /* import "../interfaces/IMapleGlobals.sol"; */
                                                        /* import "lib/openzeppelin-contracts/contracts/math/SafeMath.sol"; */
                                                        
                                                        /// @title Util is a library that contains utility functions.
                                                        library Util {
                                                        
                                                            using SafeMath for uint256;
                                                        
                                                            /**
                                                                @dev    Calculates the minimum amount from a swap (adjustable for price slippage).
                                                                @param  globals   Instance of a MapleGlobals.
                                                                @param  fromAsset Address of ERC-20 that will be swapped.
                                                                @param  toAsset   Address of ERC-20 that will returned from swap.
                                                                @param  swapAmt   Amount of `fromAsset` to be swapped.
                                                                @return Expected amount of `toAsset` to receive from swap based on current oracle prices.
                                                            */
                                                            function calcMinAmount(IMapleGlobals globals, address fromAsset, address toAsset, uint256 swapAmt) external view returns (uint256) {
                                                                return 
                                                                    swapAmt
                                                                        .mul(globals.getLatestPrice(fromAsset))           // Convert from `fromAsset` value.
                                                                        .mul(10 ** IERC20Details(toAsset).decimals())     // Convert to `toAsset` decimal precision.
                                                                        .div(globals.getLatestPrice(toAsset))             // Convert to `toAsset` value.
                                                                        .div(10 ** IERC20Details(fromAsset).decimals());  // Convert from `fromAsset` decimal precision.
                                                            }
                                                        }
                                                        
                                                        ////// lib/openzeppelin-contracts/contracts/utils/Address.sol
                                                        /* pragma solidity >=0.6.2 <0.8.0; */
                                                        
                                                        /**
                                                         * @dev Collection of functions related to the address type
                                                         */
                                                        library Address {
                                                            /**
                                                             * @dev Returns true if `account` is a contract.
                                                             *
                                                             * [IMPORTANT]
                                                             * ====
                                                             * It is unsafe to assume that an address for which this function returns
                                                             * false is an externally-owned account (EOA) and not a contract.
                                                             *
                                                             * Among others, `isContract` will return false for the following
                                                             * types of addresses:
                                                             *
                                                             *  - an externally-owned account
                                                             *  - a contract in construction
                                                             *  - an address where a contract will be created
                                                             *  - an address where a contract lived, but was destroyed
                                                             * ====
                                                             */
                                                            function isContract(address account) internal view returns (bool) {
                                                                // This method relies on extcodesize, which returns 0 for contracts in
                                                                // construction, since the code is only stored at the end of the
                                                                // constructor execution.
                                                        
                                                                uint256 size;
                                                                // solhint-disable-next-line no-inline-assembly
                                                                assembly { size := extcodesize(account) }
                                                                return size > 0;
                                                            }
                                                        
                                                            /**
                                                             * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                                                             * `recipient`, forwarding all available gas and reverting on errors.
                                                             *
                                                             * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                                                             * of certain opcodes, possibly making contracts go over the 2300 gas limit
                                                             * imposed by `transfer`, making them unable to receive funds via
                                                             * `transfer`. {sendValue} removes this limitation.
                                                             *
                                                             * https://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");
                                                            }
                                                        
                                                            /**
                                                             * @dev Performs a Solidity function call using a low level `call`. A
                                                             * plain`call` is an unsafe replacement for a function call: use this
                                                             * function instead.
                                                             *
                                                             * If `target` reverts with a revert reason, it is bubbled up by this
                                                             * function (like regular Solidity function calls).
                                                             *
                                                             * Returns the raw returned data. To convert to the expected return value,
                                                             * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                                                             *
                                                             * Requirements:
                                                             *
                                                             * - `target` must be a contract.
                                                             * - calling `target` with `data` must not revert.
                                                             *
                                                             * _Available since v3.1._
                                                             */
                                                            function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                                                              return functionCall(target, data, "Address: low-level call failed");
                                                            }
                                                        
                                                            /**
                                                             * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                                                             * `errorMessage` as a fallback revert reason when `target` reverts.
                                                             *
                                                             * _Available since v3.1._
                                                             */
                                                            function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                                                                return functionCallWithValue(target, data, 0, errorMessage);
                                                            }
                                                        
                                                            /**
                                                             * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                                                             * but also transferring `value` wei to `target`.
                                                             *
                                                             * Requirements:
                                                             *
                                                             * - the calling contract must have an ETH balance of at least `value`.
                                                             * - the called Solidity function must be `payable`.
                                                             *
                                                             * _Available since v3.1._
                                                             */
                                                            function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                                                                return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                                                            }
                                                        
                                                            /**
                                                             * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                                                             * with `errorMessage` as a fallback revert reason when `target` reverts.
                                                             *
                                                             * _Available since v3.1._
                                                             */
                                                            function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
                                                                require(address(this).balance >= value, "Address: insufficient balance for call");
                                                                require(isContract(target), "Address: call to non-contract");
                                                        
                                                                // solhint-disable-next-line avoid-low-level-calls
                                                                (bool success, bytes memory returndata) = target.call{ value: value }(data);
                                                                return _verifyCallResult(success, returndata, errorMessage);
                                                            }
                                                        
                                                            /**
                                                             * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                                                             * but performing a static call.
                                                             *
                                                             * _Available since v3.3._
                                                             */
                                                            function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                                                                return functionStaticCall(target, data, "Address: low-level static call failed");
                                                            }
                                                        
                                                            /**
                                                             * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                                                             * but performing a static call.
                                                             *
                                                             * _Available since v3.3._
                                                             */
                                                            function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
                                                                require(isContract(target), "Address: static call to non-contract");
                                                        
                                                                // solhint-disable-next-line avoid-low-level-calls
                                                                (bool success, bytes memory returndata) = target.staticcall(data);
                                                                return _verifyCallResult(success, returndata, errorMessage);
                                                            }
                                                        
                                                            function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
                                                                if (success) {
                                                                    return returndata;
                                                                } else {
                                                                    // Look for revert reason and bubble it up if present
                                                                    if (returndata.length > 0) {
                                                                        // The easiest way to bubble the revert reason is using memory via assembly
                                                        
                                                                        // solhint-disable-next-line no-inline-assembly
                                                                        assembly {
                                                                            let returndata_size := mload(returndata)
                                                                            revert(add(32, returndata), returndata_size)
                                                                        }
                                                                    } else {
                                                                        revert(errorMessage);
                                                                    }
                                                                }
                                                            }
                                                        }
                                                        
                                                        ////// lib/openzeppelin-contracts/contracts/token/ERC20/SafeERC20.sol
                                                        /* pragma solidity >=0.6.0 <0.8.0; */
                                                        
                                                        /* import "./IERC20.sol"; */
                                                        /* import "../../math/SafeMath.sol"; */
                                                        /* import "../../utils/Address.sol"; */
                                                        
                                                        /**
                                                         * @title SafeERC20
                                                         * @dev Wrappers around ERC20 operations that throw on failure (when the token
                                                         * contract returns false). Tokens that return no value (and instead revert or
                                                         * throw on failure) are also supported, non-reverting calls are assumed to be
                                                         * successful.
                                                         * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
                                                         * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
                                                         */
                                                        library SafeERC20 {
                                                            using SafeMath for uint256;
                                                            using Address for address;
                                                        
                                                            function safeTransfer(IERC20 token, address to, uint256 value) internal {
                                                                _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
                                                            }
                                                        
                                                            function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
                                                                _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
                                                            }
                                                        
                                                            /**
                                                             * @dev Deprecated. This function has issues similar to the ones found in
                                                             * {IERC20-approve}, and its usage is discouraged.
                                                             *
                                                             * Whenever possible, use {safeIncreaseAllowance} and
                                                             * {safeDecreaseAllowance} instead.
                                                             */
                                                            function safeApprove(IERC20 token, address spender, uint256 value) internal {
                                                                // safeApprove should only be called when setting an initial allowance,
                                                                // or when resetting it to zero. To increase and decrease it, use
                                                                // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
                                                                // solhint-disable-next-line max-line-length
                                                                require((value == 0) || (token.allowance(address(this), spender) == 0),
                                                                    "SafeERC20: approve from non-zero to non-zero allowance"
                                                                );
                                                                _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
                                                            }
                                                        
                                                            function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
                                                                uint256 newAllowance = token.allowance(address(this), spender).add(value);
                                                                _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
                                                            }
                                                        
                                                            function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
                                                                uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
                                                                _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
                                                            }
                                                        
                                                            /**
                                                             * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
                                                             * on the return value: the return value is optional (but if data is returned, it must not be false).
                                                             * @param token The token targeted by the call.
                                                             * @param data The call data (encoded using abi.encode or one of its variants).
                                                             */
                                                            function _callOptionalReturn(IERC20 token, bytes memory data) private {
                                                                // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
                                                                // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
                                                                // the target address contains contract code and also asserts for success in the low-level call.
                                                        
                                                                bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
                                                                if (returndata.length > 0) { // Return data is optional
                                                                    // solhint-disable-next-line max-line-length
                                                                    require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
                                                                }
                                                            }
                                                        }
                                                        
                                                        ////// contracts/MapleTreasury.sol
                                                        /* pragma solidity 0.6.11; */
                                                        
                                                        /* import "lib/openzeppelin-contracts/contracts/math/SafeMath.sol"; */
                                                        /* import "lib/openzeppelin-contracts/contracts/token/ERC20/SafeERC20.sol"; */
                                                        
                                                        /* import "./interfaces/IMapleGlobals.sol"; */
                                                        /* import "./interfaces/IMapleToken.sol"; */
                                                        /* import "./interfaces/IERC20Details.sol"; */
                                                        /* import "./interfaces/IUniswapRouter.sol"; */
                                                        
                                                        /* import "./library/Util.sol"; */
                                                        
                                                        /// @title MapleTreasury earns revenue from Loans and distributes it to token holders and the Maple development team.
                                                        contract MapleTreasury {
                                                        
                                                            using SafeMath  for uint256;
                                                            using SafeERC20 for IERC20;
                                                        
                                                            address public immutable mpl;            // The address of ERC-2222 Maple Token for the Maple protocol.
                                                            address public immutable fundsToken;     // The address of the `fundsToken` of the ERC-2222 Maple Token.
                                                            address public immutable uniswapRouter;  // The address of the official UniswapV2 router.
                                                            address public           globals;        // The address of an instance of MapleGlobals.
                                                        
                                                            /**
                                                                @dev   Instantiates the MapleTreasury contract.
                                                                @param _mpl           The address of ERC-2222 Maple Token for the Maple protocol.
                                                                @param _fundsToken    The address of the `fundsToken` of the ERC-2222 Maple Token.
                                                                @param _uniswapRouter The address of the official UniswapV2 router.
                                                                @param _globals       The address of an instance of MapleGlobals.
                                                            */
                                                            constructor(
                                                                address _mpl,
                                                                address _fundsToken,
                                                                address _uniswapRouter,
                                                                address _globals
                                                            ) public {
                                                                mpl           = _mpl;
                                                                fundsToken    = _fundsToken;
                                                                uniswapRouter = _uniswapRouter;
                                                                globals       = _globals;
                                                            }
                                                        
                                                            event      ERC20Conversion(address indexed asset, uint256 amountIn, uint256 amountOut);
                                                            event DistributedToHolders(uint256 amount);
                                                            event       ERC20Reclaimed(address indexed asset, uint256 amount);
                                                            event           GlobalsSet(address newGlobals);
                                                        
                                                            /**
                                                                @dev Checks that `msg.sender` is the Governor.
                                                            */
                                                            modifier isGovernor() {
                                                                require(msg.sender == IMapleGlobals(globals).governor(), "MT:NOT_GOV");
                                                                _;
                                                            }
                                                        
                                                            /**
                                                                @dev   Updates the MapleGlobals instance. Only the Governor can call this function.
                                                                @dev   It emits a `GlobalsSet` event.
                                                                @param newGlobals Address of a new MapleGlobals instance.
                                                            */
                                                            function setGlobals(address newGlobals) isGovernor external {
                                                                globals = newGlobals;
                                                                emit GlobalsSet(newGlobals);
                                                            }
                                                        
                                                            /**
                                                                @dev   Reclaims Treasury funds to the MapleDAO address. Only the Governor can call this function.
                                                                @dev   It emits a `ERC20Reclaimed` event.
                                                                @param asset  Address of the token to be reclaimed.
                                                                @param amount Amount to withdraw.
                                                            */
                                                            function reclaimERC20(address asset, uint256 amount) isGovernor external {
                                                                IERC20(asset).safeTransfer(msg.sender, amount);
                                                                emit ERC20Reclaimed(asset, amount);
                                                            }
                                                        
                                                            /**
                                                                @dev Passes through the current `fundsToken` balance of the Treasury to Maple Token, where it can be claimed by MPL holders.
                                                                     Only the Governor can call this function.
                                                                @dev It emits a `DistributedToHolders` event.
                                                            */
                                                            function distributeToHolders() isGovernor external {
                                                                IERC20 _fundsToken = IERC20(fundsToken);
                                                                uint256 distributeAmount = _fundsToken.balanceOf(address(this));
                                                                _fundsToken.safeTransfer(mpl, distributeAmount);
                                                                IMapleToken(mpl).updateFundsReceived();
                                                                emit DistributedToHolders(distributeAmount);
                                                            }
                                                        
                                                            /**
                                                                @dev   Converts an ERC-20 asset, via Uniswap, to `fundsToken`. Only the Governor can call this function.
                                                                @dev   It emits a `ERC20Conversion` event.
                                                                @param asset The ERC-20 asset to convert to `fundsToken`.
                                                            */
                                                            function convertERC20(address asset) isGovernor external {
                                                                require(asset != fundsToken, "MT:ASSET_IS_FUNDS_TOKEN");
                                                        
                                                                IMapleGlobals _globals = IMapleGlobals(globals);
                                                        
                                                                uint256 assetBalance = IERC20(asset).balanceOf(address(this));
                                                                uint256 minAmount    = Util.calcMinAmount(_globals, asset, fundsToken, assetBalance);
                                                        
                                                                IERC20(asset).safeApprove(uniswapRouter, uint256(0));
                                                                IERC20(asset).safeApprove(uniswapRouter, assetBalance);
                                                        
                                                                address uniswapAssetForPath = _globals.defaultUniswapPath(asset, fundsToken);
                                                                bool middleAsset            = uniswapAssetForPath != fundsToken && uniswapAssetForPath != address(0);
                                                        
                                                                address[] memory path = new address[](middleAsset ? 3 : 2);
                                                        
                                                                path[0] = asset;
                                                                path[1] = middleAsset ? uniswapAssetForPath : fundsToken;
                                                        
                                                                if (middleAsset) path[2] = fundsToken;
                                                        
                                                                uint256[] memory returnAmounts = IUniswapRouter(uniswapRouter).swapExactTokensForTokens(
                                                                    assetBalance,
                                                                    minAmount.sub(minAmount.mul(_globals.maxSwapSlippage()).div(10_000)),
                                                                    path,
                                                                    address(this),
                                                                    block.timestamp
                                                                );
                                                        
                                                                emit ERC20Conversion(asset, returnAmounts[0], returnAmounts[path.length - 1]);
                                                            }
                                                        
                                                        }

                                                        File 4 of 13: TetherToken
                                                        pragma solidity ^0.4.17;
                                                        
                                                        /**
                                                         * @title SafeMath
                                                         * @dev Math operations with safety checks that throw on error
                                                         */
                                                        library SafeMath {
                                                            function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                                                                if (a == 0) {
                                                                    return 0;
                                                                }
                                                                uint256 c = a * b;
                                                                assert(c / a == b);
                                                                return c;
                                                            }
                                                        
                                                            function div(uint256 a, uint256 b) internal pure returns (uint256) {
                                                                // assert(b > 0); // Solidity automatically throws when dividing by 0
                                                                uint256 c = a / b;
                                                                // assert(a == b * c + a % b); // There is no case in which this doesn't hold
                                                                return c;
                                                            }
                                                        
                                                            function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                                                                assert(b <= a);
                                                                return a - b;
                                                            }
                                                        
                                                            function add(uint256 a, uint256 b) internal pure returns (uint256) {
                                                                uint256 c = a + b;
                                                                assert(c >= a);
                                                                return c;
                                                            }
                                                        }
                                                        
                                                        /**
                                                         * @title Ownable
                                                         * @dev The Ownable contract has an owner address, and provides basic authorization control
                                                         * functions, this simplifies the implementation of "user permissions".
                                                         */
                                                        contract Ownable {
                                                            address public owner;
                                                        
                                                            /**
                                                              * @dev The Ownable constructor sets the original `owner` of the contract to the sender
                                                              * account.
                                                              */
                                                            function Ownable() public {
                                                                owner = msg.sender;
                                                            }
                                                        
                                                            /**
                                                              * @dev Throws if called by any account other than the owner.
                                                              */
                                                            modifier onlyOwner() {
                                                                require(msg.sender == owner);
                                                                _;
                                                            }
                                                        
                                                            /**
                                                            * @dev Allows the current owner to transfer control of the contract to a newOwner.
                                                            * @param newOwner The address to transfer ownership to.
                                                            */
                                                            function transferOwnership(address newOwner) public onlyOwner {
                                                                if (newOwner != address(0)) {
                                                                    owner = newOwner;
                                                                }
                                                            }
                                                        
                                                        }
                                                        
                                                        /**
                                                         * @title ERC20Basic
                                                         * @dev Simpler version of ERC20 interface
                                                         * @dev see https://github.com/ethereum/EIPs/issues/20
                                                         */
                                                        contract ERC20Basic {
                                                            uint public _totalSupply;
                                                            function totalSupply() public constant returns (uint);
                                                            function balanceOf(address who) public constant returns (uint);
                                                            function transfer(address to, uint value) public;
                                                            event Transfer(address indexed from, address indexed to, uint value);
                                                        }
                                                        
                                                        /**
                                                         * @title ERC20 interface
                                                         * @dev see https://github.com/ethereum/EIPs/issues/20
                                                         */
                                                        contract ERC20 is ERC20Basic {
                                                            function allowance(address owner, address spender) public constant returns (uint);
                                                            function transferFrom(address from, address to, uint value) public;
                                                            function approve(address spender, uint value) public;
                                                            event Approval(address indexed owner, address indexed spender, uint value);
                                                        }
                                                        
                                                        /**
                                                         * @title Basic token
                                                         * @dev Basic version of StandardToken, with no allowances.
                                                         */
                                                        contract BasicToken is Ownable, ERC20Basic {
                                                            using SafeMath for uint;
                                                        
                                                            mapping(address => uint) public balances;
                                                        
                                                            // additional variables for use if transaction fees ever became necessary
                                                            uint public basisPointsRate = 0;
                                                            uint public maximumFee = 0;
                                                        
                                                            /**
                                                            * @dev Fix for the ERC20 short address attack.
                                                            */
                                                            modifier onlyPayloadSize(uint size) {
                                                                require(!(msg.data.length < size + 4));
                                                                _;
                                                            }
                                                        
                                                            /**
                                                            * @dev transfer token for a specified address
                                                            * @param _to The address to transfer to.
                                                            * @param _value The amount to be transferred.
                                                            */
                                                            function transfer(address _to, uint _value) public onlyPayloadSize(2 * 32) {
                                                                uint fee = (_value.mul(basisPointsRate)).div(10000);
                                                                if (fee > maximumFee) {
                                                                    fee = maximumFee;
                                                                }
                                                                uint sendAmount = _value.sub(fee);
                                                                balances[msg.sender] = balances[msg.sender].sub(_value);
                                                                balances[_to] = balances[_to].add(sendAmount);
                                                                if (fee > 0) {
                                                                    balances[owner] = balances[owner].add(fee);
                                                                    Transfer(msg.sender, owner, fee);
                                                                }
                                                                Transfer(msg.sender, _to, sendAmount);
                                                            }
                                                        
                                                            /**
                                                            * @dev Gets the balance of the specified address.
                                                            * @param _owner The address to query the the balance of.
                                                            * @return An uint representing the amount owned by the passed address.
                                                            */
                                                            function balanceOf(address _owner) public constant returns (uint balance) {
                                                                return balances[_owner];
                                                            }
                                                        
                                                        }
                                                        
                                                        /**
                                                         * @title Standard ERC20 token
                                                         *
                                                         * @dev Implementation of the basic standard token.
                                                         * @dev https://github.com/ethereum/EIPs/issues/20
                                                         * @dev Based oncode by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
                                                         */
                                                        contract StandardToken is BasicToken, ERC20 {
                                                        
                                                            mapping (address => mapping (address => uint)) public allowed;
                                                        
                                                            uint public constant MAX_UINT = 2**256 - 1;
                                                        
                                                            /**
                                                            * @dev Transfer tokens from one address to another
                                                            * @param _from address The address which you want to send tokens from
                                                            * @param _to address The address which you want to transfer to
                                                            * @param _value uint the amount of tokens to be transferred
                                                            */
                                                            function transferFrom(address _from, address _to, uint _value) public onlyPayloadSize(3 * 32) {
                                                                var _allowance = allowed[_from][msg.sender];
                                                        
                                                                // Check is not needed because sub(_allowance, _value) will already throw if this condition is not met
                                                                // if (_value > _allowance) throw;
                                                        
                                                                uint fee = (_value.mul(basisPointsRate)).div(10000);
                                                                if (fee > maximumFee) {
                                                                    fee = maximumFee;
                                                                }
                                                                if (_allowance < MAX_UINT) {
                                                                    allowed[_from][msg.sender] = _allowance.sub(_value);
                                                                }
                                                                uint sendAmount = _value.sub(fee);
                                                                balances[_from] = balances[_from].sub(_value);
                                                                balances[_to] = balances[_to].add(sendAmount);
                                                                if (fee > 0) {
                                                                    balances[owner] = balances[owner].add(fee);
                                                                    Transfer(_from, owner, fee);
                                                                }
                                                                Transfer(_from, _to, sendAmount);
                                                            }
                                                        
                                                            /**
                                                            * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
                                                            * @param _spender The address which will spend the funds.
                                                            * @param _value The amount of tokens to be spent.
                                                            */
                                                            function approve(address _spender, uint _value) public onlyPayloadSize(2 * 32) {
                                                        
                                                                // To change the approve amount you first have to reduce the addresses`
                                                                //  allowance to zero by calling `approve(_spender, 0)` if it is not
                                                                //  already 0 to mitigate the race condition described here:
                                                                //  https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                                                                require(!((_value != 0) && (allowed[msg.sender][_spender] != 0)));
                                                        
                                                                allowed[msg.sender][_spender] = _value;
                                                                Approval(msg.sender, _spender, _value);
                                                            }
                                                        
                                                            /**
                                                            * @dev Function to check the amount of tokens than an owner allowed to a spender.
                                                            * @param _owner address The address which owns the funds.
                                                            * @param _spender address The address which will spend the funds.
                                                            * @return A uint specifying the amount of tokens still available for the spender.
                                                            */
                                                            function allowance(address _owner, address _spender) public constant returns (uint remaining) {
                                                                return allowed[_owner][_spender];
                                                            }
                                                        
                                                        }
                                                        
                                                        
                                                        /**
                                                         * @title Pausable
                                                         * @dev Base contract which allows children to implement an emergency stop mechanism.
                                                         */
                                                        contract Pausable is Ownable {
                                                          event Pause();
                                                          event Unpause();
                                                        
                                                          bool public paused = false;
                                                        
                                                        
                                                          /**
                                                           * @dev Modifier to make a function callable only when the contract is not paused.
                                                           */
                                                          modifier whenNotPaused() {
                                                            require(!paused);
                                                            _;
                                                          }
                                                        
                                                          /**
                                                           * @dev Modifier to make a function callable only when the contract is paused.
                                                           */
                                                          modifier whenPaused() {
                                                            require(paused);
                                                            _;
                                                          }
                                                        
                                                          /**
                                                           * @dev called by the owner to pause, triggers stopped state
                                                           */
                                                          function pause() onlyOwner whenNotPaused public {
                                                            paused = true;
                                                            Pause();
                                                          }
                                                        
                                                          /**
                                                           * @dev called by the owner to unpause, returns to normal state
                                                           */
                                                          function unpause() onlyOwner whenPaused public {
                                                            paused = false;
                                                            Unpause();
                                                          }
                                                        }
                                                        
                                                        contract BlackList is Ownable, BasicToken {
                                                        
                                                            /////// Getters to allow the same blacklist to be used also by other contracts (including upgraded Tether) ///////
                                                            function getBlackListStatus(address _maker) external constant returns (bool) {
                                                                return isBlackListed[_maker];
                                                            }
                                                        
                                                            function getOwner() external constant returns (address) {
                                                                return owner;
                                                            }
                                                        
                                                            mapping (address => bool) public isBlackListed;
                                                            
                                                            function addBlackList (address _evilUser) public onlyOwner {
                                                                isBlackListed[_evilUser] = true;
                                                                AddedBlackList(_evilUser);
                                                            }
                                                        
                                                            function removeBlackList (address _clearedUser) public onlyOwner {
                                                                isBlackListed[_clearedUser] = false;
                                                                RemovedBlackList(_clearedUser);
                                                            }
                                                        
                                                            function destroyBlackFunds (address _blackListedUser) public onlyOwner {
                                                                require(isBlackListed[_blackListedUser]);
                                                                uint dirtyFunds = balanceOf(_blackListedUser);
                                                                balances[_blackListedUser] = 0;
                                                                _totalSupply -= dirtyFunds;
                                                                DestroyedBlackFunds(_blackListedUser, dirtyFunds);
                                                            }
                                                        
                                                            event DestroyedBlackFunds(address _blackListedUser, uint _balance);
                                                        
                                                            event AddedBlackList(address _user);
                                                        
                                                            event RemovedBlackList(address _user);
                                                        
                                                        }
                                                        
                                                        contract UpgradedStandardToken is StandardToken{
                                                            // those methods are called by the legacy contract
                                                            // and they must ensure msg.sender to be the contract address
                                                            function transferByLegacy(address from, address to, uint value) public;
                                                            function transferFromByLegacy(address sender, address from, address spender, uint value) public;
                                                            function approveByLegacy(address from, address spender, uint value) public;
                                                        }
                                                        
                                                        contract TetherToken is Pausable, StandardToken, BlackList {
                                                        
                                                            string public name;
                                                            string public symbol;
                                                            uint public decimals;
                                                            address public upgradedAddress;
                                                            bool public deprecated;
                                                        
                                                            //  The contract can be initialized with a number of tokens
                                                            //  All the tokens are deposited to the owner address
                                                            //
                                                            // @param _balance Initial supply of the contract
                                                            // @param _name Token Name
                                                            // @param _symbol Token symbol
                                                            // @param _decimals Token decimals
                                                            function TetherToken(uint _initialSupply, string _name, string _symbol, uint _decimals) public {
                                                                _totalSupply = _initialSupply;
                                                                name = _name;
                                                                symbol = _symbol;
                                                                decimals = _decimals;
                                                                balances[owner] = _initialSupply;
                                                                deprecated = false;
                                                            }
                                                        
                                                            // Forward ERC20 methods to upgraded contract if this one is deprecated
                                                            function transfer(address _to, uint _value) public whenNotPaused {
                                                                require(!isBlackListed[msg.sender]);
                                                                if (deprecated) {
                                                                    return UpgradedStandardToken(upgradedAddress).transferByLegacy(msg.sender, _to, _value);
                                                                } else {
                                                                    return super.transfer(_to, _value);
                                                                }
                                                            }
                                                        
                                                            // Forward ERC20 methods to upgraded contract if this one is deprecated
                                                            function transferFrom(address _from, address _to, uint _value) public whenNotPaused {
                                                                require(!isBlackListed[_from]);
                                                                if (deprecated) {
                                                                    return UpgradedStandardToken(upgradedAddress).transferFromByLegacy(msg.sender, _from, _to, _value);
                                                                } else {
                                                                    return super.transferFrom(_from, _to, _value);
                                                                }
                                                            }
                                                        
                                                            // Forward ERC20 methods to upgraded contract if this one is deprecated
                                                            function balanceOf(address who) public constant returns (uint) {
                                                                if (deprecated) {
                                                                    return UpgradedStandardToken(upgradedAddress).balanceOf(who);
                                                                } else {
                                                                    return super.balanceOf(who);
                                                                }
                                                            }
                                                        
                                                            // Forward ERC20 methods to upgraded contract if this one is deprecated
                                                            function approve(address _spender, uint _value) public onlyPayloadSize(2 * 32) {
                                                                if (deprecated) {
                                                                    return UpgradedStandardToken(upgradedAddress).approveByLegacy(msg.sender, _spender, _value);
                                                                } else {
                                                                    return super.approve(_spender, _value);
                                                                }
                                                            }
                                                        
                                                            // Forward ERC20 methods to upgraded contract if this one is deprecated
                                                            function allowance(address _owner, address _spender) public constant returns (uint remaining) {
                                                                if (deprecated) {
                                                                    return StandardToken(upgradedAddress).allowance(_owner, _spender);
                                                                } else {
                                                                    return super.allowance(_owner, _spender);
                                                                }
                                                            }
                                                        
                                                            // deprecate current contract in favour of a new one
                                                            function deprecate(address _upgradedAddress) public onlyOwner {
                                                                deprecated = true;
                                                                upgradedAddress = _upgradedAddress;
                                                                Deprecate(_upgradedAddress);
                                                            }
                                                        
                                                            // deprecate current contract if favour of a new one
                                                            function totalSupply() public constant returns (uint) {
                                                                if (deprecated) {
                                                                    return StandardToken(upgradedAddress).totalSupply();
                                                                } else {
                                                                    return _totalSupply;
                                                                }
                                                            }
                                                        
                                                            // Issue a new amount of tokens
                                                            // these tokens are deposited into the owner address
                                                            //
                                                            // @param _amount Number of tokens to be issued
                                                            function issue(uint amount) public onlyOwner {
                                                                require(_totalSupply + amount > _totalSupply);
                                                                require(balances[owner] + amount > balances[owner]);
                                                        
                                                                balances[owner] += amount;
                                                                _totalSupply += amount;
                                                                Issue(amount);
                                                            }
                                                        
                                                            // Redeem tokens.
                                                            // These tokens are withdrawn from the owner address
                                                            // if the balance must be enough to cover the redeem
                                                            // or the call will fail.
                                                            // @param _amount Number of tokens to be issued
                                                            function redeem(uint amount) public onlyOwner {
                                                                require(_totalSupply >= amount);
                                                                require(balances[owner] >= amount);
                                                        
                                                                _totalSupply -= amount;
                                                                balances[owner] -= amount;
                                                                Redeem(amount);
                                                            }
                                                        
                                                            function setParams(uint newBasisPoints, uint newMaxFee) public onlyOwner {
                                                                // Ensure transparency by hardcoding limit beyond which fees can never be added
                                                                require(newBasisPoints < 20);
                                                                require(newMaxFee < 50);
                                                        
                                                                basisPointsRate = newBasisPoints;
                                                                maximumFee = newMaxFee.mul(10**decimals);
                                                        
                                                                Params(basisPointsRate, maximumFee);
                                                            }
                                                        
                                                            // Called when new token are issued
                                                            event Issue(uint amount);
                                                        
                                                            // Called when tokens are redeemed
                                                            event Redeem(uint amount);
                                                        
                                                            // Called when contract is deprecated
                                                            event Deprecate(address newAddress);
                                                        
                                                            // Called if contract ever adds fees
                                                            event Params(uint feeBasisPoints, uint maxFee);
                                                        }

                                                        File 5 of 13: MaplePool
                                                        // SPDX-License-Identifier: BUSL-1.1
                                                        pragma solidity =0.8.7 ^0.8.7;
                                                        
                                                        // contracts/interfaces/Interfaces.sol
                                                        
                                                        interface IERC20Like_0 {
                                                        
                                                            function allowance(address owner_, address spender_) external view returns (uint256 allowance_);
                                                        
                                                            function balanceOf(address account_) external view returns (uint256 balance_);
                                                        
                                                            function totalSupply() external view returns (uint256 totalSupply_);
                                                        
                                                        }
                                                        
                                                        interface IGlobalsLike {
                                                        
                                                            function bootstrapMint(address asset_) external view returns (uint256 bootstrapMint_);
                                                        
                                                            function governor() external view returns (address governor_);
                                                        
                                                            function isFunctionPaused(bytes4 sig_) external view returns (bool isFunctionPaused_);
                                                        
                                                            function isInstanceOf(bytes32 instanceId_, address instance_) external view returns (bool isInstance_);
                                                        
                                                            function isPoolAsset(address asset_) external view returns (bool isPoolAsset_);
                                                        
                                                            function isPoolDelegate(address account_) external view returns (bool isPoolDelegate_);
                                                        
                                                            function isPoolDeployer(address poolDeployer_) external view returns (bool isPoolDeployer_);
                                                        
                                                            function isValidScheduledCall(address caller_, address contract_, bytes32 functionId_, bytes calldata callData_)
                                                                external view
                                                                returns (bool isValid_);
                                                        
                                                            function mapleTreasury() external view returns (address mapleTreasury_);
                                                        
                                                            function maxCoverLiquidationPercent(address poolManager_) external view returns (uint256 maxCoverLiquidationPercent_);
                                                        
                                                            function migrationAdmin() external view returns (address migrationAdmin_);
                                                        
                                                            function minCoverAmount(address poolManager_) external view returns (uint256 minCoverAmount_);
                                                        
                                                            function operationalAdmin() external view returns (address operationalAdmin_);
                                                        
                                                            function ownedPoolManager(address poolDelegate_) external view returns (address poolManager_);
                                                        
                                                            function securityAdmin() external view returns (address securityAdmin_);
                                                        
                                                            function transferOwnedPoolManager(address fromPoolDelegate_, address toPoolDelegate_) external;
                                                        
                                                            function unscheduleCall(address caller_, bytes32 functionId_, bytes calldata callData_) external;
                                                        
                                                        }
                                                        
                                                        interface ILoanManagerLike {
                                                        
                                                            function assetsUnderManagement() external view returns (uint256 assetsUnderManagement_);
                                                        
                                                            function finishCollateralLiquidation(address loan_) external returns (uint256 remainingLosses_, uint256 serviceFee_);
                                                        
                                                            function triggerDefault(address loan_, address liquidatorFactory_)
                                                                external
                                                                returns (bool liquidationComplete_, uint256 remainingLosses_, uint256 platformFees_);
                                                        
                                                            function unrealizedLosses() external view returns (uint256 unrealizedLosses_);
                                                        
                                                        }
                                                        
                                                        interface ILoanLike {
                                                        
                                                            function lender() external view returns (address lender_);
                                                        
                                                        }
                                                        
                                                        interface IMapleProxyFactoryLike {
                                                        
                                                            function isInstance(address instance_) external view returns (bool isInstance_);
                                                        
                                                            function mapleGlobals() external view returns (address mapleGlobals_);
                                                        
                                                        }
                                                        
                                                        interface IPoolDelegateCoverLike {
                                                        
                                                            function moveFunds(uint256 amount_, address recipient_) external;
                                                        
                                                        }
                                                        
                                                        interface IPoolLike is IERC20Like_0 {
                                                        
                                                            function convertToExitShares(uint256 assets_) external view returns (uint256 shares_);
                                                        
                                                            function previewDeposit(uint256 assets_) external view returns (uint256 shares_);
                                                        
                                                            function previewMint(uint256 shares_) external view returns (uint256 assets_);
                                                        
                                                        }
                                                        
                                                        interface IPoolManagerLike {
                                                        
                                                            function addLoanManager(address loanManagerFactory_) external returns (address loanManager_);
                                                        
                                                            function canCall(bytes32 functionId_, address caller_, bytes memory data_)
                                                                external view
                                                                returns (bool canCall_, string memory errorMessage_);
                                                        
                                                            function completeConfiguration() external;
                                                        
                                                            function getEscrowParams(address owner_, uint256 shares_) external view returns (uint256 escrowShares_, address escrow_);
                                                        
                                                            function maxDeposit(address receiver_) external view returns (uint256 maxAssets_);
                                                        
                                                            function maxMint(address receiver_) external view returns (uint256 maxShares_);
                                                        
                                                            function maxRedeem(address owner_) external view returns (uint256 maxShares_);
                                                        
                                                            function maxWithdraw(address owner_) external view returns (uint256 maxAssets_);
                                                        
                                                            function pool() external view returns (address pool_);
                                                        
                                                            function poolDelegateCover() external view returns (address poolDelegateCover_);
                                                        
                                                            function previewRedeem(address owner_, uint256 shares_) external view returns (uint256 assets_);
                                                        
                                                            function previewWithdraw(address owner_, uint256 assets_) external view returns (uint256 shares_);
                                                        
                                                            function processRedeem(uint256 shares_, address owner_, address sender_)
                                                                external
                                                                returns (uint256 redeemableShares_, uint256 resultingAssets_);
                                                        
                                                            function processWithdraw(uint256 assets_, address owner_, address sender_)
                                                                external
                                                                returns (uint256 redeemableShares_, uint256 resultingAssets_);
                                                        
                                                            function removeShares(uint256 shares_, address owner_) external returns (uint256 sharesReturned_);
                                                        
                                                            function requestRedeem(uint256 shares_, address owner_, address sender_) external;
                                                        
                                                            function requestWithdraw(uint256 shares_, uint256 assets_, address owner_, address sender_) external;
                                                        
                                                            function setDelegateManagementFeeRate(uint256 delegateManagementFeeRate_) external;
                                                        
                                                            function setLiquidityCap(uint256 liquidityCap_) external;
                                                        
                                                            function setPoolPermissionManager(address poolPermissionManager_) external;
                                                        
                                                            function setWithdrawalManager(address withdrawalManager_) external;
                                                        
                                                            function totalAssets() external view returns (uint256 totalAssets_);
                                                        
                                                            function unrealizedLosses() external view returns (uint256 unrealizedLosses_);
                                                        
                                                        }
                                                        
                                                        interface IPoolPermissionManagerLike {
                                                        
                                                            function hasPermission(address poolManager, address caller, bytes32 functionId) external view returns (bool allowed);
                                                        
                                                            function hasPermission(address poolManager, address[] calldata caller, bytes32 functionId) external view returns (bool allowed);
                                                        
                                                        }
                                                        
                                                        interface IWithdrawalManagerLike {
                                                        
                                                            function addShares(uint256 shares_, address owner_) external;
                                                        
                                                            function factory() external view returns (address factory_);
                                                        
                                                            function isInExitWindow(address owner_) external view returns (bool isInExitWindow_);
                                                        
                                                            function lockedLiquidity() external view returns (uint256 lockedLiquidity_);
                                                        
                                                            function lockedShares(address owner_) external view returns (uint256 lockedShares_);
                                                        
                                                            function previewRedeem(address owner_, uint256 shares) external view returns (uint256 redeemableShares, uint256 resultingAssets_);
                                                        
                                                            function previewWithdraw(address owner_, uint256 assets_) external view returns (uint256 redeemableAssets_, uint256 resultingShares_);
                                                        
                                                            function processExit(uint256 shares_, address account_) external returns (uint256 redeemableShares_, uint256 resultingAssets_);
                                                        
                                                            function removeShares(uint256 shares_, address owner_) external returns (uint256 sharesReturned_);
                                                        
                                                        }
                                                        
                                                        // modules/erc20/contracts/interfaces/IERC20.sol
                                                        
                                                        /// @title Interface of the ERC20 standard as defined in the EIP, including EIP-2612 permit functionality.
                                                        interface IERC20 {
                                                        
                                                            /**************************************************************************************************************************************/
                                                            /*** Events                                                                                                                         ***/
                                                            /**************************************************************************************************************************************/
                                                        
                                                            /**
                                                             *  @dev   Emitted when one account has set the allowance of another account over their tokens.
                                                             *  @param owner_   Account that tokens are approved from.
                                                             *  @param spender_ Account that tokens are approved for.
                                                             *  @param amount_  Amount of tokens that have been approved.
                                                             */
                                                            event Approval(address indexed owner_, address indexed spender_, uint256 amount_);
                                                        
                                                            /**
                                                             *  @dev   Emitted when tokens have moved from one account to another.
                                                             *  @param owner_     Account that tokens have moved from.
                                                             *  @param recipient_ Account that tokens have moved to.
                                                             *  @param amount_    Amount of tokens that have been transferred.
                                                             */
                                                            event Transfer(address indexed owner_, address indexed recipient_, uint256 amount_);
                                                        
                                                            /**************************************************************************************************************************************/
                                                            /*** External Functions                                                                                                             ***/
                                                            /**************************************************************************************************************************************/
                                                        
                                                            /**
                                                             *  @dev    Function that allows one account to set the allowance of another account over their tokens.
                                                             *          Emits an {Approval} event.
                                                             *  @param  spender_ Account that tokens are approved for.
                                                             *  @param  amount_  Amount of tokens that have been approved.
                                                             *  @return success_ Boolean indicating whether the operation succeeded.
                                                             */
                                                            function approve(address spender_, uint256 amount_) external returns (bool success_);
                                                        
                                                            /**
                                                             *  @dev    Function that allows one account to decrease the allowance of another account over their tokens.
                                                             *          Emits an {Approval} event.
                                                             *  @param  spender_          Account that tokens are approved for.
                                                             *  @param  subtractedAmount_ Amount to decrease approval by.
                                                             *  @return success_          Boolean indicating whether the operation succeeded.
                                                             */
                                                            function decreaseAllowance(address spender_, uint256 subtractedAmount_) external returns (bool success_);
                                                        
                                                            /**
                                                             *  @dev    Function that allows one account to increase the allowance of another account over their tokens.
                                                             *          Emits an {Approval} event.
                                                             *  @param  spender_     Account that tokens are approved for.
                                                             *  @param  addedAmount_ Amount to increase approval by.
                                                             *  @return success_     Boolean indicating whether the operation succeeded.
                                                             */
                                                            function increaseAllowance(address spender_, uint256 addedAmount_) external returns (bool success_);
                                                        
                                                            /**
                                                             *  @dev   Approve by signature.
                                                             *  @param owner_    Owner address that signed the permit.
                                                             *  @param spender_  Spender of the permit.
                                                             *  @param amount_   Permit approval spend limit.
                                                             *  @param deadline_ Deadline after which the permit is invalid.
                                                             *  @param v_        ECDSA signature v component.
                                                             *  @param r_        ECDSA signature r component.
                                                             *  @param s_        ECDSA signature s component.
                                                             */
                                                            function permit(address owner_, address spender_, uint amount_, uint deadline_, uint8 v_, bytes32 r_, bytes32 s_) external;
                                                        
                                                            /**
                                                             *  @dev    Moves an amount of tokens from `msg.sender` to a specified account.
                                                             *          Emits a {Transfer} event.
                                                             *  @param  recipient_ Account that receives tokens.
                                                             *  @param  amount_    Amount of tokens that are transferred.
                                                             *  @return success_   Boolean indicating whether the operation succeeded.
                                                             */
                                                            function transfer(address recipient_, uint256 amount_) external returns (bool success_);
                                                        
                                                            /**
                                                             *  @dev    Moves a pre-approved amount of tokens from a sender to a specified account.
                                                             *          Emits a {Transfer} event.
                                                             *          Emits an {Approval} event.
                                                             *  @param  owner_     Account that tokens are moving from.
                                                             *  @param  recipient_ Account that receives tokens.
                                                             *  @param  amount_    Amount of tokens that are transferred.
                                                             *  @return success_   Boolean indicating whether the operation succeeded.
                                                             */
                                                            function transferFrom(address owner_, address recipient_, uint256 amount_) external returns (bool success_);
                                                        
                                                            /**************************************************************************************************************************************/
                                                            /*** View Functions                                                                                                                 ***/
                                                            /**************************************************************************************************************************************/
                                                        
                                                            /**
                                                             *  @dev    Returns the allowance that one account has given another over their tokens.
                                                             *  @param  owner_     Account that tokens are approved from.
                                                             *  @param  spender_   Account that tokens are approved for.
                                                             *  @return allowance_ Allowance that one account has given another over their tokens.
                                                             */
                                                            function allowance(address owner_, address spender_) external view returns (uint256 allowance_);
                                                        
                                                            /**
                                                             *  @dev    Returns the amount of tokens owned by a given account.
                                                             *  @param  account_ Account that owns the tokens.
                                                             *  @return balance_ Amount of tokens owned by a given account.
                                                             */
                                                            function balanceOf(address account_) external view returns (uint256 balance_);
                                                        
                                                            /**
                                                             *  @dev    Returns the decimal precision used by the token.
                                                             *  @return decimals_ The decimal precision used by the token.
                                                             */
                                                            function decimals() external view returns (uint8 decimals_);
                                                        
                                                            /**
                                                             *  @dev    Returns the signature domain separator.
                                                             *  @return domainSeparator_ The signature domain separator.
                                                             */
                                                            function DOMAIN_SEPARATOR() external view returns (bytes32 domainSeparator_);
                                                        
                                                            /**
                                                             *  @dev    Returns the name of the token.
                                                             *  @return name_ The name of the token.
                                                             */
                                                            function name() external view returns (string memory name_);
                                                        
                                                            /**
                                                              *  @dev    Returns the nonce for the given owner.
                                                              *  @param  owner_  The address of the owner account.
                                                              *  @return nonce_ The nonce for the given owner.
                                                             */
                                                            function nonces(address owner_) external view returns (uint256 nonce_);
                                                        
                                                            /**
                                                             *  @dev    Returns the permit type hash.
                                                             *  @return permitTypehash_ The permit type hash.
                                                             */
                                                            function PERMIT_TYPEHASH() external view returns (bytes32 permitTypehash_);
                                                        
                                                            /**
                                                             *  @dev    Returns the symbol of the token.
                                                             *  @return symbol_ The symbol of the token.
                                                             */
                                                            function symbol() external view returns (string memory symbol_);
                                                        
                                                            /**
                                                             *  @dev    Returns the total amount of tokens in existence.
                                                             *  @return totalSupply_ The total amount of tokens in existence.
                                                             */
                                                            function totalSupply() external view returns (uint256 totalSupply_);
                                                        
                                                        }
                                                        
                                                        // modules/erc20-helper/src/interfaces/IERC20Like.sol
                                                        
                                                        /// @title Interface of the ERC20 standard as needed by ERC20Helper.
                                                        interface IERC20Like_1 {
                                                        
                                                            function approve(address spender_, uint256 amount_) external returns (bool success_);
                                                        
                                                            function transfer(address recipient_, uint256 amount_) external returns (bool success_);
                                                        
                                                            function transferFrom(address owner_, address recipient_, uint256 amount_) external returns (bool success_);
                                                        
                                                        }
                                                        
                                                        // contracts/interfaces/IERC4626.sol
                                                        
                                                        /// @title A standard for tokenized Vaults with a single underlying ERC-20 token.
                                                        interface IERC4626 is IERC20 {
                                                        
                                                            /**************************************************************************************************************************************/
                                                            /*** Events                                                                                                                         ***/
                                                            /**************************************************************************************************************************************/
                                                        
                                                            /**
                                                             *  @dev   `caller_` has exchanged `assets_` for `shares_` and transferred them to `owner_`.
                                                             *         MUST be emitted when assets are deposited via the `deposit` or `mint` methods.
                                                             *  @param caller_ The caller of the function that emitted the `Deposit` event.
                                                             *  @param owner_  The owner of the shares.
                                                             *  @param assets_ The amount of assets deposited.
                                                             *  @param shares_ The amount of shares minted.
                                                             */
                                                            event Deposit(address indexed caller_, address indexed owner_, uint256 assets_, uint256 shares_);
                                                        
                                                            /**
                                                             *  @dev   `caller_` has exchanged `shares_`, owned by `owner_`, for `assets_`, and transferred them to `receiver_`.
                                                             *         MUST be emitted when assets are withdrawn via the `withdraw` or `redeem` methods.
                                                             *  @param caller_   The caller of the function that emitted the `Withdraw` event.
                                                             *  @param receiver_ The receiver of the assets.
                                                             *  @param owner_    The owner of the shares.
                                                             *  @param assets_   The amount of assets withdrawn.
                                                             *  @param shares_   The amount of shares burned.
                                                             */
                                                            event Withdraw(address indexed caller_, address indexed receiver_, address indexed owner_, uint256 assets_, uint256 shares_);
                                                        
                                                            /**************************************************************************************************************************************/
                                                            /*** State Variables                                                                                                                ***/
                                                            /**************************************************************************************************************************************/
                                                        
                                                            /**
                                                             *  @dev    The address of the underlying asset used by the Vault.
                                                             *          MUST be a contract that implements the ERC-20 standard.
                                                             *          MUST NOT revert.
                                                             *  @return asset_ The address of the underlying asset.
                                                             */
                                                            function asset() external view returns (address asset_);
                                                        
                                                            /**************************************************************************************************************************************/
                                                            /*** State Changing Functions                                                                                                       ***/
                                                            /**************************************************************************************************************************************/
                                                        
                                                            /**
                                                             *  @dev    Mints `shares_` to `receiver_` by depositing `assets_` into the Vault.
                                                             *          MUST emit the {Deposit} event.
                                                             *          MUST revert if all of the assets cannot be deposited (due to insufficient approval, deposit limits, slippage, etc).
                                                             *  @param  assets_   The amount of assets to deposit.
                                                             *  @param  receiver_ The receiver of the shares.
                                                             *  @return shares_   The amount of shares minted.
                                                             */
                                                            function deposit(uint256 assets_, address receiver_) external returns (uint256 shares_);
                                                        
                                                            /**
                                                             *  @dev    Mints `shares_` to `receiver_` by depositing `assets_` into the Vault.
                                                             *          MUST emit the {Deposit} event.
                                                             *          MUST revert if all of shares cannot be minted (due to insufficient approval, deposit limits, slippage, etc).
                                                             *  @param  shares_   The amount of shares to mint.
                                                             *  @param  receiver_ The receiver of the shares.
                                                             *  @return assets_   The amount of assets deposited.
                                                             */
                                                            function mint(uint256 shares_, address receiver_) external returns (uint256 assets_);
                                                        
                                                            /**
                                                             *  @dev    Burns `shares_` from `owner_` and sends `assets_` to `receiver_`.
                                                             *          MUST emit the {Withdraw} event.
                                                             *          MUST revert if all of the shares cannot be redeemed (due to insufficient shares, withdrawal limits, slippage, etc).
                                                             *  @param  shares_   The amount of shares to redeem.
                                                             *  @param  receiver_ The receiver of the assets.
                                                             *  @param  owner_    The owner of the shares.
                                                             *  @return assets_   The amount of assets sent to the receiver.
                                                             */
                                                            function redeem(uint256 shares_, address receiver_, address owner_) external returns (uint256 assets_);
                                                        
                                                            /**
                                                             *  @dev    Burns `shares_` from `owner_` and sends `assets_` to `receiver_`.
                                                             *          MUST emit the {Withdraw} event.
                                                             *          MUST revert if all of the assets cannot be withdrawn (due to insufficient assets, withdrawal limits, slippage, etc).
                                                             *  @param  assets_   The amount of assets to withdraw.
                                                             *  @param  receiver_ The receiver of the assets.
                                                             *  @param  owner_    The owner of the assets.
                                                             *  @return shares_   The amount of shares burned from the owner.
                                                             */
                                                            function withdraw(uint256 assets_, address receiver_, address owner_) external returns (uint256 shares_);
                                                        
                                                            /**************************************************************************************************************************************/
                                                            /*** View Functions                                                                                                                 ***/
                                                            /**************************************************************************************************************************************/
                                                        
                                                            /**
                                                             *  @dev    The amount of `assets_` the `shares_` are currently equivalent to.
                                                             *          MUST NOT be inclusive of any fees that are charged against assets in the Vault.
                                                             *          MUST NOT reflect slippage or other on-chain conditions when performing the actual exchange.
                                                             *          MUST NOT show any variations depending on the caller.
                                                             *          MUST NOT revert.
                                                             *  @param  shares_ The amount of shares to convert.
                                                             *  @return assets_ The amount of equivalent assets.
                                                             */
                                                            function convertToAssets(uint256 shares_) external view returns (uint256 assets_);
                                                        
                                                            /**
                                                             *  @dev    The amount of `shares_` the `assets_` are currently equivalent to.
                                                             *          MUST NOT be inclusive of any fees that are charged against assets in the Vault.
                                                             *          MUST NOT reflect slippage or other on-chain conditions when performing the actual exchange.
                                                             *          MUST NOT show any variations depending on the caller.
                                                             *          MUST NOT revert.
                                                             *  @param  assets_ The amount of assets to convert.
                                                             *  @return shares_ The amount of equivalent shares.
                                                             */
                                                            function convertToShares(uint256 assets_) external view returns (uint256 shares_);
                                                        
                                                            /**
                                                             *  @dev    Maximum amount of `assets_` that can be deposited on behalf of the `receiver_` through a `deposit` call.
                                                             *          MUST return a limited value if the receiver is subject to any limits, or the maximum value otherwise.
                                                             *          MUST NOT revert.
                                                             *  @param  receiver_ The receiver of the assets.
                                                             *  @return assets_   The maximum amount of assets that can be deposited.
                                                             */
                                                            function maxDeposit(address receiver_) external view returns (uint256 assets_);
                                                        
                                                            /**
                                                             *  @dev    Maximum amount of `shares_` that can be minted on behalf of the `receiver_` through a `mint` call.
                                                             *          MUST return a limited value if the receiver is subject to any limits, or the maximum value otherwise.
                                                             *          MUST NOT revert.
                                                             *  @param  receiver_ The receiver of the shares.
                                                             *  @return shares_   The maximum amount of shares that can be minted.
                                                             */
                                                            function maxMint(address receiver_) external view returns (uint256 shares_);
                                                        
                                                            /**
                                                             *  @dev    Maximum amount of `shares_` that can be redeemed from the `owner_` through a `redeem` call.
                                                             *          MUST return a limited value if the owner is subject to any limits, or the total amount of owned shares otherwise.
                                                             *          MUST NOT revert.
                                                             *  @param  owner_  The owner of the shares.
                                                             *  @return shares_ The maximum amount of shares that can be redeemed.
                                                             */
                                                            function maxRedeem(address owner_) external view returns (uint256 shares_);
                                                        
                                                            /**
                                                             *  @dev    Maximum amount of `assets_` that can be withdrawn from the `owner_` through a `withdraw` call.
                                                             *          MUST return a limited value if the owner is subject to any limits, or the total amount of owned assets otherwise.
                                                             *          MUST NOT revert.
                                                             *  @param  owner_  The owner of the assets.
                                                             *  @return assets_ The maximum amount of assets that can be withdrawn.
                                                             */
                                                            function maxWithdraw(address owner_) external view returns (uint256 assets_);
                                                        
                                                            /**
                                                             *  @dev    Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given current on-chain conditions.
                                                             *          MUST return as close to and no more than the exact amount of shares that would be minted in a `deposit` call in the same transaction.
                                                             *          MUST NOT account for deposit limits like those returned from `maxDeposit` and should always act as though the deposit would be accepted.
                                                             *  @param  assets_ The amount of assets to deposit.
                                                             *  @return shares_ The amount of shares that would be minted.
                                                             */
                                                            function previewDeposit(uint256 assets_) external view returns (uint256 shares_);
                                                        
                                                            /**
                                                             *  @dev    Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given current on-chain conditions.
                                                             *          MUST return as close to and no fewer than the exact amount of assets that would be deposited in a `mint` call in the same transaction.
                                                             *          MUST NOT account for mint limits like those returned from `maxMint` and should always act as though the minting would be accepted.
                                                             *  @param  shares_ The amount of shares to mint.
                                                             *  @return assets_ The amount of assets that would be deposited.
                                                             */
                                                            function previewMint(uint256 shares_) external view returns (uint256 assets_);
                                                        
                                                            /**
                                                             *  @dev    Allows an on-chain or off-chain user to simulate the effects of their redemption at the current block, given current on-chain conditions.
                                                             *          MUST return as close to and no more than the exact amount of assets that would be withdrawn in a `redeem` call in the same transaction.
                                                             *          MUST NOT account for redemption limits like those returned from `maxRedeem` and should always act as though the redemption would be accepted.
                                                             *  @param  shares_ The amount of shares to redeem.
                                                             *  @return assets_ The amount of assets that would be withdrawn.
                                                             */
                                                            function previewRedeem(uint256 shares_) external view returns (uint256 assets_);
                                                        
                                                            /**
                                                             *  @dev    Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block, given current on-chain conditions.
                                                             *          MUST return as close to and no fewer than the exact amount of shares that would be burned in a `withdraw` call in the same transaction.
                                                             *          MUST NOT account for withdrawal limits like those returned from `maxWithdraw` and should always act as though the withdrawal would be accepted.
                                                             *  @param  assets_ The amount of assets to withdraw.
                                                             *  @return shares_ The amount of shares that would be redeemed.
                                                             */
                                                            function previewWithdraw(uint256 assets_) external view returns (uint256 shares_);
                                                        
                                                            /**
                                                             *  @dev    Total amount of the underlying asset that is managed by the Vault.
                                                             *          SHOULD include compounding that occurs from any yields.
                                                             *          MUST NOT revert.
                                                             *  @return totalAssets_ The total amount of assets the Vault manages.
                                                             */
                                                            function totalAssets() external view returns (uint256 totalAssets_);
                                                        
                                                        }
                                                        
                                                        // modules/erc20/contracts/ERC20.sol
                                                        
                                                        /*
                                                            ███████╗██████╗  ██████╗    ██████╗  ██████╗
                                                            ██╔════╝██╔══██╗██╔════╝    ╚════██╗██╔═████╗
                                                            █████╗  ██████╔╝██║          █████╔╝██║██╔██║
                                                            ██╔══╝  ██╔══██╗██║         ██╔═══╝ ████╔╝██║
                                                            ███████╗██║  ██║╚██████╗    ███████╗╚██████╔╝
                                                            ╚══════╝╚═╝  ╚═╝ ╚═════╝    ╚══════╝ ╚═════╝
                                                        */
                                                        
                                                        /**
                                                         *  @title Modern ERC-20 implementation.
                                                         *  @dev   Acknowledgements to Solmate, OpenZeppelin, and DSS for inspiring this code.
                                                         */
                                                        contract ERC20 is IERC20 {
                                                        
                                                            /**************************************************************************************************************************************/
                                                            /*** ERC-20                                                                                                                         ***/
                                                            /**************************************************************************************************************************************/
                                                        
                                                            string public override name;
                                                            string public override symbol;
                                                        
                                                            uint8 public immutable override decimals;
                                                        
                                                            uint256 public override totalSupply;
                                                        
                                                            mapping(address => uint256) public override balanceOf;
                                                        
                                                            mapping(address => mapping(address => uint256)) public override allowance;
                                                        
                                                            /**************************************************************************************************************************************/
                                                            /*** ERC-2612                                                                                                                       ***/
                                                            /**************************************************************************************************************************************/
                                                        
                                                            // PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
                                                            bytes32 public constant override PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
                                                        
                                                            mapping(address => uint256) public override nonces;
                                                        
                                                            /**
                                                             *  @param name_     The name of the token.
                                                             *  @param symbol_   The symbol of the token.
                                                             *  @param decimals_ The decimal precision used by the token.
                                                             */
                                                            constructor(string memory name_, string memory symbol_, uint8 decimals_) {
                                                                name     = name_;
                                                                symbol   = symbol_;
                                                                decimals = decimals_;
                                                            }
                                                        
                                                            /**************************************************************************************************************************************/
                                                            /*** External Functions                                                                                                             ***/
                                                            /**************************************************************************************************************************************/
                                                        
                                                            function approve(address spender_, uint256 amount_) public virtual override returns (bool success_) {
                                                                _approve(msg.sender, spender_, amount_);
                                                                return true;
                                                            }
                                                        
                                                            function decreaseAllowance(address spender_, uint256 subtractedAmount_) public virtual override returns (bool success_) {
                                                                _decreaseAllowance(msg.sender, spender_, subtractedAmount_);
                                                                return true;
                                                            }
                                                        
                                                            function increaseAllowance(address spender_, uint256 addedAmount_) public virtual override returns (bool success_) {
                                                                _approve(msg.sender, spender_, allowance[msg.sender][spender_] + addedAmount_);
                                                                return true;
                                                            }
                                                        
                                                            function permit(address owner_, address spender_, uint256 amount_, uint256 deadline_, uint8 v_, bytes32 r_, bytes32 s_)
                                                                public virtual override
                                                            {
                                                                require(deadline_ >= block.timestamp, "ERC20:P:EXPIRED");
                                                        
                                                                // Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
                                                                // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}.
                                                                require(
                                                                    uint256(s_) <= uint256(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) &&
                                                                    (v_ == 27 || v_ == 28),
                                                                    "ERC20:P:MALLEABLE"
                                                                );
                                                        
                                                                // Nonce realistically cannot overflow.
                                                                unchecked {
                                                                    bytes32 digest_ = keccak256(
                                                                        abi.encodePacked(
                                                                            "\x19\x01",
                                                                            DOMAIN_SEPARATOR(),
                                                                            keccak256(abi.encode(PERMIT_TYPEHASH, owner_, spender_, amount_, nonces[owner_]++, deadline_))
                                                                        )
                                                                    );
                                                        
                                                                    address recoveredAddress_ = ecrecover(digest_, v_, r_, s_);
                                                        
                                                                    require(recoveredAddress_ == owner_ && owner_ != address(0), "ERC20:P:INVALID_SIGNATURE");
                                                                }
                                                        
                                                                _approve(owner_, spender_, amount_);
                                                            }
                                                        
                                                            function transfer(address recipient_, uint256 amount_) public virtual override returns (bool success_) {
                                                                _transfer(msg.sender, recipient_, amount_);
                                                                return true;
                                                            }
                                                        
                                                            function transferFrom(address owner_, address recipient_, uint256 amount_) public virtual override returns (bool success_) {
                                                                _decreaseAllowance(owner_, msg.sender, amount_);
                                                                _transfer(owner_, recipient_, amount_);
                                                                return true;
                                                            }
                                                        
                                                            /**************************************************************************************************************************************/
                                                            /*** View Functions                                                                                                                 ***/
                                                            /**************************************************************************************************************************************/
                                                        
                                                            function DOMAIN_SEPARATOR() public view override returns (bytes32 domainSeparator_) {
                                                                return keccak256(
                                                                    abi.encode(
                                                                        keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                                                                        keccak256(bytes(name)),
                                                                        keccak256(bytes("1")),
                                                                        block.chainid,
                                                                        address(this)
                                                                    )
                                                                );
                                                            }
                                                        
                                                            /**************************************************************************************************************************************/
                                                            /*** Internal Functions                                                                                                             ***/
                                                            /**************************************************************************************************************************************/
                                                        
                                                            function _approve(address owner_, address spender_, uint256 amount_) internal {
                                                                emit Approval(owner_, spender_, allowance[owner_][spender_] = amount_);
                                                            }
                                                        
                                                            function _burn(address owner_, uint256 amount_) internal {
                                                                balanceOf[owner_] -= amount_;
                                                        
                                                                // Cannot underflow because a user's balance will never be larger than the total supply.
                                                                unchecked { totalSupply -= amount_; }
                                                        
                                                                emit Transfer(owner_, address(0), amount_);
                                                            }
                                                        
                                                            function _decreaseAllowance(address owner_, address spender_, uint256 subtractedAmount_) internal {
                                                                uint256 spenderAllowance = allowance[owner_][spender_];  // Cache to memory.
                                                        
                                                                if (spenderAllowance != type(uint256).max) {
                                                                    _approve(owner_, spender_, spenderAllowance - subtractedAmount_);
                                                                }
                                                            }
                                                        
                                                            function _mint(address recipient_, uint256 amount_) internal {
                                                                totalSupply += amount_;
                                                        
                                                                // Cannot overflow because totalSupply would first overflow in the statement above.
                                                                unchecked { balanceOf[recipient_] += amount_; }
                                                        
                                                                emit Transfer(address(0), recipient_, amount_);
                                                            }
                                                        
                                                            function _transfer(address owner_, address recipient_, uint256 amount_) internal {
                                                                balanceOf[owner_] -= amount_;
                                                        
                                                                // Cannot overflow because minting prevents overflow of totalSupply, and sum of user balances == totalSupply.
                                                                unchecked { balanceOf[recipient_] += amount_; }
                                                        
                                                                emit Transfer(owner_, recipient_, amount_);
                                                            }
                                                        
                                                        }
                                                        
                                                        // modules/erc20-helper/src/ERC20Helper.sol
                                                        
                                                        /**
                                                         * @title Small Library to standardize erc20 token interactions.
                                                         */
                                                        library ERC20Helper {
                                                        
                                                            /**************************************************************************************************************************************/
                                                            /*** Internal Functions                                                                                                             ***/
                                                            /**************************************************************************************************************************************/
                                                        
                                                            function transfer(address token_, address to_, uint256 amount_) internal returns (bool success_) {
                                                                return _call(token_, abi.encodeWithSelector(IERC20Like_1.transfer.selector, to_, amount_));
                                                            }
                                                        
                                                            function transferFrom(address token_, address from_, address to_, uint256 amount_) internal returns (bool success_) {
                                                                return _call(token_, abi.encodeWithSelector(IERC20Like_1.transferFrom.selector, from_, to_, amount_));
                                                            }
                                                        
                                                            function approve(address token_, address spender_, uint256 amount_) internal returns (bool success_) {
                                                                // If setting approval to zero fails, return false.
                                                                if (!_call(token_, abi.encodeWithSelector(IERC20Like_1.approve.selector, spender_, uint256(0)))) return false;
                                                        
                                                                // If `amount_` is zero, return true as the previous step already did this.
                                                                if (amount_ == uint256(0)) return true;
                                                        
                                                                // Return the result of setting the approval to `amount_`.
                                                                return _call(token_, abi.encodeWithSelector(IERC20Like_1.approve.selector, spender_, amount_));
                                                            }
                                                        
                                                            function _call(address token_, bytes memory data_) private returns (bool success_) {
                                                                if (token_.code.length == uint256(0)) return false;
                                                        
                                                                bytes memory returnData;
                                                                ( success_, returnData ) = token_.call(data_);
                                                        
                                                                return success_ && (returnData.length == uint256(0) || abi.decode(returnData, (bool)));
                                                            }
                                                        
                                                        }
                                                        
                                                        // contracts/interfaces/IMaplePool.sol
                                                        
                                                        interface IMaplePool is IERC20, IERC4626 {
                                                        
                                                            /**************************************************************************************************************************************/
                                                            /*** Events                                                                                                                         ***/
                                                            /**************************************************************************************************************************************/
                                                        
                                                            /**
                                                             *  @dev   Initial shares amount was minted to the zero address to prevent the first depositor frontrunning exploit.
                                                             *  @param caller_              The caller of the function that emitted the `BootstrapMintPerformed` event.
                                                             *  @param receiver_            The user that was minted the shares.
                                                             *  @param assets_              The amount of assets deposited.
                                                             *  @param shares_              The amount of shares that would have been minted to the user if it was not the first deposit.
                                                             *  @param bootStrapMintAmount_ The amount of shares that was minted to the zero address to protect the first depositor.
                                                             */
                                                            event BootstrapMintPerformed(
                                                                address indexed caller_,
                                                                address indexed receiver_,
                                                                uint256 assets_,
                                                                uint256 shares_,
                                                                uint256 bootStrapMintAmount_
                                                            );
                                                        
                                                            /**
                                                             *  @dev   `newOwner_` has accepted the transferral of RDT ownership from `previousOwner_`.
                                                             *  @param previousOwner_ The previous RDT owner.
                                                             *  @param newOwner_      The new RDT owner.
                                                             */
                                                            event OwnershipAccepted(address indexed previousOwner_, address indexed newOwner_);
                                                        
                                                            /**
                                                             *  @dev   `owner_` has set the new pending owner of RDT to `pendingOwner_`.
                                                             *  @param owner_        The current RDT owner.
                                                             *  @param pendingOwner_ The new pending RDT owner.
                                                             */
                                                            event PendingOwnerSet(address indexed owner_, address indexed pendingOwner_);
                                                        
                                                            /**
                                                             *  @dev   A new redemption request has been made.
                                                             *  @param owner_          The owner of shares.
                                                             *  @param shares_         The amount of shares requested to redeem.
                                                             *  @param escrowedShares_ The amount of shares actually escrowed for this withdrawal request.
                                                             */
                                                            event RedemptionRequested(address indexed owner_, uint256 shares_, uint256 escrowedShares_);
                                                        
                                                            /**
                                                             *  @dev   Shares have been removed.
                                                             *  @param owner_  The owner of shares.
                                                             *  @param shares_ The amount of shares requested to be removed.
                                                             */
                                                            event SharesRemoved(address indexed owner_, uint256 shares_);
                                                        
                                                            /**
                                                             *  @dev   A new withdrawal request has been made.
                                                             *  @param owner_          The owner of shares.
                                                             *  @param assets_         The amount of assets requested to withdraw.
                                                             *  @param escrowedShares_ The amount of shares actually escrowed for this withdrawal request.
                                                             */
                                                            event WithdrawRequested(address indexed owner_, uint256 assets_, uint256 escrowedShares_);
                                                        
                                                            /**************************************************************************************************************************************/
                                                            /*** State Variables                                                                                                                ***/
                                                            /**************************************************************************************************************************************/
                                                        
                                                            /**
                                                             *  @dev    The amount of shares that will be burned during the first deposit/mint.
                                                             *  @return bootstrapMint_ The amount of shares to be burned.
                                                             */
                                                            function BOOTSTRAP_MINT() external view returns (uint256 bootstrapMint_);
                                                        
                                                            /**
                                                             *  @dev    The address of the account that is allowed to update the vesting schedule.
                                                             *  @return manager_ The address of the pool manager.
                                                             */
                                                            function manager() external view returns (address manager_);
                                                        
                                                            /**************************************************************************************************************************************/
                                                            /*** LP Functions                                                                                                                   ***/
                                                            /**************************************************************************************************************************************/
                                                        
                                                            /**
                                                             *  @dev    Does a ERC4626 `deposit` with a ERC-2612 `permit`.
                                                             *  @param  assets_   The amount of `asset` to deposit.
                                                             *  @param  receiver_ The receiver of the shares.
                                                             *  @param  deadline_ The timestamp after which the `permit` signature is no longer valid.
                                                             *  @param  v_        ECDSA signature v component.
                                                             *  @param  r_        ECDSA signature r component.
                                                             *  @param  s_        ECDSA signature s component.
                                                             *  @return shares_   The amount of shares minted.
                                                             */
                                                            function depositWithPermit(uint256 assets_, address receiver_, uint256 deadline_, uint8 v_, bytes32 r_, bytes32 s_)
                                                                external returns (uint256 shares_);
                                                        
                                                            /**
                                                             *  @dev    Does a ERC4626 `mint` with a ERC-2612 `permit`.
                                                             *  @param  shares_    The amount of `shares` to mint.
                                                             *  @param  receiver_  The receiver of the shares.
                                                             *  @param  maxAssets_ The maximum amount of assets that can be taken, as per the permit.
                                                             *  @param  deadline_  The timestamp after which the `permit` signature is no longer valid.
                                                             *  @param  v_         ECDSA signature v component.
                                                             *  @param  r_         ECDSA signature r component.
                                                             *  @param  s_         ECDSA signature s component.
                                                             *  @return assets_    The amount of shares deposited.
                                                             */
                                                            function mintWithPermit(uint256 shares_, address receiver_, uint256 maxAssets_, uint256 deadline_, uint8 v_, bytes32 r_, bytes32 s_)
                                                                external returns (uint256 assets_);
                                                        
                                                            /**************************************************************************************************************************************/
                                                            /*** Withdrawal Request Functions                                                                                                   ***/
                                                            /**************************************************************************************************************************************/
                                                        
                                                            /**
                                                             *  @dev    Removes shares from the withdrawal mechanism, can only be called after the beginning of the withdrawal window has passed.
                                                             *  @param  shares_         The amount of shares to redeem.
                                                             *  @param  owner_          The owner of the shares.
                                                             *  @return sharesReturned_ The amount of shares withdrawn.
                                                             */
                                                            function removeShares(uint256 shares_, address owner_) external returns (uint256 sharesReturned_);
                                                        
                                                            /**
                                                             *  @dev    Requests a redemption of shares from the pool.
                                                             *  @param  shares_       The amount of shares to redeem.
                                                             *  @param  owner_        The owner of the shares.
                                                             *  @return escrowShares_ The amount of shares sent to escrow.
                                                             */
                                                            function requestRedeem(uint256 shares_, address owner_) external returns (uint256 escrowShares_);
                                                        
                                                            /**
                                                             *  @dev    Requests a withdrawal of assets from the pool.
                                                             *  @param  assets_       The amount of assets to withdraw.
                                                             *  @param  owner_        The owner of the shares.
                                                             *  @return escrowShares_ The amount of shares sent to escrow.
                                                             */
                                                            function requestWithdraw(uint256 assets_, address owner_) external returns (uint256 escrowShares_);
                                                        
                                                            /**************************************************************************************************************************************/
                                                            /*** View Functions                                                                                                                 ***/
                                                            /**************************************************************************************************************************************/
                                                        
                                                            /**
                                                             *  @dev    Returns the amount of underlying assets owned by the specified account.
                                                             *  @param  account_ Address of the account.
                                                             *  @return assets_  Amount of assets owned.
                                                             */
                                                            function balanceOfAssets(address account_) external view returns (uint256 assets_);
                                                        
                                                            /**
                                                             *  @dev    Returns the amount of exit assets for the input amount.
                                                             *  @param  shares_ The amount of shares to convert to assets.
                                                             *  @return assets_ Amount of assets able to be exited.
                                                             */
                                                            function convertToExitAssets(uint256 shares_) external view returns (uint256 assets_);
                                                        
                                                            /**
                                                             *  @dev    Returns the amount of exit shares for the input amount.
                                                             *  @param  assets_ The amount of assets to convert to shares.
                                                             *  @return shares_ Amount of shares able to be exited.
                                                             */
                                                            function convertToExitShares(uint256 assets_) external view returns (uint256 shares_);
                                                        
                                                            /**
                                                             *  @dev    Returns the amount unrealized losses.
                                                             *  @return unrealizedLosses_ Amount of unrealized losses.
                                                             */
                                                            function unrealizedLosses() external view returns (uint256 unrealizedLosses_);
                                                        
                                                        }
                                                        
                                                        // contracts/MaplePool.sol
                                                        
                                                        /*
                                                        
                                                            ███╗   ███╗ █████╗ ██████╗ ██╗     ███████╗    ██████╗  ██████╗  ██████╗ ██╗
                                                            ████╗ ████║██╔══██╗██╔══██╗██║     ██╔════╝    ██╔══██╗██╔═══██╗██╔═══██╗██║
                                                            ██╔████╔██║███████║██████╔╝██║     █████╗      ██████╔╝██║   ██║██║   ██║██║
                                                            ██║╚██╔╝██║██╔══██║██╔═══╝ ██║     ██╔══╝      ██╔═══╝ ██║   ██║██║   ██║██║
                                                            ██║ ╚═╝ ██║██║  ██║██║     ███████╗███████╗    ██║     ╚██████╔╝╚██████╔╝███████╗
                                                            ╚═╝     ╚═╝╚═╝  ╚═╝╚═╝     ╚══════╝╚══════╝    ╚═╝      ╚═════╝  ╚═════╝ ╚══════╝
                                                        
                                                        */
                                                        
                                                        contract MaplePool is IMaplePool, ERC20 {
                                                        
                                                            uint256 public immutable override BOOTSTRAP_MINT;
                                                        
                                                            address public override asset;    // Underlying ERC-20 asset handled by the ERC-4626 contract.
                                                            address public override manager;  // Address of the contract that manages administrative functionality.
                                                        
                                                            uint256 private _locked = 1;  // Used when checking for reentrancy.
                                                        
                                                            constructor(
                                                                address manager_,
                                                                address asset_,
                                                                address destination_,
                                                                uint256 bootstrapMint_,
                                                                uint256 initialSupply_,
                                                                string memory name_,
                                                                string memory symbol_
                                                            )
                                                                ERC20(name_, symbol_, ERC20(asset_).decimals())
                                                            {
                                                                require((manager = manager_) != address(0), "P:C:ZERO_MANAGER");
                                                                require((asset   = asset_)   != address(0), "P:C:ZERO_ASSET");
                                                        
                                                                if (initialSupply_ != 0) {
                                                                    _mint(destination_, initialSupply_);
                                                                }
                                                        
                                                                BOOTSTRAP_MINT = bootstrapMint_;
                                                        
                                                                require(ERC20Helper.approve(asset_, manager_, type(uint256).max), "P:C:FAILED_APPROVE");
                                                            }
                                                        
                                                            /**************************************************************************************************************************************/
                                                            /*** Modifiers                                                                                                                      ***/
                                                            /**************************************************************************************************************************************/
                                                        
                                                            modifier checkCall(bytes32 functionId_) {
                                                                ( bool success_, string memory errorMessage_ ) = IPoolManagerLike(manager).canCall(functionId_, msg.sender, msg.data[4:]);
                                                        
                                                                require(success_, errorMessage_);
                                                        
                                                                _;
                                                            }
                                                        
                                                            modifier nonReentrant() {
                                                                require(_locked == 1, "P:LOCKED");
                                                        
                                                                _locked = 2;
                                                        
                                                                _;
                                                        
                                                                _locked = 1;
                                                            }
                                                        
                                                            /**************************************************************************************************************************************/
                                                            /*** LP Functions                                                                                                                   ***/
                                                            /**************************************************************************************************************************************/
                                                        
                                                            function deposit(uint256 assets_, address receiver_) external override nonReentrant checkCall("P:deposit") returns (uint256 shares_) {
                                                                _mint(shares_ = previewDeposit(assets_), assets_, receiver_, msg.sender);
                                                            }
                                                        
                                                            function depositWithPermit(
                                                                uint256 assets_,
                                                                address receiver_,
                                                                uint256 deadline_,
                                                                uint8   v_,
                                                                bytes32 r_,
                                                                bytes32 s_
                                                            )
                                                                external override nonReentrant checkCall("P:depositWithPermit") returns (uint256 shares_)
                                                            {
                                                                ERC20(asset).permit(msg.sender, address(this), assets_, deadline_, v_, r_, s_);
                                                                _mint(shares_ = previewDeposit(assets_), assets_, receiver_, msg.sender);
                                                            }
                                                        
                                                            function mint(uint256 shares_, address receiver_) external override nonReentrant checkCall("P:mint") returns (uint256 assets_) {
                                                                _mint(shares_, assets_ = previewMint(shares_), receiver_, msg.sender);
                                                            }
                                                        
                                                            function mintWithPermit(
                                                                uint256 shares_,
                                                                address receiver_,
                                                                uint256 maxAssets_,
                                                                uint256 deadline_,
                                                                uint8   v_,
                                                                bytes32 r_,
                                                                bytes32 s_
                                                            )
                                                                external override nonReentrant checkCall("P:mintWithPermit") returns (uint256 assets_)
                                                            {
                                                                require((assets_ = previewMint(shares_)) <= maxAssets_, "P:MWP:INSUFFICIENT_PERMIT");
                                                        
                                                                ERC20(asset).permit(msg.sender, address(this), maxAssets_, deadline_, v_, r_, s_);
                                                                _mint(shares_, assets_, receiver_, msg.sender);
                                                            }
                                                        
                                                            function redeem(uint256 shares_, address receiver_, address owner_)
                                                                external override nonReentrant checkCall("P:redeem") returns (uint256 assets_)
                                                            {
                                                                uint256 redeemableShares_;
                                                                ( redeemableShares_, assets_ ) = IPoolManagerLike(manager).processRedeem(shares_, owner_, msg.sender);
                                                                _burn(redeemableShares_, assets_, receiver_, owner_, msg.sender);
                                                            }
                                                        
                                                            function withdraw(uint256 assets_, address receiver_, address owner_)
                                                                external override nonReentrant checkCall("P:withdraw") returns (uint256 shares_)
                                                            {
                                                                ( shares_, assets_ ) = IPoolManagerLike(manager).processWithdraw(assets_, owner_, msg.sender);
                                                                _burn(shares_, assets_, receiver_, owner_, msg.sender);
                                                            }
                                                        
                                                            /**************************************************************************************************************************************/
                                                            /*** ERC-20 Overridden Functions                                                                                                    ***/
                                                            /**************************************************************************************************************************************/
                                                        
                                                            function transfer(
                                                                address recipient_,
                                                                uint256 amount_
                                                            )
                                                                public override(IERC20, ERC20) checkCall("P:transfer") returns (bool success_)
                                                            {
                                                                success_ = super.transfer(recipient_, amount_);
                                                            }
                                                        
                                                            function transferFrom(
                                                                address owner_,
                                                                address recipient_,
                                                                uint256 amount_
                                                            )
                                                                public override(IERC20, ERC20) checkCall("P:transferFrom") returns (bool success_)
                                                            {
                                                                success_ = super.transferFrom(owner_, recipient_, amount_);
                                                            }
                                                        
                                                            /**************************************************************************************************************************************/
                                                            /*** Withdrawal Request Functions                                                                                                   ***/
                                                            /**************************************************************************************************************************************/
                                                        
                                                            function removeShares(uint256 shares_, address owner_)
                                                                external override nonReentrant checkCall("P:removeShares") returns (uint256 sharesReturned_)
                                                            {
                                                                if (msg.sender != owner_) _decreaseAllowance(owner_, msg.sender, shares_);
                                                        
                                                                emit SharesRemoved(
                                                                    owner_,
                                                                    sharesReturned_ = IPoolManagerLike(manager).removeShares(shares_, owner_)
                                                                );
                                                            }
                                                        
                                                            function requestRedeem(uint256 shares_, address owner_)
                                                                external override nonReentrant checkCall("P:requestRedeem") returns (uint256 escrowedShares_)
                                                            {
                                                                emit RedemptionRequested(
                                                                    owner_,
                                                                    shares_,
                                                                    escrowedShares_ = _requestRedeem(shares_, owner_)
                                                                );
                                                            }
                                                        
                                                            function requestWithdraw(uint256 assets_, address owner_)
                                                                external override nonReentrant checkCall("P:requestWithdraw") returns (uint256 escrowedShares_)
                                                            {
                                                                emit WithdrawRequested(
                                                                    owner_,
                                                                    assets_,
                                                                    escrowedShares_ = _requestWithdraw(assets_, owner_)
                                                                );
                                                            }
                                                        
                                                            /**************************************************************************************************************************************/
                                                            /*** Internal Functions                                                                                                             ***/
                                                            /**************************************************************************************************************************************/
                                                        
                                                            function _burn(uint256 shares_, uint256 assets_, address receiver_, address owner_, address caller_) internal {
                                                                require(receiver_ != address(0), "P:B:ZERO_RECEIVER");
                                                        
                                                                if (shares_ == 0) return;
                                                        
                                                                if (caller_ != owner_) {
                                                                    _decreaseAllowance(owner_, caller_, shares_);
                                                                }
                                                        
                                                                _burn(owner_, shares_);
                                                        
                                                                emit Withdraw(caller_, receiver_, owner_, assets_, shares_);
                                                        
                                                                require(ERC20Helper.transfer(asset, receiver_, assets_), "P:B:TRANSFER");
                                                            }
                                                        
                                                            function _divRoundUp(uint256 numerator_, uint256 divisor_) internal pure returns (uint256 result_) {
                                                                result_ = (numerator_ + divisor_ - 1) / divisor_;
                                                            }
                                                        
                                                            function _mint(uint256 shares_, uint256 assets_, address receiver_, address caller_) internal {
                                                                require(receiver_ != address(0), "P:M:ZERO_RECEIVER");
                                                                require(shares_   != uint256(0), "P:M:ZERO_SHARES");
                                                                require(assets_   != uint256(0), "P:M:ZERO_ASSETS");
                                                        
                                                                if (totalSupply == 0 && BOOTSTRAP_MINT != 0) {
                                                                    _mint(address(0), BOOTSTRAP_MINT);
                                                        
                                                                    emit BootstrapMintPerformed(caller_, receiver_, assets_, shares_, BOOTSTRAP_MINT);
                                                        
                                                                    shares_ -= BOOTSTRAP_MINT;
                                                                }
                                                        
                                                                _mint(receiver_, shares_);
                                                        
                                                                emit Deposit(caller_, receiver_, assets_, shares_);
                                                        
                                                                require(ERC20Helper.transferFrom(asset, caller_, address(this), assets_), "P:M:TRANSFER_FROM");
                                                            }
                                                        
                                                            function _requestRedeem(uint256 shares_, address owner_) internal returns (uint256 escrowShares_) {
                                                                address destination_;
                                                        
                                                                ( escrowShares_, destination_ ) = IPoolManagerLike(manager).getEscrowParams(owner_, shares_);
                                                        
                                                                if (msg.sender != owner_) {
                                                                    _decreaseAllowance(owner_, msg.sender, escrowShares_);
                                                                }
                                                        
                                                                if (escrowShares_ != 0 && destination_ != address(0)) {
                                                                    _transfer(owner_, destination_, escrowShares_);
                                                                }
                                                        
                                                                IPoolManagerLike(manager).requestRedeem(escrowShares_, owner_, msg.sender);
                                                            }
                                                        
                                                            function _requestWithdraw(uint256 assets_, address owner_) internal returns (uint256 escrowShares_) {
                                                                address destination_;
                                                        
                                                                ( escrowShares_, destination_ ) = IPoolManagerLike(manager).getEscrowParams(owner_, convertToExitShares(assets_));
                                                        
                                                                if (msg.sender != owner_) {
                                                                    _decreaseAllowance(owner_, msg.sender, escrowShares_);
                                                                }
                                                        
                                                                if (escrowShares_ != 0 && destination_ != address(0)) {
                                                                    _transfer(owner_, destination_, escrowShares_);
                                                                }
                                                        
                                                                IPoolManagerLike(manager).requestWithdraw(escrowShares_, assets_, owner_, msg.sender);
                                                            }
                                                        
                                                            /**************************************************************************************************************************************/
                                                            /*** External View Functions                                                                                                        ***/
                                                            /**************************************************************************************************************************************/
                                                        
                                                            function balanceOfAssets(address account_) external view override returns (uint256 balanceOfAssets_) {
                                                                balanceOfAssets_ = convertToAssets(balanceOf[account_]);
                                                            }
                                                        
                                                            function maxDeposit(address receiver_) external view override returns (uint256 maxAssets_) {
                                                                maxAssets_ = IPoolManagerLike(manager).maxDeposit(receiver_);
                                                            }
                                                        
                                                            function maxMint(address receiver_) external view override returns (uint256 maxShares_) {
                                                                maxShares_ = IPoolManagerLike(manager).maxMint(receiver_);
                                                            }
                                                        
                                                            function maxRedeem(address owner_) external view override returns (uint256 maxShares_) {
                                                                maxShares_ = IPoolManagerLike(manager).maxRedeem(owner_);
                                                            }
                                                        
                                                            function maxWithdraw(address owner_) external view override returns (uint256 maxAssets_) {
                                                                maxAssets_ = IPoolManagerLike(manager).maxWithdraw(owner_);
                                                            }
                                                        
                                                            function previewRedeem(uint256 shares_) external view override returns (uint256 assets_) {
                                                                assets_ = IPoolManagerLike(manager).previewRedeem(msg.sender, shares_);
                                                            }
                                                        
                                                            function previewWithdraw(uint256 assets_) external view override returns (uint256 shares_) {
                                                                shares_ = IPoolManagerLike(manager).previewWithdraw(msg.sender, assets_);
                                                            }
                                                        
                                                            /**************************************************************************************************************************************/
                                                            /*** Public View Functions                                                                                                          ***/
                                                            /**************************************************************************************************************************************/
                                                        
                                                            function convertToAssets(uint256 shares_) public view override returns (uint256 assets_) {
                                                                uint256 totalSupply_ = totalSupply;
                                                        
                                                                assets_ = totalSupply_ == 0 ? shares_ : (shares_ * totalAssets()) / totalSupply_;
                                                            }
                                                        
                                                            function convertToExitAssets(uint256 shares_) public view override returns (uint256 assets_) {
                                                                uint256 totalSupply_ = totalSupply;
                                                        
                                                                assets_ = totalSupply_ == 0 ? shares_ : shares_ * (totalAssets() - unrealizedLosses()) / totalSupply_;
                                                            }
                                                        
                                                            function convertToShares(uint256 assets_) public view override returns (uint256 shares_) {
                                                                uint256 totalSupply_ = totalSupply;
                                                        
                                                                shares_ = totalSupply_ == 0 ? assets_ : (assets_ * totalSupply_) / totalAssets();
                                                            }
                                                        
                                                            function convertToExitShares(uint256 amount_) public view override returns (uint256 shares_) {
                                                                shares_ = _divRoundUp(amount_ * totalSupply, totalAssets() - unrealizedLosses());
                                                            }
                                                        
                                                            function previewDeposit(uint256 assets_) public view override returns (uint256 shares_) {
                                                                // As per https://eips.ethereum.org/EIPS/eip-4626#security-considerations,
                                                                // it should round DOWN if it’s calculating the amount of shares to issue to a user, given an amount of assets provided.
                                                                shares_ = convertToShares(assets_);
                                                            }
                                                        
                                                            function previewMint(uint256 shares_) public view override returns (uint256 assets_) {
                                                                uint256 totalSupply_ = totalSupply;
                                                        
                                                                // As per https://eips.ethereum.org/EIPS/eip-4626#security-considerations,
                                                                // it should round UP if it’s calculating the amount of assets a user must provide, to be issued a given amount of shares.
                                                                assets_ = totalSupply_ == 0 ? shares_ : _divRoundUp(shares_ * totalAssets(), totalSupply_);
                                                            }
                                                        
                                                            function totalAssets() public view override returns (uint256 totalAssets_) {
                                                                totalAssets_ = IPoolManagerLike(manager).totalAssets();
                                                            }
                                                        
                                                            function unrealizedLosses() public view override returns (uint256 unrealizedLosses_) {
                                                                unrealizedLosses_ = IPoolManagerLike(manager).unrealizedLosses();
                                                            }
                                                        
                                                        }

                                                        File 6 of 13: MapleAaveStrategy
                                                        // SPDX-License-Identifier: BUSL-1.1
                                                        pragma solidity ^0.8.25;
                                                        import { StrategyState }      from "./interfaces/IMapleStrategy.sol";
                                                        import { IMapleAaveStrategy } from "./interfaces/aaveStrategy/IMapleAaveStrategy.sol";
                                                        import {
                                                            IAavePoolLike,
                                                            IAaveTokenLike,
                                                            IAaveRewardsControllerLike,
                                                            IGlobalsLike,
                                                            IMapleProxyFactoryLike,
                                                            IPoolManagerLike
                                                        } from "./interfaces/Interfaces.sol";
                                                        import { MapleAaveStrategyStorage } from "./proxy/aaveStrategy/MapleAaveStrategyStorage.sol";
                                                        import { MapleAbstractStrategy } from "./MapleAbstractStrategy.sol";
                                                        /*
                                                        ███╗   ███╗ █████╗ ██████╗ ██╗     ███████╗
                                                        ████╗ ████║██╔══██╗██╔══██╗██║     ██╔════╝
                                                        ██╔████╔██║███████║██████╔╝██║     █████╗
                                                        ██║╚██╔╝██║██╔══██║██╔═══╝ ██║     ██╔══╝
                                                        ██║ ╚═╝ ██║██║  ██║██║     ███████╗███████╗
                                                        ╚═╝     ╚═╝╚═╝  ╚═╝╚═╝     ╚══════╝╚══════╝
                                                         █████╗  █████╗ ██╗   ██╗███████╗
                                                        ██╔══██╗██╔══██╗██║   ██║██╔════╝
                                                        ███████║███████║██║   ██║█████╗
                                                        ██╔══██║██╔══██║╚██╗ ██╔╝██╔══╝
                                                        ██║  ██║██║  ██║ ╚████╔╝ ███████╗
                                                        ╚═╝  ╚═╝╚═╝  ╚═╝  ╚═══╝  ╚══════╝
                                                        ███████╗████████╗██████╗  █████╗ ████████╗███████╗ ██████╗██╗   ██╗
                                                        ██╔════╝╚══██╔══╝██╔══██╗██╔══██╗╚══██╔══╝██╔════╝██╔════╝╚██╗ ██╔╝
                                                        ███████╗   ██║   ██████╔╝███████║   ██║   █████╗  ██║  ███╗╚████╔╝
                                                        ╚════██║   ██║   ██╔══██╗██╔══██║   ██║   ██╔══╝  ██║   ██║ ╚██╔╝
                                                        ███████║   ██║   ██║  ██║██║  ██║   ██║   ███████╗╚██████╔╝  ██║
                                                        ╚══════╝   ╚═╝   ╚═╝  ╚═╝╚═╝  ╚═╝   ╚═╝   ╚══════╝ ╚═════╝   ╚═╝
                                                        */
                                                        contract MapleAaveStrategy is IMapleAaveStrategy, MapleAbstractStrategy, MapleAaveStrategyStorage {
                                                            string public constant override STRATEGY_TYPE = "AAVE";
                                                            uint256 public constant HUNDRED_PERCENT = 1e6;
                                                            /**************************************************************************************************************************************/
                                                            /*** Strategy Manager Functions                                                                                                     ***/
                                                            /**************************************************************************************************************************************/
                                                            function fundStrategy(uint256 assetsIn_) external override nonReentrant whenProtocolNotPaused onlyStrategyManager onlyActive {
                                                                address aavePool_   = aavePool;
                                                                address aaveToken_  = aaveToken;
                                                                address fundsAsset_ = fundsAsset;
                                                                require(IGlobalsLike(globals()).isInstanceOf("STRATEGY_VAULT", aaveToken_), "MAS:FS:INVALID_AAVE_TOKEN");
                                                                _accrueFees(aavePool_, aaveToken_, fundsAsset_);
                                                                IPoolManagerLike(poolManager).requestFunds(address(this), assetsIn_);
                                                                IAavePoolLike(aavePool_).supply(fundsAsset_, assetsIn_, address(this), 0);
                                                                lastRecordedTotalAssets = _currentTotalAssets(aaveToken_);
                                                                emit StrategyFunded(assetsIn_);
                                                            }
                                                            function withdrawFromStrategy(uint256 assetsOut_) external override nonReentrant whenProtocolNotPaused onlyStrategyManager {
                                                                require(assetsOut_ > 0, "MAS:WFS:ZERO_ASSETS");
                                                                address aavePool_   = aavePool;
                                                                address aaveToken_  = aaveToken;
                                                                address fundsAsset_ = fundsAsset;
                                                                bool isStrategyActive_ = _strategyState() == StrategyState.Active;
                                                                // Strategy only accrues fees when it is active.
                                                                if (isStrategyActive_) {
                                                                    require(assetsOut_ <= assetsUnderManagement(), "MAS:WFS:LOW_ASSETS");
                                                                    _accrueFees(aavePool_, aaveToken_, fundsAsset_);
                                                                }
                                                                IAavePoolLike(aavePool_).withdraw(fundsAsset_, assetsOut_, pool);
                                                                if (isStrategyActive_) {
                                                                    lastRecordedTotalAssets = _currentTotalAssets(aaveToken_);
                                                                }
                                                                emit StrategyWithdrawal(assetsOut_);
                                                            }
                                                            /**************************************************************************************************************************************/
                                                            /*** Strategy Admin Functions                                                                                                       ***/
                                                            /**************************************************************************************************************************************/
                                                            function claimRewards(address[] calldata assets_, uint256 amount_, address rewardToken_)
                                                                external override nonReentrant whenProtocolNotPaused onlyProtocolAdmins
                                                            {
                                                                address rewardsController_ = IAaveTokenLike(aaveToken).getIncentivesController();
                                                                uint256 rewardAmount_ = IAaveRewardsControllerLike(rewardsController_).claimRewards(assets_, amount_, treasury(), rewardToken_);
                                                                emit RewardsClaimed(rewardToken_, rewardAmount_);
                                                            }
                                                            function deactivateStrategy() external override nonReentrant whenProtocolNotPaused onlyProtocolAdmins {
                                                                require(_strategyState() != StrategyState.Inactive, "MAS:DS:ALREADY_INACTIVE");
                                                                strategyState = StrategyState.Inactive;
                                                                emit StrategyDeactivated();
                                                            }
                                                            function impairStrategy() external override nonReentrant whenProtocolNotPaused onlyProtocolAdmins {
                                                                require(_strategyState() != StrategyState.Impaired, "MAS:IS:ALREADY_IMPAIRED");
                                                                strategyState = StrategyState.Impaired;
                                                                emit StrategyImpaired();
                                                            }
                                                            function reactivateStrategy(bool updateAccounting_) external override nonReentrant whenProtocolNotPaused onlyProtocolAdmins {
                                                                require(_strategyState() != StrategyState.Active, "MAS:RS:ALREADY_ACTIVE");
                                                                // Updating the fee accounting will result in no fees being charged for the period of impairment and/or inactivity.
                                                                // Otherwise, fees will be charged retroactively as if no impairment and/or deactivation occurred.
                                                                if (updateAccounting_) {
                                                                    lastRecordedTotalAssets = _currentTotalAssets(aaveToken);
                                                                }
                                                                strategyState = StrategyState.Active;
                                                                emit StrategyReactivated(updateAccounting_);
                                                            }
                                                            function setStrategyFeeRate(uint256 strategyFeeRate_)
                                                                external override nonReentrant whenProtocolNotPaused onlyProtocolAdmins onlyActive
                                                            {
                                                                require(strategyFeeRate_ <= HUNDRED_PERCENT, "MAS:SSFR:INVALID_FEE_RATE");
                                                                address aaveToken_ = aaveToken;
                                                                _accrueFees(aavePool, aaveToken_, fundsAsset);
                                                                lastRecordedTotalAssets = _currentTotalAssets(aaveToken_);
                                                                strategyFeeRate         = strategyFeeRate_;
                                                                emit StrategyFeeRateSet(strategyFeeRate_);
                                                            }
                                                            /**************************************************************************************************************************************/
                                                            /*** Strategy View Functions                                                                                                        ***/
                                                            /**************************************************************************************************************************************/
                                                            function assetsUnderManagement() public view override returns (uint256 assetsUnderManagement_) {
                                                                // All assets are marked as zero if the strategy is inactive.
                                                                if (_strategyState() == StrategyState.Inactive) {
                                                                    return 0;
                                                                }
                                                                uint256 currentTotalAssets_ = _currentTotalAssets(aaveToken);
                                                                assetsUnderManagement_ = currentTotalAssets_ - _currentAccruedFees(currentTotalAssets_);
                                                            }
                                                            function unrealizedLosses() external view override returns (uint256 unrealizedLosses_) {
                                                                if (_strategyState() == StrategyState.Impaired) {
                                                                    unrealizedLosses_ = assetsUnderManagement();
                                                                }
                                                            }
                                                            /**************************************************************************************************************************************/
                                                            /*** Internal Helpers                                                                                                               ***/
                                                            /**************************************************************************************************************************************/
                                                            function _accrueFees(address aavePool_, address aaveToken_, address fundsAsset_) internal {
                                                                uint256 currentTotalAssets_ = _currentTotalAssets(aaveToken_);
                                                                uint256 strategyFee_        = _currentAccruedFees(currentTotalAssets_);
                                                                // Withdraw the fees from the strategy vault.
                                                                if (strategyFee_ > 0) {
                                                                    IAavePoolLike(aavePool_).withdraw(fundsAsset_, strategyFee_, treasury());
                                                                    emit StrategyFeesCollected(strategyFee_);
                                                                }
                                                            }
                                                            function _setLock(uint256 lock_) internal override {
                                                                locked = lock_;
                                                            }
                                                            /**************************************************************************************************************************************/
                                                            /*** Internal View Functions                                                                                                        ***/
                                                            /**************************************************************************************************************************************/
                                                            function _currentAccruedFees(uint256 currentTotalAssets_) internal view returns (uint256 currentAccruedFees_) {
                                                                uint256 lastRecordedTotalAssets_ = lastRecordedTotalAssets;
                                                                uint256 strategyFeeRate_         = strategyFeeRate;
                                                                // No fees to accrue if TotalAssets has decreased or fee rate is zero.
                                                                if (currentTotalAssets_ <= lastRecordedTotalAssets_ || strategyFeeRate_ == 0) {
                                                                    return 0;
                                                                }
                                                                // Can't underflow due to check above.
                                                                uint256 yieldAccrued_ = currentTotalAssets_ - lastRecordedTotalAssets_;
                                                                // It is acknowledged that `currentAccruedFees_` may be rounded down to 0 if `yieldAccrued_ * strategyFeeRate_ < HUNDRED_PERCENT`.
                                                                currentAccruedFees_ = yieldAccrued_ * strategyFeeRate_ / HUNDRED_PERCENT;
                                                            }
                                                            function _currentTotalAssets(address aaveToken_) internal view returns (uint256 currentTotalAssets_) {
                                                                currentTotalAssets_ = IAaveTokenLike(aaveToken_).balanceOf(address(this));
                                                            }
                                                            function _locked() internal view override returns (uint256) {
                                                                return locked;
                                                            }
                                                            function _strategyState() internal view override returns (StrategyState) {
                                                                return strategyState;
                                                            }
                                                            /**************************************************************************************************************************************/
                                                            /*** View Functions                                                                                                                 ***/
                                                            /**************************************************************************************************************************************/
                                                            function factory() external view override returns (address factory_) {
                                                                factory_ = _factory();
                                                            }
                                                            function globals() public view override returns (address globals_) {
                                                                globals_ = IMapleProxyFactoryLike(_factory()).mapleGlobals();
                                                            }
                                                            function governor() public view override returns (address governor_) {
                                                                governor_ = IGlobalsLike(globals()).governor();
                                                            }
                                                            function implementation() external view override returns (address implementation_) {
                                                                implementation_ = _implementation();
                                                            }
                                                            function poolDelegate() public view override returns (address poolDelegate_) {
                                                                poolDelegate_ = IPoolManagerLike(poolManager).poolDelegate();
                                                            }
                                                            function securityAdmin() public view override returns (address securityAdmin_) {
                                                                securityAdmin_ = IGlobalsLike(globals()).securityAdmin();
                                                            }
                                                            function treasury() public view override returns (address treasury_) {
                                                                treasury_ = IGlobalsLike(globals()).mapleTreasury();
                                                            }
                                                        }
                                                        // SPDX-License-Identifier: BUSL-1.1
                                                        pragma solidity ^0.8.0;
                                                        /**
                                                         *  @dev Represents the current state of a Maple strategy.
                                                         *       Can be active, impaired, or inactive.
                                                         */
                                                        enum StrategyState {
                                                            Active,
                                                            Impaired,
                                                            Inactive
                                                        }
                                                        interface IMapleStrategy {
                                                            /**************************************************************************************************************************************/
                                                            /*** Events                                                                                                                         ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev Emitted when the strategy is deactivated.
                                                             */
                                                            event StrategyDeactivated();
                                                            /**
                                                             *  @dev   Emitted when fees on the strategy's yield are collected.
                                                             *  @param fees Amount of assets collected by the treasury.
                                                             */
                                                            event StrategyFeesCollected(uint256 fees);
                                                            /**
                                                             *  @dev   Emitted when the fee rate on the strategy's yield is updated.
                                                             *  @param feeRate Percentage of yield that accrues to the treasury.
                                                             */
                                                            event StrategyFeeRateSet(uint256 feeRate);
                                                            /**
                                                             *  @dev   Emitted when assets are deposited into the strategy.
                                                             *  @param assets Amount of assets deposited.
                                                             */
                                                            event StrategyFunded(uint256 assets);
                                                            /**
                                                             *  @dev   Emitted when assets are deposited into the strategy.
                                                             *  @param assets Amount of assets deposited.
                                                             *  @param shares Amount of shares minted.
                                                             */
                                                            event StrategyFunded(uint256 assets, uint256 shares);
                                                            /**
                                                             *  @dev Emitted when the strategy is impaired.
                                                             */
                                                            event StrategyImpaired();
                                                            /**
                                                             *  @dev   Emitted when the strategy is reactivated.
                                                             *  @param updateAccounting Flag that defines if lastRecordedTotalAssets should be refreshed.
                                                             */
                                                            event StrategyReactivated(bool updateAccounting);
                                                            /**
                                                             *  @dev   Emitted when assets are withdrawn from the strategy.
                                                             *  @param assets Amount of assets withdrawn.
                                                             */
                                                            event StrategyWithdrawal(uint256 assets);
                                                            /**
                                                             *  @dev   Emitted when assets are withdrawn from the strategy.
                                                             *  @param assets Amount of assets withdrawn.
                                                             *  @param shares Amount of shares burned.
                                                             */
                                                            event StrategyWithdrawal(uint256 assets, uint256 shares);
                                                            /**************************************************************************************************************************************/
                                                            /*** Strategy Admin Functions                                                                                                       ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev Disables funding and marks all assets under management as zero.
                                                             */
                                                            function deactivateStrategy() external;
                                                            /**
                                                             *  @dev Disables funding and marks all assets under management as unrealized losses.
                                                             */
                                                            function impairStrategy() external;
                                                            /**
                                                             *  @dev   Resumes normal operation of the strategy.
                                                             *  @param updateAccounting Flag that defines if fee accounting should be refreshed.
                                                             */
                                                            function reactivateStrategy(bool updateAccounting) external;
                                                            /**
                                                             *  @dev    Sets a new fee rate for the strategy.
                                                             *          Can only be called when the strategy is active.
                                                             *  @param  feeRate Percentage of yield that accrues to the Maple treasury.
                                                             */
                                                            function setStrategyFeeRate(uint256 feeRate) external;
                                                            /**************************************************************************************************************************************/
                                                            /*** Strategy View Functions                                                                                                        ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev    Returns the current amount of assets managed by the strategy.
                                                             *  @return assetsUnderManagement Amount of assets managed by the strategy.
                                                             */
                                                            function assetsUnderManagement() external view returns (uint256 assetsUnderManagement);
                                                            /**
                                                             *  @dev    Returns the type of the strategy.
                                                             *  @return strategyType Type of the strategy.
                                                             */
                                                            function STRATEGY_TYPE() external view returns (string memory strategyType);
                                                            /**
                                                             *  @dev    Returns the current amount of unrealized losses.
                                                             *  @return unrealizedLosses Amount of assets marked as unrealized losses.
                                                             */
                                                            function unrealizedLosses() external view returns (uint256 unrealizedLosses);
                                                        }
                                                        // SPDX-License-Identifier: BUSL-1.1
                                                        pragma solidity ^0.8.0;
                                                        import { IMapleStrategy } from "../IMapleStrategy.sol";
                                                        import { IMapleAaveStrategyStorage } from "./IMapleAaveStrategyStorage.sol";
                                                        interface IMapleAaveStrategy is IMapleStrategy, IMapleAaveStrategyStorage {
                                                            /**************************************************************************************************************************************/
                                                            /*** Events                                                                                                                         ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev   Emitted when rewards are claimed from the Aave Rewards Controller.
                                                             *  @param rewardToken The address of the reward token.
                                                             *  @param amount      The amount of rewardToken claimed.
                                                             */
                                                            event RewardsClaimed(address indexed rewardToken, uint256 amount);
                                                            /**************************************************************************************************************************************/
                                                            /*** Strategy Manager Functions                                                                                                     ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev   Deploys assets from the Maple pool into the strategy.
                                                             *         Funding can only be attempted when the strategy is active.
                                                             *  @param assetsIn Amount of assets to deploy.
                                                             */
                                                            function fundStrategy(uint256 assetsIn) external;
                                                            /**
                                                             *  @dev   Withdraw assets from the strategy back into the Maple pool.
                                                             *         Withdrawals can be attempted even if the strategy is impaired or inactive.
                                                             *  @param assetsOut Amount of assets to withdraw.
                                                             */
                                                            function withdrawFromStrategy(uint256 assetsOut) external;
                                                            /**************************************************************************************************************************************/
                                                            /*** Strategy Admin Functions                                                                                                       ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev   Claims rewards from the Aave Incentives Controller.
                                                             *  @param assets      The list of assets to check eligible distributions before claiming rewards. Pass a/s/vToken addresses
                                                             *  @param amount      The amount of rewards to claim, expressed in wei. Pass MAX_UINT to claim the entire unclaimed reward balance
                                                             *  @param rewardToken The address of the reward token (e.g., stkAAVE)
                                                             */
                                                            function claimRewards(address[] calldata assets, uint256 amount, address rewardToken) external;
                                                        }
                                                        // SPDX-License-Identifier: BUSL-1.1
                                                        pragma solidity ^0.8.0;
                                                        interface IAavePoolLike {
                                                            function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external;
                                                            function withdraw(address asset, uint256 amount, address to) external returns (uint256);
                                                        }
                                                        interface IAaveRewardsControllerLike {
                                                            function claimRewards(
                                                                address[] calldata assets,
                                                                uint256 amount,
                                                                address to,
                                                                address rewardToken
                                                            ) external returns (uint256 rewardAmount);
                                                        }
                                                        interface IAaveTokenLike {
                                                            function balanceOf(address account_) external view returns (uint256 balance_);
                                                            function getIncentivesController() external view returns (address incentivesController);
                                                            function POOL() external view returns (address pool);
                                                            function UNDERLYING_ASSET_ADDRESS() external view returns (address asset);
                                                        }
                                                        interface IERC20Like {
                                                            function approve(address spender, uint256 amount) external returns (bool success);
                                                            function balanceOf(address account_) external view returns (uint256 balance_);
                                                            function transfer(address to, uint256 amount) external returns (bool);
                                                        }
                                                        interface IERC4626Like {
                                                            function asset() external view returns (address asset_);
                                                            function balanceOf(address account_) external view returns (uint256 balance_);
                                                            function convertToAssets(uint256 shares_) external view returns (uint256 assets_);
                                                            function convertToShares(uint256 assets_) external view returns (uint256 shares_);
                                                            function deposit(uint256 assets_, address receiver_) external returns (uint256 shares_);
                                                            function maxWithdraw(address owner_) external view returns (uint256 maxAssets_);
                                                            function previewRedeem(uint256 shares) external view returns (uint256 assets_);
                                                            function redeem(uint256 shares_, address receiver_, address owner_) external returns (uint256 assets_);
                                                            function withdraw(uint256 assets_, address receiver_, address owner_) external returns (uint256 shares_);
                                                        }
                                                        interface IGlobalsLike {
                                                            function canDeploy(address caller_) external view returns (bool canDeploy_);
                                                            function isFunctionPaused(bytes4 sig_) external view returns (bool isFunctionPaused_);
                                                            function governor() external view returns (address governor_);
                                                            function isInstanceOf(bytes32 instanceId, address instance_) external view returns (bool isInstance_);
                                                            function isValidScheduledCall(
                                                                address caller_,
                                                                address contract_,
                                                                bytes32 functionId_,
                                                                bytes calldata callData_
                                                            ) external view returns (bool isValid_);
                                                            function mapleTreasury() external view returns (address mapleTreasury_);
                                                            function operationalAdmin() external view returns (address operationalAdmin_);
                                                            function securityAdmin() external view returns (address securityAdmin_);
                                                            function unscheduleCall(address caller_, bytes32 functionId_, bytes calldata callData_) external;
                                                        }
                                                        interface IMapleProxyFactoryLike {
                                                            function isInstance(address instance_) external view returns (bool isInstance_);
                                                            function mapleGlobals() external view returns (address globals_);
                                                        }
                                                        interface IPoolLike {
                                                            function asset() external view returns (address asset_);
                                                            function manager() external view returns (address poolManager_);
                                                        }
                                                        interface IPoolManagerLike {
                                                            function factory() external view returns (address factory_);
                                                            function pool() external view returns (address pool_);
                                                            function poolDelegate() external view returns (address poolDelegate_);
                                                            function requestFunds(address destination_, uint256 principal_) external;
                                                        }
                                                        interface IPSMLike {
                                                            function buyGem(address usr, uint256 gemAmt) external returns (uint256 daiInWad);
                                                            function gem() external view returns (address gem_);
                                                            function sellGem(address usr, uint256 gemAmt) external returns (uint256 daiOutWad);
                                                            function tin() external view returns (uint256 tin); // Sell side fee
                                                            function tout() external view returns (uint256 tout); // Buy side fee
                                                            function to18ConversionFactor() external view returns (uint256 to18ConversionFactor);
                                                            function usds() external view returns (address usds_);
                                                        }
                                                        // SPDX-License-Identifier: BUSL-1.1
                                                        pragma solidity ^0.8.25;
                                                        import { StrategyState }             from "../../interfaces/IMapleStrategy.sol";
                                                        import { IMapleAaveStrategyStorage } from "../../interfaces/aaveStrategy/IMapleAaveStrategyStorage.sol";
                                                        contract MapleAaveStrategyStorage is IMapleAaveStrategyStorage {
                                                            /**************************************************************************************************************************************/
                                                            /*** State Variables                                                                                                                ***/
                                                            /**************************************************************************************************************************************/
                                                            // Used for reentrancy checks.
                                                            uint256 public locked;
                                                            address public override fundsAsset;
                                                            address public override pool;
                                                            address public override poolManager;
                                                            address public override aavePool;
                                                            address public override aaveToken;
                                                            uint256 public override lastRecordedTotalAssets;
                                                            uint256 public override strategyFeeRate;
                                                            StrategyState public override strategyState;
                                                        }
                                                        // SPDX-License-Identifier: BUSL-1.1
                                                        pragma solidity ^0.8.25;
                                                        import { IMapleProxyFactory }    from "../modules/maple-proxy-factory/contracts/interfaces/IMapleProxyFactory.sol";
                                                        import { IMapleProxied }         from "../modules/maple-proxy-factory/contracts/interfaces/IMapleProxied.sol";
                                                        import { MapleProxiedInternals } from "../modules/maple-proxy-factory/contracts/MapleProxiedInternals.sol";
                                                        import { IMapleStrategy, StrategyState } from "./interfaces/IMapleStrategy.sol";
                                                        import {
                                                            IERC20Like,
                                                            IGlobalsLike,
                                                            IPoolLike,
                                                            IPoolManagerLike
                                                        } from "./interfaces/Interfaces.sol";
                                                        /// @dev This is the base contract that all Maple strategies inherit from.
                                                        abstract contract MapleAbstractStrategy is IMapleStrategy, IMapleProxied, MapleProxiedInternals {
                                                            /**************************************************************************************************************************************/
                                                            /*** Modifiers                                                                                                                      ***/
                                                            /**************************************************************************************************************************************/
                                                            modifier onlyActive() {
                                                                require(_strategyState() == StrategyState.Active, "MS:NOT_ACTIVE");
                                                                _;
                                                            }
                                                            modifier nonReentrant() {
                                                                require(_locked() == 1, "MS:LOCKED");
                                                                _setLock(2);
                                                                _;
                                                                _setLock(1);
                                                            }
                                                            modifier whenProtocolNotPaused() {
                                                                require(!IGlobalsLike(globals()).isFunctionPaused(msg.sig), "MS:PAUSED");
                                                                _;
                                                            }
                                                            modifier onlyProtocolAdmins {
                                                                require(
                                                                    msg.sender == poolDelegate() ||
                                                                    msg.sender == governor() ||
                                                                    msg.sender == IGlobalsLike(globals()).operationalAdmin(),
                                                                    "MS:NOT_ADMIN"
                                                                );
                                                                _;
                                                            }
                                                            modifier onlyStrategyManager {
                                                                require(
                                                                    msg.sender == poolDelegate() ||
                                                                    IGlobalsLike(globals()).isInstanceOf("STRATEGY_MANAGER", msg.sender),
                                                                    "MS:NOT_MANAGER"
                                                                );
                                                                _;
                                                            }
                                                            /**************************************************************************************************************************************/
                                                            /*** Proxy Functions                                                                                                                ***/
                                                            /**************************************************************************************************************************************/
                                                            function migrate(address migrator_, bytes calldata arguments_) external whenProtocolNotPaused {
                                                                require(msg.sender == _factory(),        "MS:M:NOT_FACTORY");
                                                                require(_migrate(migrator_, arguments_), "MS:M:FAILED");
                                                            }
                                                            function setImplementation(address implementation_) external whenProtocolNotPaused {
                                                                require(msg.sender == _factory(), "MS:SI:NOT_FACTORY");
                                                                _setImplementation(implementation_);
                                                            }
                                                            function upgrade(uint256 version_, bytes calldata arguments_) external whenProtocolNotPaused {
                                                                address poolDelegate_ = poolDelegate();
                                                                require(msg.sender == poolDelegate_ || msg.sender == securityAdmin(), "MS:U:NOT_AUTHORIZED");
                                                                IGlobalsLike mapleGlobals_ = IGlobalsLike(globals());
                                                                if (msg.sender == poolDelegate_) {
                                                                    require(mapleGlobals_.isValidScheduledCall(msg.sender, address(this), "MS:UPGRADE", msg.data), "MS:U:INVALID_SCHED_CALL");
                                                                    mapleGlobals_.unscheduleCall(msg.sender, "MS:UPGRADE", msg.data);
                                                                }
                                                                IMapleProxyFactory(_factory()).upgradeInstance(version_, arguments_);
                                                            }
                                                            /**************************************************************************************************************************************/
                                                            /*** Virtual Functions                                                                                                              ***/
                                                            /**************************************************************************************************************************************/
                                                            function factory() external view virtual returns (address factory_);
                                                            function globals() public view virtual returns (address globals_);
                                                            function governor() public view virtual returns (address governor_);
                                                            function implementation() external view virtual returns (address implementation_);
                                                            function poolDelegate() public view virtual returns (address poolDelegate_);
                                                            function securityAdmin() public view virtual returns (address securityAdmin_);
                                                            function treasury() public view virtual returns (address treasury_);
                                                            /**************************************************************************************************************************************/
                                                            /*** Internal Functions                                                                                                             ***/
                                                            /**************************************************************************************************************************************/
                                                            function _setLock(uint256 lock_) internal virtual;
                                                            function _locked() internal view virtual returns (uint256);
                                                            function _strategyState() internal view virtual returns (StrategyState);
                                                        }
                                                        // SPDX-License-Identifier: BUSL-1.1
                                                        pragma solidity ^0.8.0;
                                                        import { StrategyState } from "../IMapleStrategy.sol";
                                                        interface IMapleAaveStrategyStorage {
                                                            /**
                                                             *  @dev    Returns the address of the Aave pool.
                                                             *  @return aavePool Address of the Aave pool.
                                                             */
                                                            function aavePool() external view returns (address aavePool);
                                                            /**
                                                             *  @dev    Returns the address of the Aave token.
                                                             *  @return aaveToken Address of the Aave token.
                                                             */
                                                            function aaveToken() external view returns (address aaveToken);
                                                            /**
                                                             *  @dev    Returns the address of the underlying asset.
                                                             *  @return fundsAsset Address of the underlying asset.
                                                             */
                                                            function fundsAsset() external view returns (address fundsAsset);
                                                            /**
                                                             *  @dev    Returns the last recorded value of all assets managed by the strategy.
                                                             *  @return lastRecordedTotalAssets Last recorded value of all assets managed by the strategy.
                                                             */
                                                            function lastRecordedTotalAssets() external view returns (uint256 lastRecordedTotalAssets);
                                                            /**
                                                             *  @dev    Returns the address of the underlying asset.
                                                             *  @return pool Address of the Maple pool.
                                                             */
                                                            function pool() external view returns (address pool);
                                                            /**
                                                             *  @dev    Returns the address of the Maple pool manager.
                                                             *  @return poolManager Address of the Maple pool manager.
                                                             */
                                                            function poolManager() external view returns (address poolManager);
                                                            /**
                                                            *  @dev    Returns the percentage of the strategy's yield collected by the Maple treasury.
                                                            *  @return strategyFeeRate Percentage of yield collected by the treasury.
                                                            */
                                                            function strategyFeeRate() external view returns (uint256 strategyFeeRate);
                                                            /**
                                                             *  @dev    Returns the current state of the strategy.
                                                             *          Can be active, inactive, or impaired.
                                                             *  @return strategyState Current state of the strategy.
                                                             */
                                                            function strategyState() external view returns (StrategyState strategyState);
                                                        }
                                                        // SPDX-License-Identifier: AGPL-3.0-or-later
                                                        pragma solidity ^0.8.7;
                                                        import { IDefaultImplementationBeacon } from "../../modules/proxy-factory/contracts/interfaces/IDefaultImplementationBeacon.sol";
                                                        /// @title A Maple factory for Proxy contracts that proxy MapleProxied implementations.
                                                        interface IMapleProxyFactory is IDefaultImplementationBeacon {
                                                            /**************************************************************************************************************************************/
                                                            /*** Events                                                                                                                         ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev   A default version was set.
                                                             *  @param version_ The default version.
                                                             */
                                                            event DefaultVersionSet(uint256 indexed version_);
                                                            /**
                                                             *  @dev   A version of an implementation, at some address, was registered, with an optional initializer.
                                                             *  @param version_               The version registered.
                                                             *  @param implementationAddress_ The address of the implementation.
                                                             *  @param initializer_           The address of the initializer, if any.
                                                             */
                                                            event ImplementationRegistered(uint256 indexed version_, address indexed implementationAddress_, address indexed initializer_);
                                                            /**
                                                             *  @dev   A proxy contract was deployed with some initialization arguments.
                                                             *  @param version_                 The version of the implementation being proxied by the deployed proxy contract.
                                                             *  @param instance_                The address of the proxy contract deployed.
                                                             *  @param initializationArguments_ The arguments used to initialize the proxy contract, if any.
                                                             */
                                                            event InstanceDeployed(uint256 indexed version_, address indexed instance_, bytes initializationArguments_);
                                                            /**
                                                             *  @dev   A instance has upgraded by proxying to a new implementation, with some migration arguments.
                                                             *  @param instance_           The address of the proxy contract.
                                                             *  @param fromVersion_        The initial implementation version being proxied.
                                                             *  @param toVersion_          The new implementation version being proxied.
                                                             *  @param migrationArguments_ The arguments used to migrate, if any.
                                                             */
                                                            event InstanceUpgraded(address indexed instance_, uint256 indexed fromVersion_, uint256 indexed toVersion_, bytes migrationArguments_);
                                                            /**
                                                             *  @dev   The MapleGlobals was set.
                                                             *  @param mapleGlobals_ The address of a Maple Globals contract.
                                                             */
                                                            event MapleGlobalsSet(address indexed mapleGlobals_);
                                                            /**
                                                             *  @dev   An upgrade path was disabled, with an optional migrator contract.
                                                             *  @param fromVersion_ The starting version of the upgrade path.
                                                             *  @param toVersion_   The destination version of the upgrade path.
                                                             */
                                                            event UpgradePathDisabled(uint256 indexed fromVersion_, uint256 indexed toVersion_);
                                                            /**
                                                             *  @dev   An upgrade path was enabled, with an optional migrator contract.
                                                             *  @param fromVersion_ The starting version of the upgrade path.
                                                             *  @param toVersion_   The destination version of the upgrade path.
                                                             *  @param migrator_    The address of the migrator, if any.
                                                             */
                                                            event UpgradePathEnabled(uint256 indexed fromVersion_, uint256 indexed toVersion_, address indexed migrator_);
                                                            /**************************************************************************************************************************************/
                                                            /*** State Variables                                                                                                                ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev The default version.
                                                             */
                                                            function defaultVersion() external view returns (uint256 defaultVersion_);
                                                            /**
                                                             *  @dev The address of the MapleGlobals contract.
                                                             */
                                                            function mapleGlobals() external view returns (address mapleGlobals_);
                                                            /**
                                                             *  @dev    Whether the upgrade is enabled for a path from a version to another version.
                                                             *  @param  toVersion_   The initial version.
                                                             *  @param  fromVersion_ The destination version.
                                                             *  @return allowed_     Whether the upgrade is enabled.
                                                             */
                                                            function upgradeEnabledForPath(uint256 toVersion_, uint256 fromVersion_) external view returns (bool allowed_);
                                                            /**************************************************************************************************************************************/
                                                            /*** State Changing Functions                                                                                                       ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev    Deploys a new instance proxying the default implementation version, with some initialization arguments.
                                                             *          Uses a nonce and `msg.sender` as a salt for the CREATE2 opcode during instantiation to produce deterministic addresses.
                                                             *  @param  arguments_ The initialization arguments to use for the instance deployment, if any.
                                                             *  @param  salt_      The salt to use in the contract creation process.
                                                             *  @return instance_  The address of the deployed proxy contract.
                                                             */
                                                            function createInstance(bytes calldata arguments_, bytes32 salt_) external returns (address instance_);
                                                            /**
                                                             *  @dev   Enables upgrading from a version to a version of an implementation, with an optional migrator.
                                                             *         Only the Governor can call this function.
                                                             *  @param fromVersion_ The starting version of the upgrade path.
                                                             *  @param toVersion_   The destination version of the upgrade path.
                                                             *  @param migrator_    The address of the migrator, if any.
                                                             */
                                                            function enableUpgradePath(uint256 fromVersion_, uint256 toVersion_, address migrator_) external;
                                                            /**
                                                             *  @dev   Disables upgrading from a version to a version of a implementation.
                                                             *         Only the Governor can call this function.
                                                             *  @param fromVersion_ The starting version of the upgrade path.
                                                             *  @param toVersion_   The destination version of the upgrade path.
                                                             */
                                                            function disableUpgradePath(uint256 fromVersion_, uint256 toVersion_) external;
                                                            /**
                                                             *  @dev   Registers the address of an implementation contract as a version, with an optional initializer.
                                                             *         Only the Governor can call this function.
                                                             *  @param version_               The version to register.
                                                             *  @param implementationAddress_ The address of the implementation.
                                                             *  @param initializer_           The address of the initializer, if any.
                                                             */
                                                            function registerImplementation(uint256 version_, address implementationAddress_, address initializer_) external;
                                                            /**
                                                             *  @dev   Sets the default version.
                                                             *         Only the Governor can call this function.
                                                             *  @param version_ The implementation version to set as the default.
                                                             */
                                                            function setDefaultVersion(uint256 version_) external;
                                                            /**
                                                             *  @dev   Sets the Maple Globals contract.
                                                             *         Only the Governor can call this function.
                                                             *  @param mapleGlobals_ The address of a Maple Globals contract.
                                                             */
                                                            function setGlobals(address mapleGlobals_) external;
                                                            /**
                                                             *  @dev   Upgrades the calling proxy contract's implementation, with some migration arguments.
                                                             *  @param toVersion_ The implementation version to upgrade the proxy contract to.
                                                             *  @param arguments_ The migration arguments, if any.
                                                             */
                                                            function upgradeInstance(uint256 toVersion_, bytes calldata arguments_) external;
                                                            /**************************************************************************************************************************************/
                                                            /*** View Functions                                                                                                                 ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev    Returns the deterministic address of a potential proxy, given some arguments and salt.
                                                             *  @param  arguments_       The initialization arguments to be used when deploying the proxy.
                                                             *  @param  salt_            The salt to be used when deploying the proxy.
                                                             *  @return instanceAddress_ The deterministic address of a potential proxy.
                                                             */
                                                            function getInstanceAddress(bytes calldata arguments_, bytes32 salt_) external view returns (address instanceAddress_);
                                                            /**
                                                             *  @dev    Returns the address of an implementation version.
                                                             *  @param  version_        The implementation version.
                                                             *  @return implementation_ The address of the implementation.
                                                             */
                                                            function implementationOf(uint256 version_) external view returns (address implementation_);
                                                            /**
                                                             *  @dev    Returns if a given address has been deployed by this factory/
                                                             *  @param  instance_   The address to check.
                                                             *  @return isInstance_ A boolean indication if the address has been deployed by this factory.
                                                             */
                                                            function isInstance(address instance_) external view returns (bool isInstance_);
                                                            /**
                                                             *  @dev    Returns the address of a migrator contract for a migration path (from version, to version).
                                                             *          If oldVersion_ == newVersion_, the migrator is an initializer.
                                                             *  @param  oldVersion_ The old version.
                                                             *  @param  newVersion_ The new version.
                                                             *  @return migrator_   The address of a migrator contract.
                                                             */
                                                            function migratorForPath(uint256 oldVersion_, uint256 newVersion_) external view returns (address migrator_);
                                                            /**
                                                             *  @dev    Returns the version of an implementation contract.
                                                             *  @param  implementation_ The address of an implementation contract.
                                                             *  @return version_        The version of the implementation contract.
                                                             */
                                                            function versionOf(address implementation_) external view returns (uint256 version_);
                                                        }
                                                        // SPDX-License-Identifier: AGPL-3.0-or-later
                                                        pragma solidity ^0.8.7;
                                                        import { IProxied } from "../../modules/proxy-factory/contracts/interfaces/IProxied.sol";
                                                        /// @title A Maple implementation that is to be proxied, must implement IMapleProxied.
                                                        interface IMapleProxied is IProxied {
                                                            /**
                                                             *  @dev   The instance was upgraded.
                                                             *  @param toVersion_ The new version of the loan.
                                                             *  @param arguments_ The upgrade arguments, if any.
                                                             */
                                                            event Upgraded(uint256 toVersion_, bytes arguments_);
                                                            /**
                                                             *  @dev   Upgrades a contract implementation to a specific version.
                                                             *         Access control logic critical since caller can force a selfdestruct via a malicious `migrator_` which is delegatecalled.
                                                             *  @param toVersion_ The version to upgrade to.
                                                             *  @param arguments_ Some encoded arguments to use for the upgrade.
                                                             */
                                                            function upgrade(uint256 toVersion_, bytes calldata arguments_) external;
                                                        }
                                                        // SPDX-License-Identifier: AGPL-3.0-or-later
                                                        pragma solidity ^0.8.7;
                                                        import { ProxiedInternals } from "../modules/proxy-factory/contracts/ProxiedInternals.sol";
                                                        /// @title A Maple implementation that is to be proxied, will need MapleProxiedInternals.
                                                        abstract contract MapleProxiedInternals is ProxiedInternals { }
                                                        // SPDX-License-Identifier: AGPL-3.0-only
                                                        pragma solidity ^0.8.7;
                                                        /// @title An beacon that provides a default implementation for proxies, must implement IDefaultImplementationBeacon.
                                                        interface IDefaultImplementationBeacon {
                                                            /// @dev The address of an implementation for proxies.
                                                            function defaultImplementation() external view returns (address defaultImplementation_);
                                                        }
                                                        // SPDX-License-Identifier: AGPL-3.0-only
                                                        pragma solidity ^0.8.7;
                                                        /// @title An implementation that is to be proxied, must implement IProxied.
                                                        interface IProxied {
                                                            /**
                                                             *  @dev The address of the proxy factory.
                                                             */
                                                            function factory() external view returns (address factory_);
                                                            /**
                                                             *  @dev The address of the implementation contract being proxied.
                                                             */
                                                            function implementation() external view returns (address implementation_);
                                                            /**
                                                             *  @dev   Modifies the proxy's implementation address.
                                                             *  @param newImplementation_ The address of an implementation contract.
                                                             */
                                                            function setImplementation(address newImplementation_) external;
                                                            /**
                                                             *  @dev   Modifies the proxy's storage by delegate-calling a migrator contract with some arguments.
                                                             *         Access control logic critical since caller can force a selfdestruct via a malicious `migrator_` which is delegatecalled.
                                                             *  @param migrator_  The address of a migrator contract.
                                                             *  @param arguments_ Some encoded arguments to use for the migration.
                                                             */
                                                            function migrate(address migrator_, bytes calldata arguments_) external;
                                                        }
                                                        // SPDX-License-Identifier: AGPL-3.0-only
                                                        pragma solidity ^0.8.7;
                                                        import { SlotManipulatable } from "./SlotManipulatable.sol";
                                                        /// @title An implementation that is to be proxied, will need ProxiedInternals.
                                                        abstract contract ProxiedInternals is SlotManipulatable {
                                                            /// @dev Storage slot with the address of the current factory. `keccak256('eip1967.proxy.factory') - 1`.
                                                            bytes32 private constant FACTORY_SLOT = bytes32(0x7a45a402e4cb6e08ebc196f20f66d5d30e67285a2a8aa80503fa409e727a4af1);
                                                            /// @dev Storage slot with the address of the current factory. `keccak256('eip1967.proxy.implementation') - 1`.
                                                            bytes32 private constant IMPLEMENTATION_SLOT = bytes32(0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc);
                                                            /// @dev Delegatecalls to a migrator contract to manipulate storage during an initialization or migration.
                                                            function _migrate(address migrator_, bytes calldata arguments_) internal virtual returns (bool success_) {
                                                                uint256 size;
                                                                assembly {
                                                                    size := extcodesize(migrator_)
                                                                }
                                                                if (size == uint256(0)) return false;
                                                                ( success_, ) = migrator_.delegatecall(arguments_);
                                                            }
                                                            /// @dev Sets the factory address in storage.
                                                            function _setFactory(address factory_) internal virtual returns (bool success_) {
                                                                _setSlotValue(FACTORY_SLOT, bytes32(uint256(uint160(factory_))));
                                                                return true;
                                                            }
                                                            /// @dev Sets the implementation address in storage.
                                                            function _setImplementation(address implementation_) internal virtual returns (bool success_) {
                                                                _setSlotValue(IMPLEMENTATION_SLOT, bytes32(uint256(uint160(implementation_))));
                                                                return true;
                                                            }
                                                            /// @dev Returns the factory address.
                                                            function _factory() internal view virtual returns (address factory_) {
                                                                return address(uint160(uint256(_getSlotValue(FACTORY_SLOT))));
                                                            }
                                                            /// @dev Returns the implementation address.
                                                            function _implementation() internal view virtual returns (address implementation_) {
                                                                return address(uint160(uint256(_getSlotValue(IMPLEMENTATION_SLOT))));
                                                            }
                                                        }
                                                        // SPDX-License-Identifier: AGPL-3.0-only
                                                        pragma solidity ^0.8.7;
                                                        abstract contract SlotManipulatable {
                                                            function _getReferenceTypeSlot(bytes32 slot_, bytes32 key_) internal pure returns (bytes32 value_) {
                                                                return keccak256(abi.encodePacked(key_, slot_));
                                                            }
                                                            function _getSlotValue(bytes32 slot_) internal view returns (bytes32 value_) {
                                                                assembly {
                                                                    value_ := sload(slot_)
                                                                }
                                                            }
                                                            function _setSlotValue(bytes32 slot_, bytes32 value_) internal {
                                                                assembly {
                                                                    sstore(slot_, value_)
                                                                }
                                                            }
                                                        }
                                                        

                                                        File 7 of 13: NonTransparentProxy
                                                        // SPDX-License-Identifier: AGPL-3.0-or-later
                                                        pragma solidity 0.8.7;
                                                        import { INonTransparentProxy } from "./interfaces/INonTransparentProxy.sol";
                                                        contract NonTransparentProxy is INonTransparentProxy {
                                                            bytes32 private constant ADMIN_SLOT          = bytes32(uint256(keccak256("eip1967.proxy.admin"))          - 1);
                                                            bytes32 private constant IMPLEMENTATION_SLOT = bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1);
                                                            constructor(address admin_, address implementation_) {
                                                                _setAddress(ADMIN_SLOT,          admin_);
                                                                _setAddress(IMPLEMENTATION_SLOT, implementation_);
                                                            }
                                                            /******************************************************************************************************************************/
                                                            /*** Admin Functions                                                                                                        ***/
                                                            /******************************************************************************************************************************/
                                                            function setImplementation(address newImplementation_) override external {
                                                                require(msg.sender == _admin(), "NTP:SI:NOT_ADMIN");
                                                                _setAddress(IMPLEMENTATION_SLOT, newImplementation_);
                                                            }
                                                            /******************************************************************************************************************************/
                                                            /*** View Functions                                                                                                         ***/
                                                            /******************************************************************************************************************************/
                                                            function _admin() internal view returns (address admin_) {
                                                                admin_ = _getAddress(ADMIN_SLOT);
                                                            }
                                                            function _implementation() internal view returns (address implementation_) {
                                                                implementation_ = _getAddress(IMPLEMENTATION_SLOT);
                                                            }
                                                            /******************************************************************************************************************************/
                                                            /*** Utility Functions                                                                                                      ***/
                                                            /******************************************************************************************************************************/
                                                            function _setAddress(bytes32 slot_, address value_) private {
                                                                assembly {
                                                                    sstore(slot_, value_)
                                                                }
                                                            }
                                                            function _getAddress(bytes32 slot_) private view returns (address value_) {
                                                                assembly {
                                                                    value_ := sload(slot_)
                                                                }
                                                            }
                                                            /******************************************************************************************************************************/
                                                            /*** Fallback Function                                                                                                      ***/
                                                            /******************************************************************************************************************************/
                                                            fallback() external {
                                                                address implementation_ = _implementation();
                                                                require(implementation_.code.length != 0, "NTP:F:NO_CODE_ON_IMPLEMENTATION");
                                                                assembly {
                                                                    calldatacopy(0, 0, calldatasize())
                                                                    let result := delegatecall(gas(), implementation_, 0, calldatasize(), 0, 0)
                                                                    returndatacopy(0, 0, returndatasize())
                                                                    switch result
                                                                    case 0 {
                                                                        revert(0, returndatasize())
                                                                    }
                                                                    default {
                                                                        return(0, returndatasize())
                                                                    }
                                                                }
                                                            }
                                                        }
                                                        // SPDX-License-Identifier: AGPL-3.0-or-later
                                                        pragma solidity 0.8.7;
                                                        interface INonTransparentProxy {
                                                            /**
                                                             *  @dev   Sets the implementation address.
                                                             *  @param newImplementation_ The address to set the implementation to.
                                                             */
                                                            function setImplementation(address newImplementation_) external;
                                                        }
                                                        

                                                        File 8 of 13: MapleGlobals
                                                        // SPDX-License-Identifier: BUSL-1.1
                                                        pragma solidity ^0.8.25;
                                                        import { NonTransparentProxied } from "../modules/non-transparent-proxy/contracts/NonTransparentProxied.sol";
                                                        import { IMapleGlobals } from "./interfaces/IMapleGlobals.sol";
                                                        import { IChainlinkAggregatorV3Like, IPoolManagerLike, IProxyLike, IProxyFactoryLike } from "./interfaces/Interfaces.sol";
                                                        /*
                                                            ███╗   ███╗ █████╗ ██████╗ ██╗     ███████╗     ██████╗ ██╗      ██████╗ ██████╗  █████╗ ██╗     ███████╗
                                                            ████╗ ████║██╔══██╗██╔══██╗██║     ██╔════╝    ██╔════╝ ██║     ██╔═══██╗██╔══██╗██╔══██╗██║     ██╔════╝
                                                            ██╔████╔██║███████║██████╔╝██║     █████╗      ██║  ███╗██║     ██║   ██║██████╔╝███████║██║     ███████╗
                                                            ██║╚██╔╝██║██╔══██║██╔═══╝ ██║     ██╔══╝      ██║   ██║██║     ██║   ██║██╔══██╗██╔══██║██║     ╚════██║
                                                            ██║ ╚═╝ ██║██║  ██║██║     ███████╗███████╗    ╚██████╔╝███████╗╚██████╔╝██████╔╝██║  ██║███████╗███████║
                                                            ╚═╝     ╚═╝╚═╝  ╚═╝╚═╝     ╚══════╝╚══════╝     ╚═════╝ ╚══════╝ ╚═════╝ ╚═════╝ ╚═╝  ╚═╝╚══════╝╚══════╝
                                                        */
                                                        contract MapleGlobals is IMapleGlobals, NonTransparentProxied {
                                                            /**************************************************************************************************************************************/
                                                            /*** Structs                                                                                                                        ***/
                                                            /**************************************************************************************************************************************/
                                                            struct PoolDelegate {
                                                                address ownedPoolManager;
                                                                bool    isPoolDelegate;
                                                            }
                                                            struct ScheduledCall {
                                                                uint256 timestamp;
                                                                bytes32 dataHash;
                                                            }
                                                            struct TimelockParameters {
                                                                uint128 delay;
                                                                uint128 duration;
                                                            }
                                                            struct PriceOracle {
                                                                address oracle;
                                                                uint96  maxDelay;
                                                            }
                                                            /**************************************************************************************************************************************/
                                                            /*** Storage                                                                                                                        ***/
                                                            /**************************************************************************************************************************************/
                                                            uint256 public constant HUNDRED_PERCENT = 100_0000;
                                                            address public override mapleTreasury;
                                                            address public override migrationAdmin;
                                                            address public override pendingGovernor;
                                                            address public override securityAdmin;
                                                            bool public override protocolPaused;
                                                            TimelockParameters public override defaultTimelockParameters;
                                                            mapping(address => PriceOracle) public override priceOracleOf;
                                                            mapping(address => bool) public override isBorrower;
                                                            mapping(address => bool) public override isCollateralAsset;
                                                            mapping(address => bool) public override isPoolAsset;
                                                            mapping(address => bool) internal _isPoolDeployer;  // NOTE: Deprecated, but currently allowing only disabling.
                                                            mapping(address => uint256) public override manualOverridePrice;
                                                            mapping(address => uint256) public override maxCoverLiquidationPercent;
                                                            mapping(address => uint256) public override minCoverAmount;
                                                            mapping(address => uint256) public override bootstrapMint;
                                                            mapping(address => uint256) public override platformManagementFeeRate;
                                                            mapping(address => uint256) public override platformOriginationFeeRate;
                                                            mapping(address => uint256) public override platformServiceFeeRate;
                                                            mapping(address => mapping(bytes32 => TimelockParameters)) public override timelockParametersOf;
                                                            mapping(bytes32 => mapping(address => bool)) public override isInstanceOf;
                                                            // Timestamp and call data hash for a caller, on a contract, for a function id.
                                                            mapping(address => mapping(address => mapping(bytes32 => ScheduledCall))) public override scheduledCalls;
                                                            mapping(address => PoolDelegate) public override poolDelegates;
                                                            mapping(address => bool) public override isContractPaused;
                                                            mapping(address => mapping(bytes4 => bool)) public override isFunctionUnpaused;
                                                            mapping(address => mapping(address => bool)) internal _canDeployFrom;
                                                            address public override operationalAdmin;
                                                            /**************************************************************************************************************************************/
                                                            /*** Modifiers                                                                                                                      ***/
                                                            /**************************************************************************************************************************************/
                                                            modifier onlyGovernor() {
                                                                _revertIfNotGovernor();
                                                                _;
                                                            }
                                                            modifier onlyGovernorOrOperationalAdmin() {
                                                                _revertIfNotGovernorOrOperationalAdmin();
                                                                _;
                                                            }
                                                            modifier onlyGovernorOrSecurityAdmin() {
                                                                _revertIfNotGovernorOrSecurityAdmin();
                                                                _;
                                                            }
                                                            /**************************************************************************************************************************************/
                                                            /*** Governor Transfer Functions                                                                                                    ***/
                                                            /**************************************************************************************************************************************/
                                                            function acceptGovernor() external override {
                                                                require(msg.sender == pendingGovernor, "MG:NOT_PENDING_GOV");
                                                                emit GovernorshipAccepted(admin(), msg.sender);
                                                                _setAddress(ADMIN_SLOT, msg.sender);
                                                                pendingGovernor = address(0);
                                                            }
                                                            function setPendingGovernor(address pendingGovernor_) external override onlyGovernor {
                                                                emit PendingGovernorSet(pendingGovernor = pendingGovernor_);
                                                            }
                                                            /**************************************************************************************************************************************/
                                                            /*** Global Setters                                                                                                                 ***/
                                                            /**************************************************************************************************************************************/
                                                            // NOTE: `minCoverAmount` is not enforced at activation time.
                                                            function activatePoolManager(address poolManager_) external override onlyGovernorOrOperationalAdmin {
                                                                address factory_  = IPoolManagerLike(poolManager_).factory();
                                                                address delegate_ = IPoolManagerLike(poolManager_).poolDelegate();
                                                                require(isInstanceOf["POOL_MANAGER_FACTORY"][factory_],          "MG:APM:INVALID_FACTORY");
                                                                require(IProxyFactoryLike(factory_).isInstance(poolManager_),    "MG:APM:INVALID_POOL_MANAGER");
                                                                require(poolDelegates[delegate_].isPoolDelegate,                 "MG:APM:INVALID_DELEGATE");
                                                                require(poolDelegates[delegate_].ownedPoolManager == address(0), "MG:APM:ALREADY_OWNS");
                                                                emit PoolManagerActivated(poolManager_, delegate_);
                                                                poolDelegates[delegate_].ownedPoolManager = poolManager_;
                                                                IPoolManagerLike(poolManager_).setActive(true);
                                                            }
                                                            function setBootstrapMint(address asset_, uint256 amount_) external override onlyGovernorOrOperationalAdmin {
                                                                emit BootstrapMintSet(asset_, bootstrapMint[asset_] = amount_);
                                                            }
                                                            function setDefaultTimelockParameters(uint128 defaultTimelockDelay_, uint128 defaultTimelockDuration_) external override onlyGovernor {
                                                                emit DefaultTimelockParametersSet(
                                                                    defaultTimelockParameters.delay,
                                                                    defaultTimelockDelay_,
                                                                    defaultTimelockParameters.duration,
                                                                    defaultTimelockDuration_
                                                                );
                                                                defaultTimelockParameters = TimelockParameters(defaultTimelockDelay_, defaultTimelockDuration_);
                                                            }
                                                            function setMapleTreasury(address mapleTreasury_) external override onlyGovernor {
                                                                require(mapleTreasury_ != address(0), "MG:SMT:ZERO_ADDR");
                                                                emit MapleTreasurySet(mapleTreasury, mapleTreasury_);
                                                                mapleTreasury = mapleTreasury_;
                                                            }
                                                            function setMigrationAdmin(address migrationAdmin_) external override onlyGovernor {
                                                                emit MigrationAdminSet(migrationAdmin, migrationAdmin_);
                                                                migrationAdmin = migrationAdmin_;
                                                            }
                                                            function setOperationalAdmin(address operationalAdmin_) external override onlyGovernor {
                                                                emit OperationalAdminSet(operationalAdmin, operationalAdmin_);
                                                                operationalAdmin = operationalAdmin_;
                                                            }
                                                            function setPriceOracle(address asset_, address oracle_, uint96 maxDelay_) external override onlyGovernor {
                                                                require(oracle_ != address(0) && asset_ != address(0), "MG:SPO:ZERO_ADDR");
                                                                require(maxDelay_ > 0,                                 "MG:SPO:ZERO_TIME");
                                                                priceOracleOf[asset_].oracle   = oracle_;
                                                                priceOracleOf[asset_].maxDelay = maxDelay_;
                                                                emit PriceOracleSet(asset_, oracle_, maxDelay_);
                                                            }
                                                            function setSecurityAdmin(address securityAdmin_) external override onlyGovernor {
                                                                require(securityAdmin_ != address(0), "MG:SSA:ZERO_ADDR");
                                                                emit SecurityAdminSet(securityAdmin, securityAdmin_);
                                                                securityAdmin = securityAdmin_;
                                                            }
                                                            /**************************************************************************************************************************************/
                                                            /*** Boolean Setters                                                                                                                ***/
                                                            /**************************************************************************************************************************************/
                                                            function setContractPause(address contract_, bool contractPaused_) external override onlyGovernorOrSecurityAdmin {
                                                                emit ContractPauseSet(
                                                                    msg.sender,
                                                                    contract_,
                                                                    isContractPaused[contract_] = contractPaused_
                                                                );
                                                            }
                                                            function setFunctionUnpause(address contract_, bytes4 sig_, bool functionUnpaused_) external override onlyGovernorOrSecurityAdmin {
                                                                emit FunctionUnpauseSet(
                                                                    msg.sender,
                                                                    contract_,
                                                                    sig_,
                                                                    isFunctionUnpaused[contract_][sig_] = functionUnpaused_
                                                                );
                                                            }
                                                            function setProtocolPause(bool protocolPaused_) external override onlyGovernorOrSecurityAdmin {
                                                                emit ProtocolPauseSet(
                                                                    msg.sender,
                                                                    protocolPaused = protocolPaused_
                                                                );
                                                            }
                                                            /**************************************************************************************************************************************/
                                                            /*** Allowlist Setters                                                                                                              ***/
                                                            /**************************************************************************************************************************************/
                                                            function setCanDeployFrom(address factory_, address account_, bool canDeployFrom_) external override onlyGovernorOrOperationalAdmin {
                                                                emit CanDeployFromSet(factory_, account_, _canDeployFrom[factory_][account_] = canDeployFrom_);
                                                            }
                                                            function setValidBorrower(address borrower_, bool isValid_) external override onlyGovernorOrOperationalAdmin {
                                                                isBorrower[borrower_] = isValid_;
                                                                emit ValidBorrowerSet(borrower_, isValid_);
                                                            }
                                                            function setValidCollateralAsset(address collateralAsset_, bool isValid_) external override onlyGovernor {
                                                                isCollateralAsset[collateralAsset_] = isValid_;
                                                                emit ValidCollateralAssetSet(collateralAsset_, isValid_);
                                                            }
                                                            function setValidInstanceOf(bytes32 instanceKey_, address instance_, bool isValid_) external override onlyGovernorOrOperationalAdmin {
                                                                isInstanceOf[instanceKey_][instance_] = isValid_;
                                                                emit ValidInstanceSet(instanceKey_, instance_, isValid_);
                                                            }
                                                            function setValidPoolAsset(address poolAsset_, bool isValid_) external override onlyGovernor {
                                                                isPoolAsset[poolAsset_] = isValid_;
                                                                emit ValidPoolAssetSet(poolAsset_, isValid_);
                                                            }
                                                            function setValidPoolDelegate(address account_, bool isValid_) external override onlyGovernorOrOperationalAdmin {
                                                                require(account_ != address(0), "MG:SVPD:ZERO_ADDR");
                                                                // Cannot remove pool delegates that own a pool manager.
                                                                require(isValid_ || poolDelegates[account_].ownedPoolManager == address(0), "MG:SVPD:OWNS_POOL_MANAGER");
                                                                poolDelegates[account_].isPoolDelegate = isValid_;
                                                                emit ValidPoolDelegateSet(account_, isValid_);
                                                            }
                                                            function setValidPoolDeployer(address account_, bool isPoolDeployer_) external override onlyGovernor {
                                                                // NOTE: Explicit PoolDeployers via mapping are deprecated in favour of generalized canDeployFrom mapping.
                                                                require(!isPoolDeployer_, "MG:SVPD:ONLY_DISABLING");
                                                                emit ValidPoolDeployerSet(account_, _isPoolDeployer[account_] = isPoolDeployer_);
                                                            }
                                                            /**************************************************************************************************************************************/
                                                            /*** Price Setters                                                                                                                  ***/
                                                            /**************************************************************************************************************************************/
                                                            function setManualOverridePrice(address asset_, uint256 price_) external override onlyGovernor {
                                                                manualOverridePrice[asset_] = price_;
                                                                emit ManualOverridePriceSet(asset_, price_);
                                                            }
                                                            /**************************************************************************************************************************************/
                                                            /*** Cover Setters                                                                                                                  ***/
                                                            /**************************************************************************************************************************************/
                                                            function setMaxCoverLiquidationPercent(
                                                                address poolManager_,
                                                                uint256 maxCoverLiquidationPercent_
                                                            )
                                                                external override onlyGovernorOrOperationalAdmin
                                                            {
                                                                require(maxCoverLiquidationPercent_ <= HUNDRED_PERCENT, "MG:SMCLP:GT_100");
                                                                maxCoverLiquidationPercent[poolManager_] = maxCoverLiquidationPercent_;
                                                                emit MaxCoverLiquidationPercentSet(poolManager_, maxCoverLiquidationPercent_);
                                                            }
                                                            function setMinCoverAmount(address poolManager_, uint256 minCoverAmount_) external override onlyGovernorOrOperationalAdmin {
                                                                minCoverAmount[poolManager_] = minCoverAmount_;
                                                                emit MinCoverAmountSet(poolManager_, minCoverAmount_);
                                                            }
                                                            /**************************************************************************************************************************************/
                                                            /*** Fee Setters                                                                                                                    ***/
                                                            /**************************************************************************************************************************************/
                                                            function setPlatformManagementFeeRate(
                                                                address poolManager_,
                                                                uint256 platformManagementFeeRate_
                                                            )
                                                                external override onlyGovernorOrOperationalAdmin
                                                            {
                                                                require(platformManagementFeeRate_ <= HUNDRED_PERCENT, "MG:SPMFR:RATE_GT_100");
                                                                platformManagementFeeRate[poolManager_] = platformManagementFeeRate_;
                                                                emit PlatformManagementFeeRateSet(poolManager_, platformManagementFeeRate_);
                                                            }
                                                            function setPlatformOriginationFeeRate(
                                                                address poolManager_,
                                                                uint256 platformOriginationFeeRate_
                                                            )
                                                                external override onlyGovernorOrOperationalAdmin
                                                            {
                                                                require(platformOriginationFeeRate_ <= HUNDRED_PERCENT, "MG:SPOFR:RATE_GT_100");
                                                                platformOriginationFeeRate[poolManager_] = platformOriginationFeeRate_;
                                                                emit PlatformOriginationFeeRateSet(poolManager_, platformOriginationFeeRate_);
                                                            }
                                                            function setPlatformServiceFeeRate(
                                                                address poolManager_,
                                                                uint256 platformServiceFeeRate_
                                                            )
                                                                external override onlyGovernorOrOperationalAdmin
                                                            {
                                                                require(platformServiceFeeRate_ <= HUNDRED_PERCENT, "MG:SPSFR:RATE_GT_100");
                                                                platformServiceFeeRate[poolManager_] = platformServiceFeeRate_;
                                                                emit PlatformServiceFeeRateSet(poolManager_, platformServiceFeeRate_);
                                                            }
                                                            /**************************************************************************************************************************************/
                                                            /*** Contract Control Functions                                                                                                     ***/
                                                            /**************************************************************************************************************************************/
                                                            function setTimelockWindow(address contract_, bytes32 functionId_, uint128 delay_, uint128 duration_) public override onlyGovernor {
                                                                timelockParametersOf[contract_][functionId_] = TimelockParameters(delay_, duration_);
                                                                emit TimelockWindowSet(contract_, functionId_, delay_, duration_);
                                                            }
                                                            function setTimelockWindows(
                                                                address            contract_,
                                                                bytes32[] calldata functionIds_,
                                                                uint128[] calldata delays_,
                                                                uint128[] calldata durations_
                                                            )
                                                                public override onlyGovernor
                                                            {
                                                                for (uint256 i_; i_ < functionIds_.length; ++i_) {
                                                                    _setTimelockWindow(contract_, functionIds_[i_], delays_[i_], durations_[i_]);
                                                                }
                                                            }
                                                            function transferOwnedPoolManager(address fromPoolDelegate_, address toPoolDelegate_) external override {
                                                                PoolDelegate storage fromDelegate_ = poolDelegates[fromPoolDelegate_];
                                                                PoolDelegate storage toDelegate_   = poolDelegates[toPoolDelegate_];
                                                                require(fromDelegate_.ownedPoolManager == msg.sender, "MG:TOPM:NO_AUTH");
                                                                require(toDelegate_.isPoolDelegate,                   "MG:TOPM:NOT_PD");
                                                                require(toDelegate_.ownedPoolManager == address(0),   "MG:TOPM:ALREADY_OWNS");
                                                                fromDelegate_.ownedPoolManager = address(0);
                                                                toDelegate_.ownedPoolManager   = msg.sender;
                                                                emit PoolManagerOwnershipTransferred(fromPoolDelegate_, toPoolDelegate_, msg.sender);
                                                            }
                                                            /**************************************************************************************************************************************/
                                                            /*** Schedule Functions                                                                                                             ***/
                                                            /**************************************************************************************************************************************/
                                                            function isValidScheduledCall(address caller_, address contract_, bytes32 functionId_, bytes calldata callData_)
                                                                public override view returns (bool isValid_)
                                                            {
                                                                ScheduledCall      storage scheduledCall_      = scheduledCalls[caller_][contract_][functionId_];
                                                                TimelockParameters storage timelockParameters_ = timelockParametersOf[contract_][functionId_];
                                                                uint256 timestamp_ = scheduledCall_.timestamp;
                                                                uint128 delay_     = timelockParameters_.delay;
                                                                uint128 duration_  = timelockParameters_.duration;
                                                                if (duration_ == uint128(0)) {
                                                                    delay_    = defaultTimelockParameters.delay;
                                                                    duration_ = defaultTimelockParameters.duration;
                                                                }
                                                                isValid_ =
                                                                    (block.timestamp >= timestamp_ + delay_) &&
                                                                    (block.timestamp <= timestamp_ + delay_ + duration_) &&
                                                                    (keccak256(abi.encode(callData_)) == scheduledCall_.dataHash);
                                                            }
                                                            function scheduleCall(address contract_, bytes32 functionId_, bytes calldata callData_) external override {
                                                                bytes32 dataHash_ = keccak256(abi.encode(callData_));
                                                                scheduledCalls[msg.sender][contract_][functionId_] = ScheduledCall(block.timestamp, dataHash_);
                                                                emit CallScheduled(msg.sender, contract_, functionId_, dataHash_, block.timestamp);
                                                            }
                                                            function unscheduleCall(address caller_, bytes32 functionId_, bytes calldata callData_) external override {
                                                                _unscheduleCall(caller_, msg.sender, functionId_, callData_);
                                                            }
                                                            function unscheduleCall(address caller_, address contract_, bytes32 functionId_, bytes calldata callData_)
                                                                external override onlyGovernor
                                                            {
                                                                _unscheduleCall(caller_, contract_, functionId_, callData_);
                                                            }
                                                            function _unscheduleCall(address caller_, address contract_, bytes32 functionId_, bytes calldata callData_) internal {
                                                                bytes32 dataHash_ = keccak256(abi.encode(callData_));
                                                                require(dataHash_ == scheduledCalls[caller_][contract_][functionId_].dataHash, "MG:UC:CALLDATA_MISMATCH");
                                                                delete scheduledCalls[caller_][contract_][functionId_];
                                                                emit CallUnscheduled(caller_, contract_, functionId_, dataHash_, block.timestamp);
                                                            }
                                                            /**************************************************************************************************************************************/
                                                            /*** View Functions                                                                                                                 ***/
                                                            /**************************************************************************************************************************************/
                                                            function canDeploy(address caller_) public override view returns (bool canDeploy_) {
                                                                canDeploy_ = canDeployFrom(msg.sender, caller_);
                                                            }
                                                            function canDeployFrom(address factory_, address caller_) public override view returns (bool canDeployFrom_) {
                                                                // Simply check if the caller can deploy at the factory. If not, since a PoolManager is often deployed in the same transaction as
                                                                // the Strategies it deploys, check if `factory_` is a StrategyFactory and the caller is a PoolManager or
                                                                // if the factory is a loan factory and the caller is a valid borrower.
                                                                canDeployFrom_ = _canDeployFrom[factory_][caller_] ||
                                                                                 (isInstanceOf["LOAN_FACTORY"][factory_] && isBorrower[caller_]) ||
                                                                                 (isInstanceOf["STRATEGY_FACTORY"][factory_] && _isPoolManager(caller_));
                                                            }
                                                            function getLatestPrice(address asset_) external override view returns (uint256 latestPrice_) {
                                                                // If governor has overridden price because of oracle outage, return overridden price.
                                                                if (manualOverridePrice[asset_] != 0) return manualOverridePrice[asset_];
                                                                address oracle_ = priceOracleOf[asset_].oracle;
                                                                require(oracle_ != address(0), "MG:GLP:ZERO_ORACLE");
                                                                (
                                                                    ,
                                                                    int256 price_,
                                                                    ,
                                                                    uint256 updatedAt_,
                                                                ) = IChainlinkAggregatorV3Like(oracle_).latestRoundData();
                                                                require(updatedAt_ != 0,                                                  "MG:GLP:ROUND_NOT_COMPLETE");
                                                                require(updatedAt_ >= (block.timestamp - priceOracleOf[asset_].maxDelay), "MG:GLP:STALE_PRICE");
                                                                require(price_ > int256(0),                                               "MG:GLP:ZERO_PRICE");
                                                                latestPrice_ = uint256(price_);
                                                            }
                                                            function governor() external view override returns (address governor_) {
                                                                governor_ = admin();
                                                            }
                                                            // NOTE: This function is deprecated.
                                                            // NOTE: This is only used by the LiquidatorFactory to determine if the factory of it's caller is a FixedTermLoanManagerFactory.
                                                            // NOTE: Original liquidatorFactory checks isFactory("LOAN_MANAGER", IMapleProxied(msg.sender).factory());
                                                            function isFactory(bytes32 factoryId_, address factory_) external view override returns (bool isFactory_) {
                                                                // NOTE: Key is not used as this function is deprecated and narrowed.
                                                                factoryId_;
                                                                // Revert if caller is not LiquidatorFactory, the only allowed caller of this deprecated function.
                                                                require(isInstanceOf["LIQUIDATOR_FACTORY"][msg.sender], "MG:IF:NOT_LIQ_FACTORY");
                                                                // Determine if the `factory_` is a `FixedTermLoanManagerFactory`.
                                                                isFactory_ = isInstanceOf["FT_LOAN_MANAGER_FACTORY"][factory_];
                                                            }
                                                            function isFunctionPaused(bytes4 sig_) external view override returns (bool functionIsPaused_) {
                                                                functionIsPaused_ = isFunctionPaused(msg.sender, sig_);
                                                            }
                                                            function isFunctionPaused(address contract_, bytes4 sig_) public view override returns (bool functionIsPaused_) {
                                                                functionIsPaused_ = (protocolPaused || isContractPaused[contract_]) && !isFunctionUnpaused[contract_][sig_];
                                                            }
                                                            function isPoolDelegate(address account_) external view override returns (bool isPoolDelegate_) {
                                                                isPoolDelegate_ = poolDelegates[account_].isPoolDelegate;
                                                            }
                                                            // NOTE: This function is deprecated.
                                                            // NOTE: This is only used by FixedTermLoanManagerFactory, PoolManagerFactory, and WithdrawalManagerFactory, so it must return true for
                                                            //       any caller that is either:
                                                            //       - An actual PoolDeployer contract (in the case of a PoolManagerFactory or WithdrawalManagerFactory), or
                                                            //       - A PoolManager contract (in the case of a FixedTermLoanManagerFactory)
                                                            function isPoolDeployer(address caller_) external view override returns (bool isPoolDeployer_) {
                                                                // Revert if caller is not FixedTermLoanManagerFactory, PoolManagerFactory, or WithdrawalManagerFactory,
                                                                // the only allowed callers of this deprecated function.
                                                                require(
                                                                    isInstanceOf["FT_LOAN_MANAGER_FACTORY"][msg.sender] ||
                                                                    isInstanceOf["POOL_MANAGER_FACTORY"][msg.sender] ||
                                                                    isInstanceOf["WITHDRAWAL_MANAGER_FACTORY"][msg.sender],
                                                                    "MG:IPD:INV_FACTORY"
                                                                );
                                                                // This demonstrates that canDeploy() is a full replacement for isPoolDeployer().
                                                                isPoolDeployer_ = canDeploy(caller_);
                                                            }
                                                            function ownedPoolManager(address account_) external view override returns (address poolManager_) {
                                                                poolManager_ = poolDelegates[account_].ownedPoolManager;
                                                            }
                                                            /**************************************************************************************************************************************/
                                                            /*** Helper Functions                                                                                                               ***/
                                                            /**************************************************************************************************************************************/
                                                            function _isPoolManager(address contract_) internal view returns (bool isPoolManager_) {
                                                                address factory_ = IProxyLike(contract_).factory();
                                                                isPoolManager_ = (isInstanceOf["POOL_MANAGER_FACTORY"][factory_]) && IProxyFactoryLike(factory_).isInstance(contract_);
                                                            }
                                                            function _revertIfNotGovernor() internal view {
                                                                require(msg.sender == admin(), "MG:NOT_GOV");
                                                            }
                                                            function _revertIfNotGovernorOrOperationalAdmin() internal view {
                                                                require(msg.sender == admin() || msg.sender == operationalAdmin, "MG:NOT_GOV_OR_OA");
                                                            }
                                                            function _revertIfNotGovernorOrSecurityAdmin() internal view {
                                                                require(msg.sender == admin() || msg.sender == securityAdmin, "MG:NOT_GOV_OR_SA");
                                                            }
                                                            function _setAddress(bytes32 slot_, address value_) private {
                                                                assembly {
                                                                    sstore(slot_, value_)
                                                                }
                                                            }
                                                            function _setTimelockWindow(address contract_, bytes32 functionId_, uint128 delay_, uint128 duration_) internal {
                                                                timelockParametersOf[contract_][functionId_] = TimelockParameters(delay_, duration_);
                                                                emit TimelockWindowSet(contract_, functionId_, delay_, duration_);
                                                            }
                                                        }
                                                        // SPDX-License-Identifier: AGPL-3.0-or-later
                                                        pragma solidity ^0.8.7;
                                                        import { INonTransparentProxied } from "./interfaces/INonTransparentProxied.sol";
                                                        contract NonTransparentProxied is INonTransparentProxied {
                                                            bytes32 internal constant ADMIN_SLOT          = bytes32(uint256(keccak256("eip1967.proxy.admin"))          - 1);
                                                            bytes32 internal constant IMPLEMENTATION_SLOT = bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1);
                                                            function admin() public view override returns (address admin_) {
                                                                admin_ = _getAddress(ADMIN_SLOT);
                                                            }
                                                            function implementation() public view override returns (address implementation_) {
                                                                implementation_ = _getAddress(IMPLEMENTATION_SLOT);
                                                            }
                                                            function _getAddress(bytes32 slot_) internal view returns (address value_) {
                                                                assembly {
                                                                    value_ := sload(slot_)
                                                                }
                                                            }
                                                        }
                                                        // SPDX-License-Identifier: BUSL-1.1
                                                        pragma solidity ^0.8.0;
                                                        import { INonTransparentProxied } from "../../modules/non-transparent-proxy/contracts/NonTransparentProxied.sol";
                                                        interface IMapleGlobals is INonTransparentProxied {
                                                            /**************************************************************************************************************************************/
                                                            /*** Events                                                                                                                         ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev   A virtualized first mint that acts as as offset to `totalAssets` and `totalSupply`.
                                                             *  @param asset_         The address of the pool asset.
                                                             *  @param bootstrapMint_ The amount of shares that will offset `totalAssets` and `totalSupply`.
                                                             */
                                                            event BootstrapMintSet(address indexed asset_, uint256 bootstrapMint_);
                                                            /**
                                                             *  @dev   A time locked call has been scheduled.
                                                             *  @param caller_     The address of the function caller.
                                                             *  @param contract_   The contract to execute the call on.
                                                             *  @param functionId_ The id of the function to execute.
                                                             *  @param dataHash_   The hash of the parameters to pass to the function.
                                                             *  @param timestamp_  The timestamp of the schedule.
                                                             */
                                                            event CallScheduled(
                                                                address indexed caller_,
                                                                address indexed contract_,
                                                                bytes32 indexed functionId_,
                                                                bytes32         dataHash_,
                                                                uint256         timestamp_
                                                            );
                                                            /**
                                                             *  @dev   A time locked call has been unscheduled.
                                                             *  @param caller_     The address of the function caller.
                                                             *  @param contract_   The contract to execute the call on.
                                                             *  @param functionId_ The id of the function to execute.
                                                             *  @param dataHash_   The hash of the parameters to pass to the function.
                                                             *  @param timestamp_  The timestamp of the schedule.
                                                             */
                                                            event CallUnscheduled(
                                                                address indexed caller_,
                                                                address indexed contract_,
                                                                bytes32 indexed functionId_,
                                                                bytes32         dataHash_,
                                                                uint256         timestamp_
                                                            );
                                                            /**
                                                             *  @dev   An account has been allowed/disallowed from deploying an instance from a particular factory.
                                                             *  @param factory_       The address of the factory.
                                                             *  @param account_       The address of the account.
                                                             *  @param canDeployFrom_ Whether the account can deploy from the factory.
                                                             */
                                                            event CanDeployFromSet(address indexed factory_, address indexed account_, bool canDeployFrom_);
                                                            /**
                                                             *  @dev   The paused state for a given protocol contract was set.
                                                             *  @param caller_         The address of the security admin or governor that performed the action.
                                                             *  @param contract_       The address of a contract in the protocol.
                                                             *  @param contractPaused_ Whether the contract is uniquely paused.
                                                             */
                                                            event ContractPauseSet(address indexed caller_, address indexed contract_, bool contractPaused_);
                                                            /**
                                                             *  @dev   The default parameters for the time lock has been set.
                                                             *  @param previousDelay_    The previous required delay.
                                                             *  @param currentDelay_     The newly set required delay.
                                                             *  @param previousDuration_ The previous required duration.
                                                             *  @param currentDuration_  The newly set required duration.
                                                             */
                                                            event DefaultTimelockParametersSet(uint256 previousDelay_, uint256 currentDelay_, uint256 previousDuration_, uint256 currentDuration_);
                                                            /**
                                                             *  @dev   The paused state for a function of a given protocol contract was set.
                                                             *  @param caller_           The address of the security admin or governor that performed the action.
                                                             *  @param contract_         The address of a contract in the protocol.
                                                             *  @param sig_              The function signature within the contract.
                                                             *  @param functionUnpaused_ Whether the contract's function is uniquely unpaused.
                                                             */
                                                            event FunctionUnpauseSet(address indexed caller_, address indexed contract_, bytes4 indexed sig_, bool functionUnpaused_);
                                                            /**
                                                             *  @dev   The governorship has been accepted.
                                                             *  @param previousGovernor_ The previous governor.
                                                             *  @param currentGovernor_  The new governor.
                                                             */
                                                            event GovernorshipAccepted(address indexed previousGovernor_, address indexed currentGovernor_);
                                                            /**
                                                             *  @dev   The price for an asset has been set.
                                                             *  @param asset_ The address of the asset.
                                                             *  @param price_ The manually set price of the asset.
                                                             */
                                                            event ManualOverridePriceSet(address indexed asset_, uint256 price_);
                                                            /**
                                                             *  @dev   The address for the Maple treasury has been set.
                                                             *  @param previousMapleTreasury_ The previous treasury.
                                                             *  @param currentMapleTreasury_  The new treasury.
                                                             */
                                                            event MapleTreasurySet(address indexed previousMapleTreasury_, address indexed currentMapleTreasury_);
                                                            /**
                                                             *  @dev   The max liquidation percent for the given pool manager has been set.
                                                             *  @param poolManager_                The address of the pool manager.
                                                             *  @param maxCoverLiquidationPercent_ The new value for the cover liquidation percent.
                                                             */
                                                            event MaxCoverLiquidationPercentSet(address indexed poolManager_, uint256 maxCoverLiquidationPercent_);
                                                            /**
                                                             *  @dev   The migration admin has been set.
                                                             *  @param previousMigrationAdmin_ The previous migration admin.
                                                             *  @param nextMigrationAdmin_     The new migration admin.
                                                             */
                                                            event MigrationAdminSet(address indexed previousMigrationAdmin_, address indexed nextMigrationAdmin_);
                                                            /**
                                                             *  @dev   The minimum cover amount for the given pool manager has been set.
                                                             *  @param poolManager_    The address of the pool manager.
                                                             *  @param minCoverAmount_ The new value for the minimum cover amount.
                                                             */
                                                            event MinCoverAmountSet(address indexed poolManager_, uint256 minCoverAmount_);
                                                            /**
                                                             *  @dev   The operational admin was set.
                                                             *  @param previousOperationalAdmin_ The address of the previous operational admin.
                                                             *  @param currentOperationalAdmin_  The address of the new operational admin.
                                                             */
                                                            event OperationalAdminSet(address indexed previousOperationalAdmin_, address indexed currentOperationalAdmin_);
                                                            /**
                                                             *  @dev   The pending governor has been set.
                                                             *  @param pendingGovernor_ The new pending governor.
                                                             */
                                                            event PendingGovernorSet(address indexed pendingGovernor_);
                                                            /**
                                                             *  @dev   The platform management fee rate for the given pool manager has been set.
                                                             *  @param poolManager_               The address of the pool manager.
                                                             *  @param platformManagementFeeRate_ The new value for the platform management fee rate.
                                                             */
                                                            event PlatformManagementFeeRateSet(address indexed poolManager_, uint256 platformManagementFeeRate_);
                                                            /**
                                                             *  @dev   The platform origination fee rate for the given pool manager has been set.
                                                             *  @param poolManager_                The address of the pool manager.
                                                             *  @param platformOriginationFeeRate_ The new value for the origination fee rate.
                                                             */
                                                            event PlatformOriginationFeeRateSet(address indexed poolManager_, uint256 platformOriginationFeeRate_);
                                                            /**
                                                             *  @dev   The platform service fee rate for the given pool manager has been set.
                                                             *  @param poolManager_            The address of the pool manager.
                                                             *  @param platformServiceFeeRate_ The new value for the platform service fee rate.
                                                             */
                                                            event PlatformServiceFeeRateSet(address indexed poolManager_, uint256 platformServiceFeeRate_);
                                                            /**
                                                             *  @dev   The pool manager was activated.
                                                             *  @param poolManager_  The address of the pool manager.
                                                             *  @param poolDelegate_ The address of the pool delegate.
                                                             */
                                                            event PoolManagerActivated(address indexed poolManager_, address indexed poolDelegate_);
                                                            /**
                                                             *  @dev   The ownership of the pool manager was transferred.
                                                             *  @param fromPoolDelegate_ The address of the previous pool delegate.
                                                             *  @param toPoolDelegate_   The address of the new pool delegate.
                                                             *  @param poolManager_      The address of the pool manager.
                                                             */
                                                            event PoolManagerOwnershipTransferred(address indexed fromPoolDelegate_, address indexed toPoolDelegate_, address indexed poolManager_);
                                                            /**
                                                             *  @dev   The oracle for an asset has been set.
                                                             *  @param asset_    The address of the asset.
                                                             *  @param oracle_   The address of the oracle.
                                                             *  @param maxDelay_ The maximum delay of the oracle.
                                                             */
                                                            event PriceOracleSet(address indexed asset_, address indexed oracle_, uint96 maxDelay_);
                                                            /**
                                                             *  @dev   The protocol pause was set to a new state.
                                                             *  @param caller_         The address of the security admin or governor that performed the action.
                                                             *  @param protocolPaused_ The protocol paused state.
                                                             */
                                                            event ProtocolPauseSet(address indexed caller_, bool protocolPaused_);
                                                            /**
                                                             *  @dev   The security admin was set.
                                                             *  @param previousSecurityAdmin_ The address of the previous security admin.
                                                             *  @param currentSecurityAdmin_  The address of the new security admin.
                                                             */
                                                            event SecurityAdminSet(address indexed previousSecurityAdmin_, address indexed currentSecurityAdmin_);
                                                            /**
                                                             *  @dev   A new timelock window was set.
                                                             *  @param contract_   The contract to execute the call on.
                                                             *  @param functionId_ The id of the function to execute.
                                                             *  @param delay_      The delay of the timelock window.
                                                             *  @param duration_   The duration of the timelock window.
                                                             */
                                                            event TimelockWindowSet(address indexed contract_, bytes32 indexed functionId_, uint128 delay_, uint128 duration_);
                                                            /**
                                                             *  @dev   A valid borrower was set.
                                                             *  @param borrower_ The address of the borrower.
                                                             *  @param isValid_  The validity of the borrower.
                                                             */
                                                            event ValidBorrowerSet(address indexed borrower_, bool isValid_);
                                                            /**
                                                             *  @dev   A valid asset was set.
                                                             *  @param collateralAsset_ The address of the collateral asset.
                                                             *  @param isValid_         The validity of the collateral asset.
                                                             */
                                                            event ValidCollateralAssetSet(address indexed collateralAsset_, bool isValid_);
                                                            /**
                                                             *  @dev   A valid instance was set.
                                                             *  @param instanceKey_ The key of the instance.
                                                             *  @param instance_    The address of the instance.
                                                             *  @param isValid_     The validity of the instance.
                                                             */
                                                            event ValidInstanceSet(bytes32 indexed instanceKey_, address indexed instance_, bool isValid_);
                                                            /**
                                                             *  @dev   A valid asset was set.
                                                             *  @param poolAsset_ The address of the asset.
                                                             *  @param isValid_   The validity of the asset.
                                                             */
                                                            event ValidPoolAssetSet(address indexed poolAsset_, bool isValid_);
                                                            /**
                                                             *  @dev   A valid pool delegate was set.
                                                             *  @param account_ The address the account.
                                                             *  @param isValid_ The validity of the asset.
                                                             */
                                                            event ValidPoolDelegateSet(address indexed account_, bool isValid_);
                                                            /**
                                                             *  @dev   A valid pool deployer was set.
                                                             *  @param poolDeployer_ The address the account.
                                                             *  @param isValid_      The validity of the asset.
                                                             */
                                                            event ValidPoolDeployerSet(address indexed poolDeployer_, bool isValid_);
                                                            /**************************************************************************************************************************************/
                                                            /*** View Functions                                                                                                                 ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev    Gets the virtualized first mint that acts as as offset to `totalAssets` and `totalSupply` for a given pool asset.
                                                             *  @param  asset_         The address of the pool asset to query
                                                             *  @return bootstrapMint_ The amount of shares that will offset `totalAssets` and `totalSupply`.
                                                             */
                                                            function bootstrapMint(address asset_) external view returns (uint256 bootstrapMint_);
                                                            /**
                                                             *  @dev    Gets whether a caller account can deploy from the factory calling this function.
                                                             *  @param  caller_    The address of the account calling the factory.
                                                             *  @return canDeploy_ Whether the account can deploy from the factory.
                                                             */
                                                            function canDeploy(address caller_) external view returns (bool canDeploy_);
                                                            /**
                                                             *  @dev    Gets whether a caller account can deploy from a factory.
                                                             *  @param  factory_       The address of the factory.
                                                             *  @param  caller_        The address of the account calling the factory.
                                                             *  @return canDeployFrom_ Whether the account can deploy from the factory.
                                                             */
                                                            function canDeployFrom(address factory_, address caller_) external view returns (bool canDeployFrom_);
                                                            /**
                                                             *  @dev    Gets the default timelock parameters.
                                                             *  @return delay    The default timelock delay.
                                                             *  @return duration The default timelock duration.
                                                             */
                                                            function defaultTimelockParameters() external view returns (uint128 delay, uint128 duration);
                                                            /**
                                                             *  @dev    Gets the latest price for an asset.
                                                             *  @param  asset_       The address of the asset to query.
                                                             *  @return latestPrice_ The latest price for the asset.
                                                             */
                                                            function getLatestPrice(address asset_) external view returns (uint256 latestPrice_);
                                                            /**
                                                             *  @dev    Gets governor address.
                                                             *  @return governor_ The address of the governor.
                                                             */
                                                            function governor() external view returns (address governor_);
                                                            /**
                                                             *  @dev    Gets the validity of a borrower.
                                                             *  @param  borrower_   The address of the borrower to query.
                                                             *  @return isBorrower_ A boolean indicating the validity of the borrower.
                                                             */
                                                            function isBorrower(address borrower_) external view returns (bool isBorrower_);
                                                            /**
                                                             *  @dev    Gets the validity of a collateral asset.
                                                             *  @param  collateralAsset_   The address of the collateralAsset to query.
                                                             *  @return isCollateralAsset_ A boolean indicating the validity of the collateral asset.
                                                             */
                                                            function isCollateralAsset(address collateralAsset_) external view returns (bool isCollateralAsset_);
                                                            /**
                                                             *  @dev    Gets whether a contract is uniquely paused.
                                                             *  @param  contract_         The address of a contract in the protocol.
                                                             *  @return isContractPaused_ Whether the contract is uniquely paused.
                                                             */
                                                            function isContractPaused(address contract_) external view returns (bool isContractPaused_);
                                                            /**
                                                             *  @dev    Gets the validity of a factory.
                                                             *  @param  factoryId_ The address of the factory to query.
                                                             *  @param  factory_   The address of the factory to query.
                                                             *  @return isFactory_ A boolean indicating the validity of the factory.
                                                             */
                                                            function isFactory(bytes32 factoryId_, address factory_) external view returns (bool isFactory_);
                                                            /**
                                                             *  @dev    Gets whether a calling contract's function is paused.
                                                             *  @param  sig_              The function signature within the contract.
                                                             *  @return isFunctionPaused_ Whether the contract's function is paused.
                                                             */
                                                            function isFunctionPaused(bytes4 sig_) external view returns (bool isFunctionPaused_);
                                                            /**
                                                             *  @dev    Gets whether a contract's function is paused.
                                                             *  @param  contract_         The address of a contract in the protocol.
                                                             *  @param  sig_              The function signature within the contract.
                                                             *  @return isFunctionPaused_ Whether the contract's function is paused.
                                                             */
                                                            function isFunctionPaused(address contract_, bytes4 sig_) external view returns (bool isFunctionPaused_);
                                                            /**
                                                             *  @dev    Gets whether a contract's function is uniquely unpaused. A false does not imply it is paused.
                                                             *  @param  contract_           The address of a contract in the protocol.
                                                             *  @param  sig_                The function signature within the contract.
                                                             *  @return isFunctionUnpaused_ Whether the contract's function is uniquely unpaused.
                                                             */
                                                            function isFunctionUnpaused(address contract_, bytes4 sig_) external view returns (bool isFunctionUnpaused_);
                                                            /**
                                                             *  @dev    Gets wether an instance is of some instance key.
                                                             *  @param  instanceKey_ The key of some instance type.
                                                             *  @param  instance_    The address of an instance.
                                                             *  @return isInstance_  A boolean indicating whether the instance is of the instance key.
                                                             */
                                                            function isInstanceOf(bytes32 instanceKey_, address instance_) external view returns (bool isInstance_);
                                                            /**
                                                             *  @dev    Gets the validity of a pool asset.
                                                             *  @param  poolAsset_   The address of the poolAsset to query.
                                                             *  @return isPoolAsset_ A boolean indicating the validity of the pool asset.
                                                             */
                                                            function isPoolAsset(address poolAsset_) external view returns (bool isPoolAsset_);
                                                            /**
                                                             *  @dev    Gets the validity of a pool delegate.
                                                             *  @param  account_        The address of the account to query.
                                                             *  @return isPoolDelegate_ A boolean indicating the validity of the pool delegate.
                                                             */
                                                            function isPoolDelegate(address account_) external view returns (bool isPoolDelegate_);
                                                            /**
                                                             *  @dev    Gets the validity of a pool deployer.
                                                             *  @param  account_        The address of the account to query.
                                                             *  @return isPoolDeployer_ A boolean indicating the validity of the pool deployer.
                                                             */
                                                            function isPoolDeployer(address account_) external view returns (bool isPoolDeployer_);
                                                            /**
                                                             *  @dev    Gets the manual override price for an asset.
                                                             *  @param  asset_               The address of the asset to query.
                                                             *  @return manualOverridePrice_ The manual override price for the asset.
                                                             */
                                                            function manualOverridePrice(address asset_) external view returns (uint256 manualOverridePrice_);
                                                            /**
                                                             *  @dev    Gets maple treasury address.
                                                             *  @return mapleTreasury_ The address of the maple treasury.
                                                             */
                                                            function mapleTreasury() external view returns (address mapleTreasury_);
                                                            /**
                                                             *  @dev    Gets the maximum cover liquidation percent for a given pool manager.
                                                             *  @param  poolManager_                The address of the pool manager to query.
                                                             *  @return maxCoverLiquidationPercent_ The maximum cover liquidation percent.
                                                             */
                                                            function maxCoverLiquidationPercent(address poolManager_) external view returns (uint256 maxCoverLiquidationPercent_);
                                                            /**
                                                             *  @dev    Gets the migration admin address.
                                                             *  @return migrationAdmin_ The address of the migration admin.
                                                             */
                                                            function migrationAdmin() external view returns (address migrationAdmin_);
                                                            /**
                                                             *  @dev    Gets the minimum cover amount for a given pool manager.
                                                             *  @param  poolManager_    The address of the pool manager to query.
                                                             *  @return minCoverAmount_ The minimum cover amount.
                                                             */
                                                            function minCoverAmount(address poolManager_) external view returns (uint256 minCoverAmount_);
                                                            /**
                                                             *  @dev    Gets the operational admin address.
                                                             *  @return operationalAdmin_ The address of the operational admin.
                                                             */
                                                            function operationalAdmin() external view returns (address operationalAdmin_);
                                                            /**
                                                             *  @dev    Gets the address of the owner pool manager.
                                                             *  @param  account_     The address of the account to query.
                                                             *  @return poolManager_ The address of the pool manager.
                                                             */
                                                            function ownedPoolManager(address account_) external view returns (address poolManager_);
                                                            /**
                                                             *  @dev    Gets the address and maximum delay of the oracle for the given asset.
                                                             *  @param  asset_   The address of the asset to query.
                                                             *  @return oracle   The address of the oracle.
                                                             *  @return maxDelay The maximum delay of the oracle.
                                                             */
                                                            function priceOracleOf(address asset_) external view returns (address oracle, uint96 maxDelay);
                                                            /**
                                                             *  @dev    Gets the pending governor address.
                                                             *  @return pendingGovernor_ The address of the pending governor.
                                                             */
                                                            function pendingGovernor() external view returns (address pendingGovernor_);
                                                            /**
                                                             *  @dev    Gets the platform management fee rate for a given pool manager.
                                                             *  @param  poolManager_               The address of the pool manager to query.
                                                             *  @return platformManagementFeeRate_ The platform management fee rate.
                                                             */
                                                            function platformManagementFeeRate(address poolManager_) external view returns (uint256 platformManagementFeeRate_);
                                                            /**
                                                             *  @dev    Gets the platform origination fee rate for a given pool manager.
                                                             *  @param  poolManager_                The address of the pool manager to query.
                                                             *  @return platformOriginationFeeRate_ The platform origination fee rate.
                                                             */
                                                            function platformOriginationFeeRate(address poolManager_) external view returns (uint256 platformOriginationFeeRate_);
                                                            /**
                                                             *  @dev    Gets the platform service fee rate for a given pool manager.
                                                             *  @param  poolManager_            The address of the pool manager to query.
                                                             *  @return platformServiceFeeRate_ The platform service fee rate.
                                                             */
                                                            function platformServiceFeeRate(address poolManager_) external view returns (uint256 platformServiceFeeRate_);
                                                            /**
                                                             *  @dev    Gets pool delegate address information.
                                                             *  @param  poolDelegate_    The address of the pool delegate to query.
                                                             *  @return ownedPoolManager The address of the pool manager owned by the pool delegate.
                                                             *  @return isPoolDelegate   A boolean indication weather or not the address passed is a current pool delegate.
                                                             */
                                                            function poolDelegates(address poolDelegate_) external view returns (address ownedPoolManager, bool isPoolDelegate);
                                                            /**
                                                             *  @dev    Gets the status of the protocol pause.
                                                             *  @return protocolPaused_ A boolean indicating the status of the protocol pause.
                                                             */
                                                            function protocolPaused() external view returns (bool protocolPaused_);
                                                            /**
                                                             *  @dev    Gets the schedule calls for the parameters.
                                                             *  @param  caller_     The address of the caller.
                                                             *  @param  contract_   The address of the contract.
                                                             *  @param  functionId_ The id function to call.
                                                             *  @return timestamp   The timestamp of the next scheduled call.
                                                             *  @return dataHash    The hash of data fot the scheduled call.
                                                             */
                                                            function scheduledCalls(
                                                                address caller_,
                                                                address contract_,
                                                                bytes32 functionId_
                                                            ) external view returns (uint256 timestamp, bytes32 dataHash);
                                                            /**
                                                             *  @dev    Gets security admin address.
                                                             *  @return securityAdmin_ The address of the security admin.
                                                             */
                                                            function securityAdmin() external view returns (address securityAdmin_);
                                                            /**
                                                             *  @dev    Gets the time lock parameters for a given contract and function.
                                                             *  @param  contract_   The address of the contract to query.
                                                             *  @param  functionId_ The id of the function to query.
                                                             *  @return delay       The time lock delay.
                                                             *  @return duration    The time lock duration.
                                                             */
                                                            function timelockParametersOf(address contract_, bytes32 functionId_) external view returns (uint128 delay, uint128 duration);
                                                            /**************************************************************************************************************************************/
                                                            /*** Governor Transfer Functions                                                                                                    ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev Accepts the governorship if the caller is the `pendingGovernor`.
                                                             */
                                                            function acceptGovernor() external;
                                                            /**
                                                             *  @dev   Sets the pending governor.
                                                             *  @param pendingGovernor_ The new pending governor.
                                                             */
                                                            function setPendingGovernor(address pendingGovernor_) external;
                                                            /**************************************************************************************************************************************/
                                                            /*** Global Setters                                                                                                                 ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev   Activates the pool manager.
                                                             *  @param poolManager_ The address of the pool manager to activate.
                                                             */
                                                            function activatePoolManager(address poolManager_) external;
                                                            /**
                                                             *  @dev   Sets the virtualized first mint that acts as as offset to `totalAssets` and `totalSupply`
                                                             *         to prevent an MEV-exploit vector against the first pool depositor.
                                                             *  @param asset_         The address of the pool asset.
                                                             *  @param bootstrapMint_ The amount of shares that will offset `totalAssets` and `totalSupply`.
                                                             */
                                                            function setBootstrapMint(address asset_, uint256 bootstrapMint_) external;
                                                            /**
                                                             *  @dev   Sets the default time lock parameters.
                                                             *  @param defaultTimelockDelay_    The default time lock delay.
                                                             *  @param defaultTimelockDuration_ The default time lock duration.
                                                             */
                                                            function setDefaultTimelockParameters(uint128 defaultTimelockDelay_, uint128 defaultTimelockDuration_) external;
                                                            /**
                                                             *  @dev   Sets the address of the Maple treasury.
                                                             *  @param mapleTreasury_ The address of the Maple treasury.
                                                             */
                                                            function setMapleTreasury(address mapleTreasury_) external;
                                                            /**
                                                             *  @dev   Sets the address of the migration admin.
                                                             *  @param migrationAdmin_ The address of the migration admin.
                                                             */
                                                            function setMigrationAdmin(address migrationAdmin_) external;
                                                            /**
                                                             *  @dev   Sets the address of the operational admin.
                                                             *  @param operationalAdmin_ The address of the operational admin.
                                                             */
                                                            function setOperationalAdmin(address operationalAdmin_) external;
                                                            /**
                                                             *  @dev   Sets the price oracle for the given asset.
                                                             *  @param asset_    The address of the asset to set the oracle for.
                                                             *  @param oracle_   The address of the oracle to set for the asset.
                                                             *  @param maxDelay_ Maximum delay set to check for stale price.
                                                             */
                                                            function setPriceOracle(address asset_, address oracle_, uint96 maxDelay_) external;
                                                            /**
                                                             *  @dev   Sets the address of the security admin.
                                                             *  @param securityAdmin_ The address of the security admin.
                                                             */
                                                            function setSecurityAdmin(address securityAdmin_) external;
                                                            /**************************************************************************************************************************************/
                                                            /*** Boolean Setters                                                                                                                ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev   Sets whether a contract is uniquely paused.
                                                             *  @param contract_       The address of a contract in the protocol.
                                                             *  @param contractPaused_ Whether the contract is uniquely paused.
                                                             */
                                                            function setContractPause(address contract_, bool contractPaused_) external;
                                                            /**
                                                             *  @dev   Sets whether a contract's function is uniquely unpaused. A false does not imply it is paused.
                                                             *  @param contract_         The address of a contract in the protocol.
                                                             *  @param sig_              The function signature within the contract.
                                                             *  @param functionUnpaused_ Whether the contract's function is uniquely unpaused.
                                                             */
                                                            function setFunctionUnpause(address contract_, bytes4 sig_, bool functionUnpaused_) external;
                                                            /**
                                                             *  @dev   Sets the protocol pause.
                                                             *  @param protocolPaused_ A boolean indicating the status of the protocol pause.
                                                             */
                                                            function setProtocolPause(bool protocolPaused_) external;
                                                            /**************************************************************************************************************************************/
                                                            /*** Allowlist Setters                                                                                                              ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev   Sets whether an account can deploying an instance from a particular factory.
                                                             *  @param factory_       The address of the factory.
                                                             *  @param account_       The address of the account.
                                                             *  @param canDeployFrom_ Whether the account can deploy or not from the factory.
                                                             */
                                                            function setCanDeployFrom(address factory_, address account_, bool canDeployFrom_) external;
                                                            /**
                                                             *  @dev   Sets the validity of the borrower.
                                                             *  @param borrower_ The address of the borrower to set the validity for.
                                                             *  @param isValid_  A boolean indicating the validity of the borrower.
                                                             */
                                                            function setValidBorrower(address borrower_, bool isValid_) external;
                                                            /**
                                                             *  @dev   Sets the validity of a collateral asset.
                                                             *  @param collateralAsset_ The address of the collateral asset to set the validity for.
                                                             *  @param isValid_         A boolean indicating the validity of the collateral asset.
                                                             */
                                                            function setValidCollateralAsset(address collateralAsset_, bool isValid_) external;
                                                            /**
                                                             *  @dev   Sets the validity of the instance.
                                                             *  @param instanceKey_ The key of the instance to set the validity for.
                                                             *  @param instance_    The address of the instance to set the validity for.
                                                             *  @param isValid_     Boolean indicating the validity of the instance.
                                                             */
                                                            function setValidInstanceOf(bytes32 instanceKey_, address instance_, bool isValid_) external;
                                                            /**
                                                             *  @dev   Sets the validity of the pool asset.
                                                             *  @param poolAsset_ The address of the pool asset to set the validity for.
                                                             *  @param isValid_   A boolean indicating the validity of the pool asset.
                                                             */
                                                            function setValidPoolAsset(address poolAsset_, bool isValid_) external;
                                                            /**
                                                             *  @dev   Sets the validity of the pool delegate.
                                                             *  @param poolDelegate_ The address of the pool delegate to set the validity for.
                                                             *  @param isValid_      A boolean indicating the validity of the pool delegate.
                                                             */
                                                            function setValidPoolDelegate(address poolDelegate_, bool isValid_) external;
                                                            /**
                                                             *  @dev   Sets the validity of the pool deployer.
                                                             *  @param account_        The address of the pool deployer to set the validity for.
                                                             *  @param isPoolDeployer_ A boolean indicating the validity of the pool deployer.
                                                             */
                                                            function setValidPoolDeployer(address account_, bool isPoolDeployer_) external;
                                                            /**************************************************************************************************************************************/
                                                            /*** Price Setters                                                                                                                  ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev   Sets the manual override price of the asset.
                                                             *  @param asset_ The address of the asset to set the price for.
                                                             *  @param price_ The price of the asset.
                                                             */
                                                            function setManualOverridePrice(address asset_, uint256 price_) external;
                                                            /**************************************************************************************************************************************/
                                                            /*** Cover Setters                                                                                                                  ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev   Sets the maximum cover liquidation percent for the given pool manager.
                                                             *  @param poolManager_                The address of the pool manager to set the maximum cover liquidation percent for.
                                                             *  @param maxCoverLiquidationPercent_ The maximum cover liquidation percent.
                                                             */
                                                            function setMaxCoverLiquidationPercent(address poolManager_, uint256 maxCoverLiquidationPercent_) external;
                                                            /**
                                                             *  @dev   Sets the minimum cover amount for the given pool manager.
                                                             *  @param poolManager_    The address of the pool manager to set the minimum cover amount  for.
                                                             *  @param minCoverAmount_ The minimum cover amount.
                                                             */
                                                            function setMinCoverAmount(address poolManager_, uint256 minCoverAmount_) external;
                                                            /**************************************************************************************************************************************/
                                                            /*** Fee Setters                                                                                                                    ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev   Sets the platform management fee rate for the given pool manager.
                                                             *  @param poolManager_               The address of the pool manager to set the fee for.
                                                             *  @param platformManagementFeeRate_ The platform management fee rate.
                                                             */
                                                            function setPlatformManagementFeeRate(address poolManager_, uint256 platformManagementFeeRate_) external;
                                                            /**
                                                             *  @dev   Sets the platform origination fee rate for the given pool manager.
                                                             *  @param poolManager_                The address of the pool manager to set the fee for.
                                                             *  @param platformOriginationFeeRate_ The platform origination fee rate.
                                                             */
                                                            function setPlatformOriginationFeeRate(address poolManager_, uint256 platformOriginationFeeRate_) external;
                                                            /**
                                                             *  @dev   Sets the platform service fee rate for the given pool manager.
                                                             *  @param poolManager_            The address of the pool manager to set the fee for.
                                                             *  @param platformServiceFeeRate_ The platform service fee rate.
                                                             */
                                                            function setPlatformServiceFeeRate(address poolManager_, uint256 platformServiceFeeRate_) external;
                                                            /**************************************************************************************************************************************/
                                                            /*** Contact Control Functions                                                                                                      ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev   Sets the timelock for the given contract.
                                                             *  @param contract_   The address of the contract to add.
                                                             *  @param functionId_ The id of the function.
                                                             *  @param delay_      The delay for the timelock window.
                                                             *  @param duration_   The duration for the timelock window.
                                                             */
                                                            function setTimelockWindow(address contract_, bytes32 functionId_, uint128 delay_, uint128 duration_) external;
                                                            /**
                                                             *  @dev   Sets the timelock for the many function ids in a contract.
                                                             *  @param contract_    The address of the contract to add.
                                                             *  @param functionIds_ The ids of the functions.
                                                             *  @param delays_      The delays for the timelock window.
                                                             *  @param durations_   The durations for the timelock window.
                                                             */
                                                            function setTimelockWindows(
                                                                address            contract_,
                                                                bytes32[] calldata functionIds_,
                                                                uint128[] calldata delays_,
                                                                uint128[] calldata durations_
                                                            ) external;
                                                            /**
                                                             *  @dev   Transfer the ownership of the pool manager.
                                                             *  @param fromPoolDelegate_ The address of the pool delegate to transfer ownership from.
                                                             *  @param toPoolDelegate_   The address of the pool delegate to transfer ownership to.
                                                             */
                                                            function transferOwnedPoolManager(address fromPoolDelegate_, address toPoolDelegate_) external;
                                                            /**************************************************************************************************************************************/
                                                            /*** Schedule Functions                                                                                                             ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev    Checks if a call is scheduled.
                                                             *  @param  caller_     The contract to execute the call on.
                                                             *  @param  contract_   The contract to execute the call on.
                                                             *  @param  functionId_ The id of the function to execute.
                                                             *  @param  callData_   The of the parameters to pass to the function.
                                                             *  @return isValid_    True if the call is scheduled, false otherwise.
                                                             */
                                                            function isValidScheduledCall(
                                                                address          caller_,
                                                                address          contract_,
                                                                bytes32          functionId_,
                                                                bytes   calldata callData_
                                                            ) external view returns (bool isValid_);
                                                            /**
                                                             *  @dev   Schedules a call to be executed.
                                                             *  @param contract_   The contract to execute the call on.
                                                             *  @param functionId_ The id of the function to execute.
                                                             *  @param callData_   The of the parameters to pass to the function.
                                                             */
                                                            function scheduleCall(address contract_, bytes32 functionId_, bytes calldata callData_) external;
                                                            /**
                                                             *  @dev   Unschedules a call to be executed.
                                                             *  @param caller_     The contract to execute the call on.
                                                             *  @param functionId_ The id of the function to execute.
                                                             *  @param callData_   The of the parameters to pass to the function.
                                                             */
                                                            function unscheduleCall(address caller_, bytes32 functionId_, bytes calldata callData_) external;
                                                            /**
                                                             *  @dev   Unschedules a call to be executed.
                                                             *  @param caller_     The contract to execute the call on.
                                                             *  @param contract_   The contract to execute the call on.
                                                             *  @param functionId_ The id of the function to execute.
                                                             *  @param callData_   The of the parameters to pass to the function.
                                                             */
                                                            function unscheduleCall(address caller_, address contract_, bytes32 functionId_, bytes calldata callData_) external;
                                                        }
                                                        // SPDX-License-Identifier: BUSL-1.1
                                                        pragma solidity ^0.8.0;
                                                        interface IChainlinkAggregatorV3Like {
                                                            function latestRoundData()
                                                                external
                                                                view
                                                                returns (
                                                                    uint80  roundId_,
                                                                    int256  price_,
                                                                    uint256 startedAt_,
                                                                    uint256 updatedAt_,
                                                                    uint80  answeredInRound_
                                                                );
                                                        }
                                                        interface IPoolLike {
                                                            function manager() external view returns (address manager_);
                                                        }
                                                        interface IPoolManagerLike {
                                                            function factory() external view returns (address factory_);
                                                            function poolDelegate() external view returns (address poolDelegate_);
                                                            function setActive(bool active_) external;
                                                        }
                                                        interface IProxyLike {
                                                            function factory() external view returns (address factory_);
                                                        }
                                                        interface IProxyFactoryLike {
                                                            function isInstance(address instance_) external view returns (bool isInstance_);
                                                        }
                                                        // SPDX-License-Identifier: AGPL-3.0-or-later
                                                        pragma solidity ^0.8.7;
                                                        interface INonTransparentProxied {
                                                            /**
                                                             *  @dev    Returns the proxy's admin address.
                                                             *  @return admin_ The address of the admin.
                                                             */
                                                            function admin() external view returns (address admin_);
                                                            /**
                                                             *  @dev    Returns the proxy's implementation address.
                                                             *  @return implementation_ The address of the implementation.
                                                             */
                                                            function implementation() external view returns (address implementation_);
                                                        }
                                                        

                                                        File 9 of 13: Proxy
                                                        // SPDX-License-Identifier: AGPL-3.0-only
                                                        pragma solidity ^0.8.7;
                                                        import { IDefaultImplementationBeacon } from "./interfaces/IDefaultImplementationBeacon.sol";
                                                        import { SlotManipulatable } from "./SlotManipulatable.sol";
                                                        /// @title A completely transparent, and thus interface-less, proxy contract.
                                                        contract Proxy is SlotManipulatable {
                                                            /// @dev Storage slot with the address of the current factory. `keccak256('eip1967.proxy.factory') - 1`.
                                                            bytes32 private constant FACTORY_SLOT = bytes32(0x7a45a402e4cb6e08ebc196f20f66d5d30e67285a2a8aa80503fa409e727a4af1);
                                                            /// @dev Storage slot with the address of the current factory. `keccak256('eip1967.proxy.implementation') - 1`.
                                                            bytes32 private constant IMPLEMENTATION_SLOT = bytes32(0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc);
                                                            /**
                                                             *  @dev   The constructor requires at least one of `factory_` or `implementation_`.
                                                             *         If an implementation is not provided, the factory is treated as an IDefaultImplementationBeacon to fetch the default implementation.
                                                             *  @param factory_        The address of a proxy factory, if any.
                                                             *  @param implementation_ The address of the implementation contract being proxied, if any.
                                                             */
                                                            constructor(address factory_, address implementation_) {
                                                                _setSlotValue(FACTORY_SLOT, bytes32(uint256(uint160(factory_))));
                                                                // If the implementation is empty, fetch it from the factory, which can act as a beacon.
                                                                address implementation = implementation_ == address(0) ? IDefaultImplementationBeacon(factory_).defaultImplementation() : implementation_;
                                                                require(implementation != address(0));
                                                                _setSlotValue(IMPLEMENTATION_SLOT, bytes32(uint256(uint160(implementation))));
                                                            }
                                                            fallback() payable external virtual {
                                                                bytes32 implementation = _getSlotValue(IMPLEMENTATION_SLOT);
                                                                require(address(uint160(uint256(implementation))).code.length != uint256(0));
                                                                assembly {
                                                                    calldatacopy(0, 0, calldatasize())
                                                                    let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                                                                    returndatacopy(0, 0, returndatasize())
                                                                    switch result
                                                                    case 0 {
                                                                        revert(0, returndatasize())
                                                                    }
                                                                    default {
                                                                        return(0, returndatasize())
                                                                    }
                                                                }
                                                            }
                                                        }
                                                        // SPDX-License-Identifier: AGPL-3.0-only
                                                        pragma solidity ^0.8.7;
                                                        abstract contract SlotManipulatable {
                                                            function _getReferenceTypeSlot(bytes32 slot_, bytes32 key_) internal pure returns (bytes32 value_) {
                                                                return keccak256(abi.encodePacked(key_, slot_));
                                                            }
                                                            function _getSlotValue(bytes32 slot_) internal view returns (bytes32 value_) {
                                                                assembly {
                                                                    value_ := sload(slot_)
                                                                }
                                                            }
                                                            function _setSlotValue(bytes32 slot_, bytes32 value_) internal {
                                                                assembly {
                                                                    sstore(slot_, value_)
                                                                }
                                                            }
                                                        }
                                                        // SPDX-License-Identifier: AGPL-3.0-only
                                                        pragma solidity ^0.8.7;
                                                        /// @title An beacon that provides a default implementation for proxies, must implement IDefaultImplementationBeacon.
                                                        interface IDefaultImplementationBeacon {
                                                            /// @dev The address of an implementation for proxies.
                                                            function defaultImplementation() external view returns (address defaultImplementation_);
                                                        }
                                                        

                                                        File 10 of 13: MaplePoolManager
                                                        // SPDX-License-Identifier: BUSL-1.1
                                                        pragma solidity ^0.8.25;
                                                        import { ERC20Helper }           from "../modules/erc20-helper/src/ERC20Helper.sol";
                                                        import { IMapleProxyFactory }    from "../modules/maple-proxy-factory/contracts/interfaces/IMapleProxyFactory.sol";
                                                        import { IMapleProxied }         from "../modules/maple-proxy-factory/contracts/interfaces/IMapleProxied.sol";
                                                        import { MapleProxiedInternals } from "../modules/maple-proxy-factory/contracts/MapleProxiedInternals.sol";
                                                        import { MaplePoolManagerStorage } from "./proxy/MaplePoolManagerStorage.sol";
                                                        import {
                                                            IERC20Like,
                                                            IGlobalsLike,
                                                            ILoanLike,
                                                            ILoanManagerLike,
                                                            IPoolDelegateCoverLike,
                                                            IPoolLike,
                                                            IPoolPermissionManagerLike,
                                                            IStrategyLike,
                                                            IWithdrawalManagerLike
                                                        } from "./interfaces/Interfaces.sol";
                                                        import { IMaplePoolManager } from "./interfaces/IMaplePoolManager.sol";
                                                        /*
                                                           ███╗   ███╗ █████╗ ██████╗ ██╗     ███████╗
                                                           ████╗ ████║██╔══██╗██╔══██╗██║     ██╔════╝
                                                           ██╔████╔██║███████║██████╔╝██║     █████╗
                                                           ██║╚██╔╝██║██╔══██║██╔═══╝ ██║     ██╔══╝
                                                           ██║ ╚═╝ ██║██║  ██║██║     ███████╗███████╗
                                                           ╚═╝     ╚═╝╚═╝  ╚═╝╚═╝     ╚══════╝╚══════╝
                                                           ██████╗  ██████╗  ██████╗ ██╗         ███╗   ███╗ █████╗ ███╗   ██╗ █████╗  ██████╗ ███████╗██████╗
                                                           ██╔══██╗██╔═══██╗██╔═══██╗██║         ████╗ ████║██╔══██╗████╗  ██║██╔══██╗██╔════╝ ██╔════╝██╔══██╗
                                                           ██████╔╝██║   ██║██║   ██║██║         ██╔████╔██║███████║██╔██╗ ██║███████║██║  ███╗█████╗  ██████╔╝
                                                           ██╔═══╝ ██║   ██║██║   ██║██║         ██║╚██╔╝██║██╔══██║██║╚██╗██║██╔══██║██║   ██║██╔══╝  ██╔══██╗
                                                           ██║     ╚██████╔╝╚██████╔╝███████╗    ██║ ╚═╝ ██║██║  ██║██║ ╚████║██║  ██║╚██████╔╝███████╗██║  ██║
                                                           ╚═╝      ╚═════╝  ╚═════╝ ╚══════╝    ╚═╝     ╚═╝╚═╝  ╚═╝╚═╝  ╚═══╝╚═╝  ╚═╝ ╚═════╝ ╚══════╝╚═╝  ╚═╝
                                                        */
                                                        contract MaplePoolManager is IMaplePoolManager, MapleProxiedInternals, MaplePoolManagerStorage {
                                                            uint256 public constant HUNDRED_PERCENT = 100_0000;  // Four decimal precision.
                                                            /**************************************************************************************************************************************/
                                                            /*** Modifiers                                                                                                                      ***/
                                                            /**************************************************************************************************************************************/
                                                            modifier nonReentrant() {
                                                                require(_locked == 1, "PM:LOCKED");
                                                                _locked = 2;
                                                                _;
                                                                _locked = 1;
                                                            }
                                                            modifier onlyIfNotConfigured() {
                                                                _revertIfConfigured();
                                                                _;
                                                            }
                                                            modifier onlyProtocolAdminsOrNotConfigured() {
                                                                _revertIfConfiguredAndNotProtocolAdmins();
                                                                _;
                                                            }
                                                            modifier onlyPool() {
                                                                _revertIfNotPool();
                                                                _;
                                                            }
                                                            modifier onlyPoolDelegate() {
                                                                _revertIfNotPoolDelegate();
                                                                _;
                                                            }
                                                            modifier onlyPoolDelegateOrProtocolAdmins() {
                                                                _revertIfNeitherPoolDelegateNorProtocolAdmins();
                                                                _;
                                                            }
                                                            modifier whenNotPaused() {
                                                                _revertIfPaused();
                                                                _;
                                                            }
                                                            /**************************************************************************************************************************************/
                                                            /*** Migration Functions                                                                                                            ***/
                                                            /**************************************************************************************************************************************/
                                                            // NOTE: Can't add whenProtocolNotPaused modifier here, as globals won't be set until
                                                            //       initializer.initialize() is called, and this function is what triggers that initialization.
                                                            function migrate(address migrator_, bytes calldata arguments_) external override whenNotPaused {
                                                                require(msg.sender == _factory(),        "PM:M:NOT_FACTORY");
                                                                require(_migrate(migrator_, arguments_), "PM:M:FAILED");
                                                                require(poolDelegateCover != address(0), "PM:M:DELEGATE_NOT_SET");
                                                            }
                                                            function setImplementation(address implementation_) external override whenNotPaused {
                                                                require(msg.sender == _factory(), "PM:SI:NOT_FACTORY");
                                                                _setImplementation(implementation_);
                                                            }
                                                            function upgrade(uint256 version_, bytes calldata arguments_) external override whenNotPaused {
                                                                IGlobalsLike globals_ = IGlobalsLike(globals());
                                                                if (msg.sender == poolDelegate) {
                                                                    require(globals_.isValidScheduledCall(msg.sender, address(this), "PM:UPGRADE", msg.data), "PM:U:INVALID_SCHED_CALL");
                                                                    globals_.unscheduleCall(msg.sender, "PM:UPGRADE", msg.data);
                                                                } else {
                                                                    require(msg.sender == globals_.securityAdmin(), "PM:U:NO_AUTH");
                                                                }
                                                                emit Upgraded(version_, arguments_);
                                                                IMapleProxyFactory(_factory()).upgradeInstance(version_, arguments_);
                                                            }
                                                            /**************************************************************************************************************************************/
                                                            /*** Initial Configuration Function                                                                                                 ***/
                                                            /**************************************************************************************************************************************/
                                                            // NOTE: This function is always called atomically during the deployment process so a DoS attack is not possible.
                                                            function completeConfiguration() external override whenNotPaused onlyIfNotConfigured {
                                                                configured = true;
                                                                emit PoolConfigurationComplete();
                                                            }
                                                            /**************************************************************************************************************************************/
                                                            /*** Ownership Transfer Functions                                                                                                   ***/
                                                            /**************************************************************************************************************************************/
                                                            function acceptPoolDelegate() external override whenNotPaused {
                                                                require(msg.sender == pendingPoolDelegate, "PM:APD:NOT_PENDING_PD");
                                                                IGlobalsLike(globals()).transferOwnedPoolManager(poolDelegate, msg.sender);
                                                                emit PendingDelegateAccepted(poolDelegate, pendingPoolDelegate);
                                                                poolDelegate        = pendingPoolDelegate;
                                                                pendingPoolDelegate = address(0);
                                                            }
                                                            function setPendingPoolDelegate(address pendingPoolDelegate_) external override whenNotPaused onlyPoolDelegateOrProtocolAdmins {
                                                                pendingPoolDelegate = pendingPoolDelegate_;
                                                                emit PendingDelegateSet(poolDelegate, pendingPoolDelegate_);
                                                            }
                                                            /**************************************************************************************************************************************/
                                                            /*** Globals Admin Functions                                                                                                        ***/
                                                            /**************************************************************************************************************************************/
                                                            function setActive(bool active_) external override whenNotPaused {
                                                                require(msg.sender == globals(), "PM:SA:NOT_GLOBALS");
                                                                emit SetAsActive(active = active_);
                                                            }
                                                            /**************************************************************************************************************************************/
                                                            /*** Pool Delegate Admin Functions                                                                                                  ***/
                                                            /**************************************************************************************************************************************/
                                                            function addStrategy(address strategyFactory_, bytes calldata extraDeploymentData_)
                                                                external override whenNotPaused onlyProtocolAdminsOrNotConfigured returns (address strategy_)
                                                            {
                                                                require(IGlobalsLike(globals()).isInstanceOf("STRATEGY_FACTORY", strategyFactory_), "PM:AS:INVALID_FACTORY");
                                                                // NOTE: If removing strategies is allowed in the future, there will be a need to rethink salts here due to collisions.
                                                                strategy_ = IMapleProxyFactory(strategyFactory_).createInstance(
                                                                    bytes.concat(abi.encode(address(this)), extraDeploymentData_),
                                                                    keccak256(abi.encode(address(this), strategyList.length))
                                                                );
                                                                isStrategy[strategy_] = true;
                                                                strategyList.push(strategy_);
                                                                emit StrategyAdded(strategy_);
                                                            }
                                                            function setDelegateManagementFeeRate(uint256 delegateManagementFeeRate_)
                                                                external override whenNotPaused onlyProtocolAdminsOrNotConfigured
                                                            {
                                                                require(delegateManagementFeeRate_ <= HUNDRED_PERCENT, "PM:SDMFR:OOB");
                                                                emit DelegateManagementFeeRateSet(delegateManagementFeeRate = delegateManagementFeeRate_);
                                                            }
                                                            function setIsStrategy(address strategy_, bool isStrategy_) external override whenNotPaused onlyPoolDelegateOrProtocolAdmins {
                                                                emit IsStrategySet(strategy_, isStrategy[strategy_] = isStrategy_);
                                                                // Check Strategy is in the list.
                                                                // NOTE: The factory and instance check are not required as the mapping is being updated for a Strategy that is in the list.
                                                                for (uint256 i_; i_ < strategyList.length; ++i_) {
                                                                    if (strategyList[i_] == strategy_) return;
                                                                }
                                                                revert("PM:SIS:INVALID_STRATEGY");
                                                            }
                                                            function setLiquidityCap(uint256 liquidityCap_) external override whenNotPaused onlyProtocolAdminsOrNotConfigured {
                                                                emit LiquidityCapSet(liquidityCap = liquidityCap_);
                                                            }
                                                            function setWithdrawalManager(address withdrawalManager_) external override whenNotPaused onlyIfNotConfigured {
                                                                address factory_ = IMapleProxied(withdrawalManager_).factory();
                                                                require(IGlobalsLike(globals()).isInstanceOf("WITHDRAWAL_MANAGER_FACTORY", factory_), "PM:SWM:INVALID_FACTORY");
                                                                require(IMapleProxyFactory(factory_).isInstance(withdrawalManager_),                  "PM:SWM:INVALID_INSTANCE");
                                                                emit WithdrawalManagerSet(withdrawalManager = withdrawalManager_);
                                                            }
                                                            function setPoolPermissionManager(address poolPermissionManager_) external override whenNotPaused onlyProtocolAdminsOrNotConfigured {
                                                                require(IGlobalsLike(globals()).isInstanceOf("POOL_PERMISSION_MANAGER", poolPermissionManager_), "PM:SPPM:INVALID_INSTANCE");
                                                                emit PoolPermissionManagerSet(poolPermissionManager = poolPermissionManager_);
                                                            }
                                                            /**************************************************************************************************************************************/
                                                            /*** Funding Functions                                                                                                              ***/
                                                            /**************************************************************************************************************************************/
                                                            function requestFunds(address destination_, uint256 principal_) external override whenNotPaused nonReentrant {
                                                                address asset_   = asset;
                                                                address pool_    = pool;
                                                                address factory_ = IMapleProxied(msg.sender).factory();
                                                                IGlobalsLike globals_ = IGlobalsLike(globals());
                                                                // NOTE: Do not need to check isInstance() as the Strategy is added to the list on `addStrategy()` or `configure()`.
                                                                require(principal_ != 0,                                     "PM:RF:INVALID_PRINCIPAL");
                                                                require(globals_.isInstanceOf("STRATEGY_FACTORY", factory_), "PM:RF:INVALID_FACTORY");
                                                                require(IMapleProxyFactory(factory_).isInstance(msg.sender), "PM:RF:INVALID_INSTANCE");
                                                                require(isStrategy[msg.sender],                              "PM:RF:NOT_STRATEGY");
                                                                require(IERC20Like(pool_).totalSupply() != 0,                "PM:RF:ZERO_SUPPLY");
                                                                require(_hasSufficientCover(address(globals_), asset_),      "PM:RF:INSUFFICIENT_COVER");
                                                                // Fetching locked liquidity needs to be done prior to transferring the tokens.
                                                                uint256 lockedLiquidity_ = IWithdrawalManagerLike(withdrawalManager).lockedLiquidity();
                                                                // Transfer the required principal.
                                                                require(destination_ != address(0),                                        "PM:RF:INVALID_DESTINATION");
                                                                require(ERC20Helper.transferFrom(asset_, pool_, destination_, principal_), "PM:RF:TRANSFER_FAIL");
                                                                // The remaining liquidity in the pool must be greater or equal to the locked liquidity.
                                                                require(IERC20Like(asset_).balanceOf(pool_) >= lockedLiquidity_, "PM:RF:LOCKED_LIQUIDITY");
                                                            }
                                                            /**************************************************************************************************************************************/
                                                            /*** Loan Default Functions                                                                                                         ***/
                                                            /**************************************************************************************************************************************/
                                                            function finishCollateralLiquidation(address loan_) external override whenNotPaused nonReentrant onlyPoolDelegateOrProtocolAdmins {
                                                                ( uint256 losses_, uint256 platformFees_ ) = ILoanManagerLike(_getLoanManager(loan_)).finishCollateralLiquidation(loan_);
                                                                _handleCover(losses_, platformFees_);
                                                                emit CollateralLiquidationFinished(loan_, losses_);
                                                            }
                                                            function triggerDefault(address loan_, address liquidatorFactory_)
                                                                external override whenNotPaused nonReentrant onlyPoolDelegateOrProtocolAdmins
                                                            {
                                                                require(IGlobalsLike(globals()).isInstanceOf("LIQUIDATOR_FACTORY", liquidatorFactory_), "PM:TD:NOT_FACTORY");
                                                                (
                                                                    bool    liquidationComplete_,
                                                                    uint256 losses_,
                                                                    uint256 platformFees_
                                                                ) = ILoanManagerLike(_getLoanManager(loan_)).triggerDefault(loan_, liquidatorFactory_);
                                                                if (!liquidationComplete_) {
                                                                    emit CollateralLiquidationTriggered(loan_);
                                                                    return;
                                                                }
                                                                _handleCover(losses_, platformFees_);
                                                                emit CollateralLiquidationFinished(loan_, losses_);
                                                            }
                                                            /**************************************************************************************************************************************/
                                                            /*** Pool Exit Functions                                                                                                            ***/
                                                            /**************************************************************************************************************************************/
                                                            function processRedeem(uint256 shares_, address owner_, address sender_)
                                                                external override whenNotPaused nonReentrant onlyPool returns (uint256 redeemableShares_, uint256 resultingAssets_)
                                                            {
                                                                require(owner_ == sender_ || IPoolLike(pool).allowance(owner_, sender_) > 0, "PM:PR:NO_ALLOWANCE");
                                                                ( redeemableShares_, resultingAssets_ ) = IWithdrawalManagerLike(withdrawalManager).processExit(shares_, owner_);
                                                                emit RedeemProcessed(owner_, redeemableShares_, resultingAssets_);
                                                            }
                                                            function processWithdraw(uint256 assets_, address owner_, address sender_)
                                                                external override whenNotPaused nonReentrant returns (uint256 redeemableShares_, uint256 resultingAssets_)
                                                            {
                                                                assets_; owner_; sender_; redeemableShares_; resultingAssets_;  // Silence compiler warnings
                                                                require(false, "PM:PW:NOT_ENABLED");
                                                            }
                                                            function removeShares(uint256 shares_, address owner_)
                                                                external override whenNotPaused nonReentrant onlyPool returns (uint256 sharesReturned_)
                                                            {
                                                                emit SharesRemoved(
                                                                    owner_,
                                                                    sharesReturned_ = IWithdrawalManagerLike(withdrawalManager).removeShares(shares_, owner_)
                                                                );
                                                            }
                                                            function requestRedeem(uint256 shares_, address owner_, address sender_) external override whenNotPaused nonReentrant onlyPool {
                                                                address pool_ = pool;
                                                                require(ERC20Helper.approve(pool_, withdrawalManager, shares_), "PM:RR:APPROVE_FAIL");
                                                                if (sender_ != owner_ && shares_ == 0) {
                                                                    require(IPoolLike(pool_).allowance(owner_, sender_) > 0, "PM:RR:NO_ALLOWANCE");
                                                                }
                                                                IWithdrawalManagerLike(withdrawalManager).addShares(shares_, owner_);
                                                                emit RedeemRequested(owner_, shares_);
                                                            }
                                                            function requestWithdraw(uint256 shares_, uint256 assets_, address owner_, address sender_)
                                                                external override whenNotPaused nonReentrant
                                                            {
                                                                shares_; assets_; owner_; sender_;  // Silence compiler warnings
                                                                require(false, "PM:RW:NOT_ENABLED");
                                                            }
                                                            /**************************************************************************************************************************************/
                                                            /*** Pool Delegate Cover Functions                                                                                                  ***/
                                                            /**************************************************************************************************************************************/
                                                            function depositCover(uint256 amount_) external override whenNotPaused {
                                                                require(ERC20Helper.transferFrom(asset, msg.sender, poolDelegateCover, amount_), "PM:DC:TRANSFER_FAIL");
                                                                emit CoverDeposited(amount_);
                                                            }
                                                            function withdrawCover(uint256 amount_, address recipient_) external override whenNotPaused onlyPoolDelegate {
                                                                recipient_ = recipient_ == address(0) ? msg.sender : recipient_;
                                                                IPoolDelegateCoverLike(poolDelegateCover).moveFunds(amount_, recipient_);
                                                                require(
                                                                    IERC20Like(asset).balanceOf(poolDelegateCover) >= IGlobalsLike(globals()).minCoverAmount(address(this)),
                                                                    "PM:WC:BELOW_MIN"
                                                                );
                                                                emit CoverWithdrawn(amount_);
                                                            }
                                                            /**************************************************************************************************************************************/
                                                            /*** View Functions                                                                                                                 ***/
                                                            /**************************************************************************************************************************************/
                                                            function canCall(bytes32 functionId_, address caller_, bytes calldata data_)
                                                                external view override returns (bool canCall_, string memory errorMessage_)
                                                            {
                                                                if (IGlobalsLike(globals()).isFunctionPaused(msg.sig)) return (false, "PM:CC:PAUSED");
                                                                uint256[3] memory params_ = _decodeParameters(data_);
                                                                uint256 assets_ = params_[0];
                                                                address lender_ = _address(params_[1]);
                                                                // For mint functions there's a need to convert shares into assets.
                                                                if (functionId_ == "P:mint" || functionId_ == "P:mintWithPermit") assets_ = IPoolLike(pool).previewMint(params_[0]);
                                                                // Redeem and withdraw require getting the third word from the calldata.
                                                                if ( functionId_ == "P:redeem" || functionId_ == "P:withdraw") lender_ = _address(params_[2]);
                                                                // Transfers need to check both the sender and the recipient.
                                                                if (functionId_ == "P:transfer" || functionId_ == "P:transferFrom") {
                                                                    address[] memory lenders_ = new address[](2);
                                                                    ( lenders_[0], lenders_[1] ) = functionId_ == "P:transfer" ?
                                                                        (caller_,              _address(params_[0])) :
                                                                        (_address(params_[0]), _address(params_[1]));
                                                                    // Check both lenders in a single call.
                                                                    if (!IPoolPermissionManagerLike(poolPermissionManager).hasPermission(address(this), lenders_, functionId_)) {
                                                                        return (false, "PM:CC:NOT_ALLOWED");
                                                                    }
                                                                } else {
                                                                    if (!IPoolPermissionManagerLike(poolPermissionManager).hasPermission(address(this), lender_, functionId_)) {
                                                                        return (false, "PM:CC:NOT_ALLOWED");
                                                                    }
                                                                }
                                                                if (
                                                                    functionId_ == "P:redeem"          ||
                                                                    functionId_ == "P:withdraw"        ||
                                                                    functionId_ == "P:removeShares"    ||
                                                                    functionId_ == "P:requestRedeem"   ||
                                                                    functionId_ == "P:requestWithdraw" ||
                                                                    functionId_ == "P:transfer"        ||
                                                                    functionId_ == "P:transferFrom"
                                                                ) return (true, "");
                                                                if (
                                                                    functionId_ == "P:deposit"           ||
                                                                    functionId_ == "P:depositWithPermit" ||
                                                                    functionId_ == "P:mint"              ||
                                                                    functionId_ == "P:mintWithPermit"
                                                                ) return _canDeposit(assets_);
                                                                return (false, "PM:CC:INVALID_FUNCTION_ID");
                                                            }
                                                            function factory() external view override returns (address factory_) {
                                                                factory_ = _factory();
                                                            }
                                                            function globals() public view override returns (address globals_) {
                                                                globals_ = IMapleProxyFactory(_factory()).mapleGlobals();
                                                            }
                                                            function governor() public view override returns (address governor_) {
                                                                governor_ = IGlobalsLike(globals()).governor();
                                                            }
                                                            function hasSufficientCover() public view override returns (bool hasSufficientCover_) {
                                                                hasSufficientCover_ = _hasSufficientCover(globals(), asset);
                                                            }
                                                            function implementation() external view override returns (address implementation_) {
                                                                implementation_ = _implementation();
                                                            }
                                                            function strategyListLength() external view override returns (uint256 strategyListLength_) {
                                                                strategyListLength_ = strategyList.length;
                                                            }
                                                            function totalAssets() public view override returns (uint256 totalAssets_) {
                                                                totalAssets_ = IERC20Like(asset).balanceOf(pool);
                                                                uint256 length_ = strategyList.length;
                                                                for (uint256 i_; i_ < length_;) {
                                                                    totalAssets_ += IStrategyLike(strategyList[i_]).assetsUnderManagement();
                                                                    unchecked { ++i_; }
                                                                }
                                                            }
                                                            /**************************************************************************************************************************************/
                                                            /*** LP Token View Functions                                                                                                        ***/
                                                            /**************************************************************************************************************************************/
                                                            function convertToExitShares(uint256 assets_) public view override returns (uint256 shares_) {
                                                                shares_ = IPoolLike(pool).convertToExitShares(assets_);
                                                            }
                                                            function getEscrowParams(address, uint256 shares_) external view override returns (uint256 escrowShares_, address destination_) {
                                                                // NOTE: `owner_` param not named to avoid compiler warning.
                                                                ( escrowShares_, destination_) = (shares_, address(this));
                                                            }
                                                            function maxDeposit(address receiver_) external view virtual override returns (uint256 maxAssets_) {
                                                                maxAssets_ = _getMaxAssets(receiver_, totalAssets(), "P:deposit");
                                                            }
                                                            function maxMint(address receiver_) external view virtual override returns (uint256 maxShares_) {
                                                                uint256 totalAssets_ = totalAssets();
                                                                uint256 maxAssets_   = _getMaxAssets(receiver_, totalAssets_, "P:mint");
                                                                maxShares_ = IPoolLike(pool).previewDeposit(maxAssets_);
                                                            }
                                                            function maxRedeem(address owner_) external view virtual override returns (uint256 maxShares_) {
                                                                uint256 lockedShares_ = IWithdrawalManagerLike(withdrawalManager).lockedShares(owner_);
                                                                maxShares_            = IWithdrawalManagerLike(withdrawalManager).isInExitWindow(owner_) ? lockedShares_ : 0;
                                                            }
                                                            function maxWithdraw(address owner_) external view virtual override returns (uint256 maxAssets_) {
                                                                owner_;          // Silence compiler warning
                                                                maxAssets_ = 0;  // NOTE: always returns 0 as withdraw is not implemented
                                                            }
                                                            function previewRedeem(address owner_, uint256 shares_) external view virtual override returns (uint256 assets_) {
                                                                ( , assets_ ) = IWithdrawalManagerLike(withdrawalManager).previewRedeem(owner_, shares_);
                                                            }
                                                            function previewWithdraw(address owner_, uint256 assets_) external view virtual override returns (uint256 shares_) {
                                                                ( , shares_ ) = IWithdrawalManagerLike(withdrawalManager).previewWithdraw(owner_, assets_);
                                                            }
                                                            function unrealizedLosses() public view override returns (uint256 unrealizedLosses_) {
                                                                uint256 length_ = strategyList.length;
                                                                for (uint256 i_; i_ < length_;) {
                                                                    unrealizedLosses_ += IStrategyLike(strategyList[i_]).unrealizedLosses();
                                                                    unchecked { ++i_; }
                                                                }
                                                                // NOTE: Use minimum to prevent underflows in the case that `unrealizedLosses` includes late interest and `totalAssets` does not.
                                                                unrealizedLosses_ = _min(unrealizedLosses_, totalAssets());
                                                            }
                                                            /**************************************************************************************************************************************/
                                                            /*** Internal Helper Functions                                                                                                      ***/
                                                            /**************************************************************************************************************************************/
                                                            function _getLoanManager(address loan_) internal view returns (address loanManager_) {
                                                                loanManager_ = ILoanLike(loan_).lender();
                                                                require(isStrategy[loanManager_], "PM:GLM:INVALID_LOAN_MANAGER");
                                                            }
                                                            function _handleCover(uint256 losses_, uint256 platformFees_) internal {
                                                                address globals_ = globals();
                                                                uint256 availableCover_ =
                                                                    IERC20Like(asset).balanceOf(poolDelegateCover) * IGlobalsLike(globals_).maxCoverLiquidationPercent(address(this)) /
                                                                    HUNDRED_PERCENT;
                                                                uint256 toTreasury_ = _min(availableCover_,               platformFees_);
                                                                uint256 toPool_     = _min(availableCover_ - toTreasury_, losses_);
                                                                if (toTreasury_ != 0) {
                                                                    IPoolDelegateCoverLike(poolDelegateCover).moveFunds(toTreasury_, IGlobalsLike(globals_).mapleTreasury());
                                                                }
                                                                if (toPool_ != 0) {
                                                                    IPoolDelegateCoverLike(poolDelegateCover).moveFunds(toPool_, pool);
                                                                }
                                                                emit CoverLiquidated(toTreasury_, toPool_);
                                                            }
                                                            /**************************************************************************************************************************************/
                                                            /*** Internal Functions                                                                                                             ***/
                                                            /**************************************************************************************************************************************/
                                                            function _address(uint256 word_) internal pure returns (address address_) {
                                                                address_ = address(uint160(word_));
                                                            }
                                                            function _canDeposit(uint256 assets_) internal view returns (bool canDeposit_, string memory errorMessage_) {
                                                                if (!active)                                return (false, "P:NOT_ACTIVE");
                                                                if (assets_ + totalAssets() > liquidityCap) return (false, "P:DEPOSIT_GT_LIQ_CAP");
                                                                return (true, "");
                                                            }
                                                            function _decodeParameters(bytes calldata data_) internal pure returns (uint256[3] memory words) {
                                                                if (data_.length > 64)  {
                                                                    ( words[0], words[1], words[2] ) = abi.decode(data_, (uint256, uint256, uint256));
                                                                } else {
                                                                    ( words[0], words[1] ) = abi.decode(data_, (uint256, uint256));
                                                                }
                                                            }
                                                            function _getMaxAssets(address receiver_, uint256 totalAssets_, bytes32 functionId_) internal view returns (uint256 maxAssets_) {
                                                                bool    depositAllowed_ = IPoolPermissionManagerLike(poolPermissionManager).hasPermission(address(this),  receiver_, functionId_);
                                                                uint256 liquidityCap_   = liquidityCap;
                                                                maxAssets_              = liquidityCap_ > totalAssets_ && depositAllowed_ ? liquidityCap_ - totalAssets_ : 0;
                                                            }
                                                            function _hasSufficientCover(address globals_, address asset_) internal view returns (bool hasSufficientCover_) {
                                                                hasSufficientCover_ = IERC20Like(asset_).balanceOf(poolDelegateCover) >= IGlobalsLike(globals_).minCoverAmount(address(this));
                                                            }
                                                            function _min(uint256 a_, uint256 b_) internal pure returns (uint256 minimum_) {
                                                                minimum_ = a_ < b_ ? a_ : b_;
                                                            }
                                                            function _revertIfConfigured() internal view {
                                                                require(!configured, "PM:ALREADY_CONFIGURED");
                                                            }
                                                            function _revertIfConfiguredAndNotProtocolAdmins() internal view {
                                                                require(
                                                                    !configured ||
                                                                    msg.sender == poolDelegate ||
                                                                    msg.sender == governor()   ||
                                                                    msg.sender == IGlobalsLike(globals()).operationalAdmin(),
                                                                    "PM:NOT_PA_OR_NOT_CONFIGURED"
                                                                );
                                                            }
                                                            function _revertIfNotPool() internal view {
                                                                require(msg.sender == pool, "PM:NOT_POOL");
                                                            }
                                                            function _revertIfNotPoolDelegate() internal view {
                                                                require(msg.sender == poolDelegate, "PM:NOT_PD");
                                                            }
                                                            function _revertIfNeitherPoolDelegateNorProtocolAdmins() internal view {
                                                                require(
                                                                    msg.sender == poolDelegate ||
                                                                    msg.sender == governor()   ||
                                                                    msg.sender == IGlobalsLike(globals()).operationalAdmin(),
                                                                    "PM:NOT_PD_OR_GOV_OR_OA"
                                                                );
                                                            }
                                                            function _revertIfPaused() internal view {
                                                                require(!IGlobalsLike(globals()).isFunctionPaused(msg.sig), "PM:PAUSED");
                                                            }
                                                        }
                                                        // SPDX-License-Identifier: AGPL-3.0-only
                                                        pragma solidity ^0.8.7;
                                                        import { IERC20Like } from "./interfaces/IERC20Like.sol";
                                                        /**
                                                         * @title Small Library to standardize erc20 token interactions.
                                                         */
                                                        library ERC20Helper {
                                                            /**************************************************************************************************************************************/
                                                            /*** Internal Functions                                                                                                             ***/
                                                            /**************************************************************************************************************************************/
                                                            function transfer(address token_, address to_, uint256 amount_) internal returns (bool success_) {
                                                                return _call(token_, abi.encodeWithSelector(IERC20Like.transfer.selector, to_, amount_));
                                                            }
                                                            function transferFrom(address token_, address from_, address to_, uint256 amount_) internal returns (bool success_) {
                                                                return _call(token_, abi.encodeWithSelector(IERC20Like.transferFrom.selector, from_, to_, amount_));
                                                            }
                                                            function approve(address token_, address spender_, uint256 amount_) internal returns (bool success_) {
                                                                // If setting approval to zero fails, return false.
                                                                if (!_call(token_, abi.encodeWithSelector(IERC20Like.approve.selector, spender_, uint256(0)))) return false;
                                                                // If `amount_` is zero, return true as the previous step already did this.
                                                                if (amount_ == uint256(0)) return true;
                                                                // Return the result of setting the approval to `amount_`.
                                                                return _call(token_, abi.encodeWithSelector(IERC20Like.approve.selector, spender_, amount_));
                                                            }
                                                            function _call(address token_, bytes memory data_) private returns (bool success_) {
                                                                if (token_.code.length == uint256(0)) return false;
                                                                bytes memory returnData;
                                                                ( success_, returnData ) = token_.call(data_);
                                                                return success_ && (returnData.length == uint256(0) || abi.decode(returnData, (bool)));
                                                            }
                                                        }
                                                        // SPDX-License-Identifier: AGPL-3.0-or-later
                                                        pragma solidity ^0.8.7;
                                                        import { IDefaultImplementationBeacon } from "../../modules/proxy-factory/contracts/interfaces/IDefaultImplementationBeacon.sol";
                                                        /// @title A Maple factory for Proxy contracts that proxy MapleProxied implementations.
                                                        interface IMapleProxyFactory is IDefaultImplementationBeacon {
                                                            /**************************************************************************************************************************************/
                                                            /*** Events                                                                                                                         ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev   A default version was set.
                                                             *  @param version_ The default version.
                                                             */
                                                            event DefaultVersionSet(uint256 indexed version_);
                                                            /**
                                                             *  @dev   A version of an implementation, at some address, was registered, with an optional initializer.
                                                             *  @param version_               The version registered.
                                                             *  @param implementationAddress_ The address of the implementation.
                                                             *  @param initializer_           The address of the initializer, if any.
                                                             */
                                                            event ImplementationRegistered(uint256 indexed version_, address indexed implementationAddress_, address indexed initializer_);
                                                            /**
                                                             *  @dev   A proxy contract was deployed with some initialization arguments.
                                                             *  @param version_                 The version of the implementation being proxied by the deployed proxy contract.
                                                             *  @param instance_                The address of the proxy contract deployed.
                                                             *  @param initializationArguments_ The arguments used to initialize the proxy contract, if any.
                                                             */
                                                            event InstanceDeployed(uint256 indexed version_, address indexed instance_, bytes initializationArguments_);
                                                            /**
                                                             *  @dev   A instance has upgraded by proxying to a new implementation, with some migration arguments.
                                                             *  @param instance_           The address of the proxy contract.
                                                             *  @param fromVersion_        The initial implementation version being proxied.
                                                             *  @param toVersion_          The new implementation version being proxied.
                                                             *  @param migrationArguments_ The arguments used to migrate, if any.
                                                             */
                                                            event InstanceUpgraded(address indexed instance_, uint256 indexed fromVersion_, uint256 indexed toVersion_, bytes migrationArguments_);
                                                            /**
                                                             *  @dev   The MapleGlobals was set.
                                                             *  @param mapleGlobals_ The address of a Maple Globals contract.
                                                             */
                                                            event MapleGlobalsSet(address indexed mapleGlobals_);
                                                            /**
                                                             *  @dev   An upgrade path was disabled, with an optional migrator contract.
                                                             *  @param fromVersion_ The starting version of the upgrade path.
                                                             *  @param toVersion_   The destination version of the upgrade path.
                                                             */
                                                            event UpgradePathDisabled(uint256 indexed fromVersion_, uint256 indexed toVersion_);
                                                            /**
                                                             *  @dev   An upgrade path was enabled, with an optional migrator contract.
                                                             *  @param fromVersion_ The starting version of the upgrade path.
                                                             *  @param toVersion_   The destination version of the upgrade path.
                                                             *  @param migrator_    The address of the migrator, if any.
                                                             */
                                                            event UpgradePathEnabled(uint256 indexed fromVersion_, uint256 indexed toVersion_, address indexed migrator_);
                                                            /**************************************************************************************************************************************/
                                                            /*** State Variables                                                                                                                ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev The default version.
                                                             */
                                                            function defaultVersion() external view returns (uint256 defaultVersion_);
                                                            /**
                                                             *  @dev The address of the MapleGlobals contract.
                                                             */
                                                            function mapleGlobals() external view returns (address mapleGlobals_);
                                                            /**
                                                             *  @dev    Whether the upgrade is enabled for a path from a version to another version.
                                                             *  @param  toVersion_   The initial version.
                                                             *  @param  fromVersion_ The destination version.
                                                             *  @return allowed_     Whether the upgrade is enabled.
                                                             */
                                                            function upgradeEnabledForPath(uint256 toVersion_, uint256 fromVersion_) external view returns (bool allowed_);
                                                            /**************************************************************************************************************************************/
                                                            /*** State Changing Functions                                                                                                       ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev    Deploys a new instance proxying the default implementation version, with some initialization arguments.
                                                             *          Uses a nonce and `msg.sender` as a salt for the CREATE2 opcode during instantiation to produce deterministic addresses.
                                                             *  @param  arguments_ The initialization arguments to use for the instance deployment, if any.
                                                             *  @param  salt_      The salt to use in the contract creation process.
                                                             *  @return instance_  The address of the deployed proxy contract.
                                                             */
                                                            function createInstance(bytes calldata arguments_, bytes32 salt_) external returns (address instance_);
                                                            /**
                                                             *  @dev   Enables upgrading from a version to a version of an implementation, with an optional migrator.
                                                             *         Only the Governor can call this function.
                                                             *  @param fromVersion_ The starting version of the upgrade path.
                                                             *  @param toVersion_   The destination version of the upgrade path.
                                                             *  @param migrator_    The address of the migrator, if any.
                                                             */
                                                            function enableUpgradePath(uint256 fromVersion_, uint256 toVersion_, address migrator_) external;
                                                            /**
                                                             *  @dev   Disables upgrading from a version to a version of a implementation.
                                                             *         Only the Governor can call this function.
                                                             *  @param fromVersion_ The starting version of the upgrade path.
                                                             *  @param toVersion_   The destination version of the upgrade path.
                                                             */
                                                            function disableUpgradePath(uint256 fromVersion_, uint256 toVersion_) external;
                                                            /**
                                                             *  @dev   Registers the address of an implementation contract as a version, with an optional initializer.
                                                             *         Only the Governor can call this function.
                                                             *  @param version_               The version to register.
                                                             *  @param implementationAddress_ The address of the implementation.
                                                             *  @param initializer_           The address of the initializer, if any.
                                                             */
                                                            function registerImplementation(uint256 version_, address implementationAddress_, address initializer_) external;
                                                            /**
                                                             *  @dev   Sets the default version.
                                                             *         Only the Governor can call this function.
                                                             *  @param version_ The implementation version to set as the default.
                                                             */
                                                            function setDefaultVersion(uint256 version_) external;
                                                            /**
                                                             *  @dev   Sets the Maple Globals contract.
                                                             *         Only the Governor can call this function.
                                                             *  @param mapleGlobals_ The address of a Maple Globals contract.
                                                             */
                                                            function setGlobals(address mapleGlobals_) external;
                                                            /**
                                                             *  @dev   Upgrades the calling proxy contract's implementation, with some migration arguments.
                                                             *  @param toVersion_ The implementation version to upgrade the proxy contract to.
                                                             *  @param arguments_ The migration arguments, if any.
                                                             */
                                                            function upgradeInstance(uint256 toVersion_, bytes calldata arguments_) external;
                                                            /**************************************************************************************************************************************/
                                                            /*** View Functions                                                                                                                 ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev    Returns the deterministic address of a potential proxy, given some arguments and salt.
                                                             *  @param  arguments_       The initialization arguments to be used when deploying the proxy.
                                                             *  @param  salt_            The salt to be used when deploying the proxy.
                                                             *  @return instanceAddress_ The deterministic address of a potential proxy.
                                                             */
                                                            function getInstanceAddress(bytes calldata arguments_, bytes32 salt_) external view returns (address instanceAddress_);
                                                            /**
                                                             *  @dev    Returns the address of an implementation version.
                                                             *  @param  version_        The implementation version.
                                                             *  @return implementation_ The address of the implementation.
                                                             */
                                                            function implementationOf(uint256 version_) external view returns (address implementation_);
                                                            /**
                                                             *  @dev    Returns if a given address has been deployed by this factory/
                                                             *  @param  instance_   The address to check.
                                                             *  @return isInstance_ A boolean indication if the address has been deployed by this factory.
                                                             */
                                                            function isInstance(address instance_) external view returns (bool isInstance_);
                                                            /**
                                                             *  @dev    Returns the address of a migrator contract for a migration path (from version, to version).
                                                             *          If oldVersion_ == newVersion_, the migrator is an initializer.
                                                             *  @param  oldVersion_ The old version.
                                                             *  @param  newVersion_ The new version.
                                                             *  @return migrator_   The address of a migrator contract.
                                                             */
                                                            function migratorForPath(uint256 oldVersion_, uint256 newVersion_) external view returns (address migrator_);
                                                            /**
                                                             *  @dev    Returns the version of an implementation contract.
                                                             *  @param  implementation_ The address of an implementation contract.
                                                             *  @return version_        The version of the implementation contract.
                                                             */
                                                            function versionOf(address implementation_) external view returns (uint256 version_);
                                                        }
                                                        // SPDX-License-Identifier: AGPL-3.0-or-later
                                                        pragma solidity ^0.8.7;
                                                        import { IProxied } from "../../modules/proxy-factory/contracts/interfaces/IProxied.sol";
                                                        /// @title A Maple implementation that is to be proxied, must implement IMapleProxied.
                                                        interface IMapleProxied is IProxied {
                                                            /**
                                                             *  @dev   The instance was upgraded.
                                                             *  @param toVersion_ The new version of the loan.
                                                             *  @param arguments_ The upgrade arguments, if any.
                                                             */
                                                            event Upgraded(uint256 toVersion_, bytes arguments_);
                                                            /**
                                                             *  @dev   Upgrades a contract implementation to a specific version.
                                                             *         Access control logic critical since caller can force a selfdestruct via a malicious `migrator_` which is delegatecalled.
                                                             *  @param toVersion_ The version to upgrade to.
                                                             *  @param arguments_ Some encoded arguments to use for the upgrade.
                                                             */
                                                            function upgrade(uint256 toVersion_, bytes calldata arguments_) external;
                                                        }
                                                        // SPDX-License-Identifier: AGPL-3.0-or-later
                                                        pragma solidity ^0.8.7;
                                                        import { ProxiedInternals } from "../modules/proxy-factory/contracts/ProxiedInternals.sol";
                                                        /// @title A Maple implementation that is to be proxied, will need MapleProxiedInternals.
                                                        abstract contract MapleProxiedInternals is ProxiedInternals { }
                                                        // SPDX-License-Identifier: BUSL-1.1
                                                        pragma solidity ^0.8.25;
                                                        import { IMaplePoolManagerStorage } from "../interfaces/IMaplePoolManagerStorage.sol";
                                                        abstract contract MaplePoolManagerStorage is IMaplePoolManagerStorage {
                                                            uint256 internal _locked;  // Used when checking for reentrancy.
                                                            address public override poolDelegate;
                                                            address public override pendingPoolDelegate;
                                                            address public override asset;
                                                            address public override pool;
                                                            address public override poolDelegateCover;
                                                            address public override withdrawalManager;
                                                            bool public override active;
                                                            bool public override configured;
                                                            
                                                            bool __deprecated_openToPublic;
                                                            uint256 public override liquidityCap;
                                                            uint256 public override delegateManagementFeeRate;
                                                            mapping(address => bool) public override isStrategy;
                                                            mapping(address => bool) __deprecated_isValidLender;
                                                            address[] public override strategyList;
                                                            address public override poolPermissionManager;
                                                        }
                                                        // SPDX-License-Identifier: BUSL-1.1
                                                        pragma solidity ^0.8.7;
                                                        interface IERC20Like {
                                                            function allowance(address owner_, address spender_) external view returns (uint256 allowance_);
                                                            function balanceOf(address account_) external view returns (uint256 balance_);
                                                            function totalSupply() external view returns (uint256 totalSupply_);
                                                        }
                                                        interface IGlobalsLike {
                                                            function bootstrapMint(address asset_) external view returns (uint256 bootstrapMint_);
                                                            function governor() external view returns (address governor_);
                                                            function isFunctionPaused(bytes4 sig_) external view returns (bool isFunctionPaused_);
                                                            function isInstanceOf(bytes32 instanceId_, address instance_) external view returns (bool isInstance_);
                                                            function isPoolAsset(address asset_) external view returns (bool isPoolAsset_);
                                                            function isPoolDelegate(address account_) external view returns (bool isPoolDelegate_);
                                                            function isPoolDeployer(address poolDeployer_) external view returns (bool isPoolDeployer_);
                                                            function isValidScheduledCall(address caller_, address contract_, bytes32 functionId_, bytes calldata callData_)
                                                                external view
                                                                returns (bool isValid_);
                                                            function mapleTreasury() external view returns (address mapleTreasury_);
                                                            function maxCoverLiquidationPercent(address poolManager_) external view returns (uint256 maxCoverLiquidationPercent_);
                                                            function migrationAdmin() external view returns (address migrationAdmin_);
                                                            function minCoverAmount(address poolManager_) external view returns (uint256 minCoverAmount_);
                                                            function operationalAdmin() external view returns (address operationalAdmin_);
                                                            function ownedPoolManager(address poolDelegate_) external view returns (address poolManager_);
                                                            function securityAdmin() external view returns (address securityAdmin_);
                                                            function transferOwnedPoolManager(address fromPoolDelegate_, address toPoolDelegate_) external;
                                                            function unscheduleCall(address caller_, bytes32 functionId_, bytes calldata callData_) external;
                                                        }
                                                        interface IStrategyLike {
                                                            function assetsUnderManagement() external view returns (uint256 assetsUnderManagement_);
                                                            function unrealizedLosses() external view returns (uint256 unrealizedLosses_);
                                                        }
                                                        interface ILoanManagerLike {
                                                            
                                                            function finishCollateralLiquidation(address loan_) external returns (uint256 remainingLosses_, uint256 serviceFee_);
                                                            function triggerDefault(address loan_, address liquidatorFactory_)
                                                                external
                                                                returns (bool liquidationComplete_, uint256 remainingLosses_, uint256 platformFees_);
                                                        }
                                                        interface ILoanLike {
                                                            function lender() external view returns (address lender_);
                                                        }
                                                        interface IMapleProxyFactoryLike {
                                                            function isInstance(address instance_) external view returns (bool isInstance_);
                                                            function mapleGlobals() external view returns (address mapleGlobals_);
                                                        }
                                                        interface IPoolDelegateCoverLike {
                                                            function moveFunds(uint256 amount_, address recipient_) external;
                                                        }
                                                        interface IPoolLike is IERC20Like {
                                                            function convertToExitShares(uint256 assets_) external view returns (uint256 shares_);
                                                            function previewDeposit(uint256 assets_) external view returns (uint256 shares_);
                                                            function previewMint(uint256 shares_) external view returns (uint256 assets_);
                                                        }
                                                        interface IPoolManagerLike {
                                                            function addStrategy(address strategyFactory_, bytes calldata deploymentData_) external returns (address strategy_);
                                                            function canCall(bytes32 functionId_, address caller_, bytes memory data_)
                                                                external view
                                                                returns (bool canCall_, string memory errorMessage_);
                                                            function completeConfiguration() external;
                                                            function getEscrowParams(address owner_, uint256 shares_) external view returns (uint256 escrowShares_, address escrow_);
                                                            function maxDeposit(address receiver_) external view returns (uint256 maxAssets_);
                                                            function maxMint(address receiver_) external view returns (uint256 maxShares_);
                                                            function maxRedeem(address owner_) external view returns (uint256 maxShares_);
                                                            function maxWithdraw(address owner_) external view returns (uint256 maxAssets_);
                                                            function pool() external view returns (address pool_);
                                                            function poolDelegateCover() external view returns (address poolDelegateCover_);
                                                            function previewRedeem(address owner_, uint256 shares_) external view returns (uint256 assets_);
                                                            function previewWithdraw(address owner_, uint256 assets_) external view returns (uint256 shares_);
                                                            function processRedeem(uint256 shares_, address owner_, address sender_)
                                                                external
                                                                returns (uint256 redeemableShares_, uint256 resultingAssets_);
                                                            function processWithdraw(uint256 assets_, address owner_, address sender_)
                                                                external
                                                                returns (uint256 redeemableShares_, uint256 resultingAssets_);
                                                            function removeShares(uint256 shares_, address owner_) external returns (uint256 sharesReturned_);
                                                            function requestRedeem(uint256 shares_, address owner_, address sender_) external;
                                                            function requestWithdraw(uint256 shares_, uint256 assets_, address owner_, address sender_) external;
                                                            function setDelegateManagementFeeRate(uint256 delegateManagementFeeRate_) external;
                                                            function setLiquidityCap(uint256 liquidityCap_) external;
                                                            function setPoolPermissionManager(address poolPermissionManager_) external;
                                                            function setWithdrawalManager(address withdrawalManager_) external;
                                                            function totalAssets() external view returns (uint256 totalAssets_);
                                                            function unrealizedLosses() external view returns (uint256 unrealizedLosses_);
                                                        }
                                                        interface IPoolPermissionManagerLike {
                                                            function hasPermission(address poolManager, address caller, bytes32 functionId) external view returns (bool allowed);
                                                            function hasPermission(address poolManager, address[] calldata caller, bytes32 functionId) external view returns (bool allowed);
                                                        }
                                                        interface IWithdrawalManagerLike {
                                                            function addShares(uint256 shares_, address owner_) external;
                                                            function factory() external view returns (address factory_);
                                                            function isInExitWindow(address owner_) external view returns (bool isInExitWindow_);
                                                            function lockedLiquidity() external view returns (uint256 lockedLiquidity_);
                                                            function lockedShares(address owner_) external view returns (uint256 lockedShares_);
                                                            function previewRedeem(address owner_, uint256 shares) external view returns (uint256 redeemableShares, uint256 resultingAssets_);
                                                            function previewWithdraw(address owner_, uint256 assets_) external view returns (uint256 redeemableAssets_, uint256 resultingShares_);
                                                            function processExit(uint256 shares_, address account_) external returns (uint256 redeemableShares_, uint256 resultingAssets_);
                                                            function removeShares(uint256 shares_, address owner_) external returns (uint256 sharesReturned_);
                                                        }
                                                        // SPDX-License-Identifier: BUSL-1.1
                                                        pragma solidity ^0.8.7;
                                                        import { IMapleProxied } from "../../modules/maple-proxy-factory/contracts/interfaces/IMapleProxied.sol";
                                                        import { IMaplePoolManagerStorage } from "./IMaplePoolManagerStorage.sol";
                                                        interface IMaplePoolManager is IMapleProxied, IMaplePoolManagerStorage {
                                                            /**************************************************************************************************************************************/
                                                            /*** Events                                                                                                                         ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev   Emitted when a collateral liquidations is finished.
                                                             *  @param loan_             The address of the loan.
                                                             *  @param unrealizedLosses_ The amount of unrealized losses.
                                                             */
                                                            event CollateralLiquidationFinished(address indexed loan_, uint256 unrealizedLosses_);
                                                            /**
                                                             *  @dev   Emitted when a collateral liquidations is triggered.
                                                             *  @param loan_ The address of the loan.
                                                             */
                                                            event CollateralLiquidationTriggered(address indexed loan_);
                                                            /**
                                                             *  @dev   Emitted when cover is deposited.
                                                             *  @param amount_ The amount of cover deposited.
                                                             */
                                                            event CoverDeposited(uint256 amount_);
                                                            /**
                                                             *  @dev   Emitted when cover is liquidated in the case of a loan defaulting.
                                                             *  @param toTreasury_ The amount of cover sent to the Treasury.
                                                             *  @param toPool_     The amount of cover sent to the Pool.
                                                             */
                                                            event CoverLiquidated(uint256 toTreasury_, uint256 toPool_);
                                                            /**
                                                             *  @dev   Emitted when cover is withdrawn.
                                                             *  @param amount_ The amount of cover withdrawn.
                                                             */
                                                            event CoverWithdrawn(uint256 amount_);
                                                            /**
                                                             *  @dev   Emitted when a new management fee rate is set.
                                                             *  @param managementFeeRate_ The amount of management fee rate.
                                                             */
                                                            event DelegateManagementFeeRateSet(uint256 managementFeeRate_);
                                                            /**
                                                             *  @dev   Emitted when a strategy is set as valid.
                                                             *  @param strategy_   The address of the strategy.
                                                             *  @param isStrategy_ Whether the strategy is valid.
                                                             */
                                                            event IsStrategySet(address indexed strategy_, bool isStrategy_);
                                                            /**
                                                             *  @dev   Emitted when a new liquidity cap is set.
                                                             *  @param liquidityCap_ The value of liquidity cap.
                                                             */
                                                            event LiquidityCapSet(uint256 liquidityCap_);
                                                            /**
                                                             *  @dev   Emitted when a new strategy is added.
                                                             *  @param strategy_ The address of the new strategy.
                                                             */
                                                            event StrategyAdded(address indexed strategy_);
                                                            /**
                                                             *  @dev   Emitted when the pending pool delegate accepts the ownership transfer.
                                                             *  @param previousDelegate_ The address of the previous delegate.
                                                             *  @param newDelegate_      The address of the new delegate.
                                                             */
                                                            event PendingDelegateAccepted(address indexed previousDelegate_, address indexed newDelegate_);
                                                            /**
                                                             *  @dev   Emitted when the pending pool delegate is set.
                                                             *  @param previousDelegate_ The address of the previous delegate.
                                                             *  @param newDelegate_      The address of the new delegate.
                                                             */
                                                            event PendingDelegateSet(address indexed previousDelegate_, address indexed newDelegate_);
                                                            /**
                                                             *  @dev Emitted when the pool configuration is marked as complete.
                                                             */
                                                            event PoolConfigurationComplete();
                                                            /**
                                                             *  @dev   Emitted when the pool permission manager is set.
                                                             *  @param poolPermissionManager_ The address of the pool permission manager.
                                                             */
                                                            event PoolPermissionManagerSet(address indexed poolPermissionManager_);
                                                            /**
                                                             *  @dev   Emitted when a redemption of shares from the pool is processed.
                                                             *  @param owner_            The owner of the shares.
                                                             *  @param redeemableShares_ The amount of redeemable shares.
                                                             *  @param resultingAssets_  The amount of assets redeemed.
                                                             */
                                                            event RedeemProcessed(address indexed owner_, uint256 redeemableShares_, uint256 resultingAssets_);
                                                            /**
                                                             *  @dev   Emitted when a redemption of shares from the pool is requested.
                                                             *  @param owner_  The owner of the shares.
                                                             *  @param shares_ The amount of redeemable shares.
                                                             */
                                                            event RedeemRequested(address indexed owner_, uint256 shares_);
                                                            /**
                                                             *  @dev   Emitted when a pool is sets to be active or inactive.
                                                             *  @param active_ Whether the pool is active.
                                                             */
                                                            event SetAsActive(bool active_);
                                                            /**
                                                             *  @dev   Emitted when shares are removed from the pool.
                                                             *  @param owner_  The address of the owner of the shares.
                                                             *  @param shares_ The amount of shares removed.
                                                             */
                                                            event SharesRemoved(address indexed owner_, uint256 shares_);
                                                            /**
                                                             *  @dev   Emitted when the withdrawal manager is set.
                                                             *  @param withdrawalManager_ The address of the withdrawal manager.
                                                             */
                                                            event WithdrawalManagerSet(address indexed withdrawalManager_);
                                                            /**
                                                             *  @dev   Emitted when withdrawal of assets from the pool is processed.
                                                             *  @param owner_            The owner of the assets.
                                                             *  @param redeemableShares_ The amount of redeemable shares.
                                                             *  @param resultingAssets_  The amount of assets redeemed.
                                                             */
                                                            event WithdrawalProcessed(address indexed owner_, uint256 redeemableShares_, uint256 resultingAssets_);
                                                            /**************************************************************************************************************************************/
                                                            /*** Ownership Transfer Functions                                                                                                   ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev Accepts the role of pool delegate.
                                                             */
                                                            function acceptPoolDelegate() external;
                                                            /**
                                                             *  @dev   Sets an address as the pending pool delegate.
                                                             *  @param pendingPoolDelegate_ The address of the new pool delegate.
                                                             */
                                                            function setPendingPoolDelegate(address pendingPoolDelegate_) external;
                                                            /**************************************************************************************************************************************/
                                                            /*** Administrative Functions                                                                                                       ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev    Adds a new strategy.
                                                             *          NOTE: The PoolManager address is encoded and prepended to the extraDeploymentData.
                                                             *  @param  strategyFactory_     The address of the strategy factory to use.
                                                             *  @param  extraDeploymentData_ The data to construct the strategy.
                                                             *  @return strategy_            The address of the new strategy.
                                                             */
                                                            function addStrategy(address strategyFactory_, bytes calldata extraDeploymentData_) external returns (address strategy_);
                                                            /**
                                                             *  @dev Complete the configuration.
                                                             */
                                                            function completeConfiguration() external;
                                                            /**
                                                             *  @dev   Sets a the pool to be active or inactive.
                                                             *  @param active_ Whether the pool is active.
                                                             */
                                                            function setActive(bool active_) external;
                                                            /**
                                                             *  @dev   Sets the value for the delegate management fee rate.
                                                             *  @param delegateManagementFeeRate_ The value for the delegate management fee rate.
                                                             */
                                                            function setDelegateManagementFeeRate(uint256 delegateManagementFeeRate_) external;
                                                            /**
                                                             *  @dev   Sets if the strategy is valid in the isStrategy mapping.
                                                             *  @param strategy_   The address of the strategy
                                                             *  @param isStrategy_ Whether the strategy is valid.
                                                             */
                                                            function setIsStrategy(address strategy_, bool isStrategy_) external;
                                                            /**
                                                             *  @dev   Sets the value for liquidity cap.
                                                             *  @param liquidityCap_ The value for liquidity cap.
                                                             */
                                                            function setLiquidityCap(uint256 liquidityCap_) external;
                                                            /**
                                                             *  @dev   Sets the address of the pool permission manager.
                                                             *  @param poolPermission_ The address of the pool permission manager.
                                                             */
                                                            function setPoolPermissionManager(address poolPermission_) external;
                                                            /**
                                                             *  @dev   Sets the address of the withdrawal manager.
                                                             *  @param withdrawalManager_ The address of the withdrawal manager.
                                                             */
                                                            function setWithdrawalManager(address withdrawalManager_) external;
                                                            /**************************************************************************************************************************************/
                                                            /*** Funding Functions                                                                                                              ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev   Strategy can request funds from the pool via the poolManager.
                                                             *  @param destination_ The address to send the funds to.
                                                             *  @param principal_   The principal amount to fund the strategy with.
                                                             */
                                                            function requestFunds(address destination_, uint256 principal_) external;
                                                            /**************************************************************************************************************************************/
                                                            /*** Liquidation Functions                                                                                                          ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev   Finishes the collateral liquidation
                                                             *  @param loan_ Loan that had its collateral liquidated.
                                                             */
                                                            function finishCollateralLiquidation(address loan_) external;
                                                            /**
                                                             *  @dev   Triggers the default of a loan.
                                                             *  @param loan_              Loan to trigger the default.
                                                             *  @param liquidatorFactory_ Factory used to deploy the liquidator.
                                                             */
                                                            function triggerDefault(address loan_, address liquidatorFactory_) external;
                                                            /**************************************************************************************************************************************/
                                                            /*** Exit Functions                                                                                                                 ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev    Processes a redemptions of shares for assets from the pool.
                                                             *  @param  shares_           The amount of shares to redeem.
                                                             *  @param  owner_            The address of the owner of the shares.
                                                             *  @param  sender_           The address of the sender of the redeem call.
                                                             *  @return redeemableShares_ The amount of shares redeemed.
                                                             *  @return resultingAssets_  The amount of assets withdrawn.
                                                             */
                                                            function processRedeem(uint256 shares_, address owner_, address sender_)
                                                                external
                                                                returns (uint256 redeemableShares_, uint256 resultingAssets_);
                                                            /**
                                                             *  @dev    Processes a redemptions of shares for assets from the pool.
                                                             *  @param  assets_           The amount of assets to withdraw.
                                                             *  @param  owner_            The address of the owner of the shares.
                                                             *  @param  sender_           The address of the sender of the withdraw call.
                                                             *  @return redeemableShares_ The amount of shares redeemed.
                                                             *  @return resultingAssets_  The amount of assets withdrawn.
                                                             */
                                                            function processWithdraw(uint256 assets_, address owner_, address sender_)
                                                                external
                                                                returns (uint256 redeemableShares_, uint256 resultingAssets_);
                                                            /**
                                                             *  @dev    Requests a redemption of shares from the pool.
                                                             *  @param  shares_         The amount of shares to redeem.
                                                             *  @param  owner_          The address of the owner of the shares.
                                                             *  @return sharesReturned_ The amount of shares withdrawn.
                                                             */
                                                            function removeShares(uint256 shares_, address owner_) external returns (uint256 sharesReturned_);
                                                            /**
                                                             *  @dev   Requests a redemption of shares from the pool.
                                                             *  @param shares_ The amount of shares to redeem.
                                                             *  @param owner_  The address of the owner of the shares.
                                                             *  @param sender_ The address of the sender of the shares.
                                                             */
                                                            function requestRedeem(uint256 shares_, address owner_, address sender_) external;
                                                            /**
                                                             *  @dev   Requests a withdrawal of assets from the pool.
                                                             *  @param shares_ The amount of shares to redeem.
                                                             *  @param assets_ The amount of assets to withdraw.
                                                             *  @param owner_  The address of the owner of the shares.
                                                             *  @param sender_ The address of the sender of the shares.
                                                             */
                                                             function requestWithdraw(uint256 shares_, uint256 assets_, address owner_, address sender_) external;
                                                            /**************************************************************************************************************************************/
                                                            /*** Cover Functions                                                                                                                ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev   Deposits cover into the pool.
                                                             *  @param amount_ The amount of cover to deposit.
                                                             */
                                                            function depositCover(uint256 amount_) external;
                                                            /**
                                                             *  @dev   Withdraws cover from the pool.
                                                             *  @param amount_    The amount of cover to withdraw.
                                                             *  @param recipient_ The address of the recipient.
                                                             */
                                                            function withdrawCover(uint256 amount_, address recipient_) external;
                                                            /**************************************************************************************************************************************/
                                                            /*** LP Token View Functions                                                                                                        ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev    Returns the amount of exit shares for the input amount.
                                                             *  @param  amount_  Address of the account.
                                                             *  @return shares_  Amount of shares able to be exited.
                                                             */
                                                            function convertToExitShares(uint256 amount_) external view returns (uint256 shares_);
                                                            /**
                                                             *  @dev    Gets the information of escrowed shares.
                                                             *  @param  owner_        The address of the owner of the shares.
                                                             *  @param  shares_       The amount of shares to get the information of.
                                                             *  @return escrowShares_ The amount of escrowed shares.
                                                             *  @return destination_  The address of the destination.
                                                             */
                                                            function getEscrowParams(address owner_, uint256 shares_) external view returns (uint256 escrowShares_, address destination_);
                                                            /**
                                                             *  @dev   Gets the amount of assets that can be deposited.
                                                             *  @param receiver_  The address to check the deposit for.
                                                             *  @param maxAssets_ The maximum amount assets to deposit.
                                                             */
                                                            function maxDeposit(address receiver_) external view returns (uint256 maxAssets_);
                                                            /**
                                                             *  @dev   Gets the amount of shares that can be minted.
                                                             *  @param receiver_  The address to check the mint for.
                                                             *  @param maxShares_ The maximum amount shares to mint.
                                                             */
                                                            function maxMint(address receiver_) external view returns (uint256 maxShares_);
                                                            /**
                                                             *  @dev   Gets the amount of shares that can be redeemed.
                                                             *  @param owner_     The address to check the redemption for.
                                                             *  @param maxShares_ The maximum amount shares to redeem.
                                                             */
                                                            function maxRedeem(address owner_) external view returns (uint256 maxShares_);
                                                            /**
                                                             *  @dev   Gets the amount of assets that can be withdrawn.
                                                             *  @param owner_     The address to check the withdraw for.
                                                             *  @param maxAssets_ The maximum amount assets to withdraw.
                                                             */
                                                            function maxWithdraw(address owner_) external view returns (uint256 maxAssets_);
                                                            /**
                                                             *  @dev    Gets the amount of shares that can be redeemed.
                                                             *  @param  owner_   The address to check the redemption for.
                                                             *  @param  shares_  The amount of requested shares to redeem.
                                                             *  @return assets_  The amount of assets that will be returned for `shares_`.
                                                             */
                                                            function previewRedeem(address owner_, uint256 shares_) external view returns (uint256 assets_);
                                                            /**
                                                             *  @dev    Gets the amount of assets that can be redeemed.
                                                             *  @param  owner_   The address to check the redemption for.
                                                             *  @param  assets_  The amount of requested shares to redeem.
                                                             *  @return shares_  The amount of assets that will be returned for `assets_`.
                                                             */
                                                            function previewWithdraw(address owner_, uint256 assets_) external view returns (uint256 shares_);
                                                            /**************************************************************************************************************************************/
                                                            /*** View Functions                                                                                                                 ***/
                                                            /**************************************************************************************************************************************/
                                                            /**
                                                             *  @dev    Checks if a scheduled call can be executed.
                                                             *  @param  functionId_   The function to check.
                                                             *  @param  caller_       The address of the caller.
                                                             *  @param  data_         The data of the call.
                                                             *  @return canCall_      True if the call can be executed, false otherwise.
                                                             *  @return errorMessage_ The error message if the call cannot be executed.
                                                             */
                                                            function canCall(bytes32 functionId_, address caller_, bytes memory data_)
                                                                external view
                                                                returns (bool canCall_, string memory errorMessage_);
                                                            /**
                                                             *  @dev    Gets the address of the globals.
                                                             *  @return globals_ The address of the globals.
                                                             */
                                                            function globals() external view returns (address globals_);
                                                            /**
                                                             *  @dev    Gets the address of the governor.
                                                             *  @return governor_ The address of the governor.
                                                             */
                                                            function governor() external view returns (address governor_);
                                                            /**
                                                             *  @dev    Returns if pool has sufficient cover.
                                                             *  @return hasSufficientCover_ True if pool has sufficient cover.
                                                             */
                                                            function hasSufficientCover() external view returns (bool hasSufficientCover_);
                                                            /**
                                                             *  @dev    Returns the length of the `strategyList`.
                                                             *  @return strategyListLength_ The length of the `strategyList`.
                                                             */
                                                            function strategyListLength() external view returns (uint256 strategyListLength_);
                                                            /**
                                                             *  @dev    Returns the amount of total assets.
                                                             *  @return totalAssets_ Amount of of total assets.
                                                             */
                                                            function totalAssets() external view returns (uint256 totalAssets_);
                                                            /**
                                                             *  @dev    Returns the amount unrealized losses.
                                                             *  @return unrealizedLosses_ Amount of unrealized losses.
                                                             */
                                                            function unrealizedLosses() external view returns (uint256 unrealizedLosses_);
                                                        }
                                                        // SPDX-License-Identifier: AGPL-3.0-only
                                                        pragma solidity ^0.8.7;
                                                        /// @title Interface of the ERC20 standard as needed by ERC20Helper.
                                                        interface IERC20Like {
                                                            function approve(address spender_, uint256 amount_) external returns (bool success_);
                                                            function transfer(address recipient_, uint256 amount_) external returns (bool success_);
                                                            function transferFrom(address owner_, address recipient_, uint256 amount_) external returns (bool success_);
                                                        }
                                                        // SPDX-License-Identifier: AGPL-3.0-only
                                                        pragma solidity ^0.8.7;
                                                        /// @title An beacon that provides a default implementation for proxies, must implement IDefaultImplementationBeacon.
                                                        interface IDefaultImplementationBeacon {
                                                            /// @dev The address of an implementation for proxies.
                                                            function defaultImplementation() external view returns (address defaultImplementation_);
                                                        }
                                                        // SPDX-License-Identifier: AGPL-3.0-only
                                                        pragma solidity ^0.8.7;
                                                        /// @title An implementation that is to be proxied, must implement IProxied.
                                                        interface IProxied {
                                                            /**
                                                             *  @dev The address of the proxy factory.
                                                             */
                                                            function factory() external view returns (address factory_);
                                                            /**
                                                             *  @dev The address of the implementation contract being proxied.
                                                             */
                                                            function implementation() external view returns (address implementation_);
                                                            /**
                                                             *  @dev   Modifies the proxy's implementation address.
                                                             *  @param newImplementation_ The address of an implementation contract.
                                                             */
                                                            function setImplementation(address newImplementation_) external;
                                                            /**
                                                             *  @dev   Modifies the proxy's storage by delegate-calling a migrator contract with some arguments.
                                                             *         Access control logic critical since caller can force a selfdestruct via a malicious `migrator_` which is delegatecalled.
                                                             *  @param migrator_  The address of a migrator contract.
                                                             *  @param arguments_ Some encoded arguments to use for the migration.
                                                             */
                                                            function migrate(address migrator_, bytes calldata arguments_) external;
                                                        }
                                                        // SPDX-License-Identifier: AGPL-3.0-only
                                                        pragma solidity ^0.8.7;
                                                        import { SlotManipulatable } from "./SlotManipulatable.sol";
                                                        /// @title An implementation that is to be proxied, will need ProxiedInternals.
                                                        abstract contract ProxiedInternals is SlotManipulatable {
                                                            /// @dev Storage slot with the address of the current factory. `keccak256('eip1967.proxy.factory') - 1`.
                                                            bytes32 private constant FACTORY_SLOT = bytes32(0x7a45a402e4cb6e08ebc196f20f66d5d30e67285a2a8aa80503fa409e727a4af1);
                                                            /// @dev Storage slot with the address of the current factory. `keccak256('eip1967.proxy.implementation') - 1`.
                                                            bytes32 private constant IMPLEMENTATION_SLOT = bytes32(0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc);
                                                            /// @dev Delegatecalls to a migrator contract to manipulate storage during an initialization or migration.
                                                            function _migrate(address migrator_, bytes calldata arguments_) internal virtual returns (bool success_) {
                                                                uint256 size;
                                                                assembly {
                                                                    size := extcodesize(migrator_)
                                                                }
                                                                if (size == uint256(0)) return false;
                                                                ( success_, ) = migrator_.delegatecall(arguments_);
                                                            }
                                                            /// @dev Sets the factory address in storage.
                                                            function _setFactory(address factory_) internal virtual returns (bool success_) {
                                                                _setSlotValue(FACTORY_SLOT, bytes32(uint256(uint160(factory_))));
                                                                return true;
                                                            }
                                                            /// @dev Sets the implementation address in storage.
                                                            function _setImplementation(address implementation_) internal virtual returns (bool success_) {
                                                                _setSlotValue(IMPLEMENTATION_SLOT, bytes32(uint256(uint160(implementation_))));
                                                                return true;
                                                            }
                                                            /// @dev Returns the factory address.
                                                            function _factory() internal view virtual returns (address factory_) {
                                                                return address(uint160(uint256(_getSlotValue(FACTORY_SLOT))));
                                                            }
                                                            /// @dev Returns the implementation address.
                                                            function _implementation() internal view virtual returns (address implementation_) {
                                                                return address(uint160(uint256(_getSlotValue(IMPLEMENTATION_SLOT))));
                                                            }
                                                        }
                                                        // SPDX-License-Identifier: BUSL-1.1
                                                        pragma solidity ^0.8.7;
                                                        interface IMaplePoolManagerStorage {
                                                            /**
                                                             *  @dev    Returns whether or not a pool is active.
                                                             *  @return active_ True if the pool is active.
                                                             */
                                                            function active() external view returns (bool active_);
                                                            /**
                                                             *  @dev    Gets the address of the funds asset.
                                                             *  @return asset_ The address of the funds asset.
                                                             */
                                                            function asset() external view returns (address asset_);
                                                            /**
                                                             *  @dev    Returns whether or not a pool is configured.
                                                             *  @return configured_ True if the pool is configured.
                                                             */
                                                            function configured() external view returns (bool configured_);
                                                            /**
                                                             *  @dev    Gets the delegate management fee rate.
                                                             *  @return delegateManagementFeeRate_ The value for the delegate management fee rate.
                                                             */
                                                            function delegateManagementFeeRate() external view returns (uint256 delegateManagementFeeRate_);
                                                            /**
                                                             *  @dev    Returns whether or not the given address is a strategy.
                                                             *  @param  strategy_   The address of the strategy.
                                                             *  @return isStrategy_ True if the address is a strategy.
                                                             */
                                                            function isStrategy(address strategy_) external view returns (bool isStrategy_);
                                                            /**
                                                             *  @dev    Gets the liquidity cap for the pool.
                                                             *  @return liquidityCap_ The liquidity cap for the pool.
                                                             */
                                                            function liquidityCap() external view returns (uint256 liquidityCap_);
                                                            /**
                                                             *  @dev    Gets the address of the strategy in the list.
                                                             *  @param  index_    The index to get the address of.
                                                             *  @return strategy_ The address in the list.
                                                             */
                                                            function strategyList(uint256 index_) external view returns (address strategy_);
                                                            /**
                                                             *  @dev    Gets the address of the pending pool delegate.
                                                             *  @return pendingPoolDelegate_ The address of the pending pool delegate.
                                                             */
                                                            function pendingPoolDelegate() external view returns (address pendingPoolDelegate_);
                                                            /**
                                                             *  @dev    Gets the address of the pool.
                                                             *  @return pool_ The address of the pool.
                                                             */
                                                            function pool() external view returns (address pool_);
                                                            /**
                                                             *  @dev    Gets the address of the pool delegate.
                                                             *  @return poolDelegate_ The address of the pool delegate.
                                                             */
                                                            function poolDelegate() external view returns (address poolDelegate_);
                                                            /**
                                                             *  @dev    Gets the address of the pool delegate cover.
                                                             *  @return poolDelegateCover_ The address of the pool delegate cover.
                                                             */
                                                            function poolDelegateCover() external view returns (address poolDelegateCover_);
                                                            /**
                                                             *  @dev    Gets the address of the pool delegate cover.
                                                             *  @return poolPermissionManager_ The address of the pool permission manager.
                                                             */
                                                            function poolPermissionManager() external view returns (address poolPermissionManager_);
                                                            /**
                                                             *  @dev    Gets the address of the withdrawal manager.
                                                             *  @return withdrawalManager_ The address of the withdrawal manager.
                                                             */
                                                            function withdrawalManager() external view returns (address withdrawalManager_);
                                                        }
                                                        // SPDX-License-Identifier: AGPL-3.0-only
                                                        pragma solidity ^0.8.7;
                                                        abstract contract SlotManipulatable {
                                                            function _getReferenceTypeSlot(bytes32 slot_, bytes32 key_) internal pure returns (bytes32 value_) {
                                                                return keccak256(abi.encodePacked(key_, slot_));
                                                            }
                                                            function _getSlotValue(bytes32 slot_) internal view returns (bytes32 value_) {
                                                                assembly {
                                                                    value_ := sload(slot_)
                                                                }
                                                            }
                                                            function _setSlotValue(bytes32 slot_, bytes32 value_) internal {
                                                                assembly {
                                                                    sstore(slot_, value_)
                                                                }
                                                            }
                                                        }
                                                        

                                                        File 11 of 13: PoolAddressesProvider
                                                        // SPDX-License-Identifier: AGPL-3.0
                                                        pragma solidity 0.8.10;
                                                        /**
                                                         * @dev Collection of functions related to the address type
                                                         */
                                                        library Address {
                                                          /**
                                                           * @dev Returns true if `account` is a contract.
                                                           *
                                                           * [IMPORTANT]
                                                           * ====
                                                           * It is unsafe to assume that an address for which this function returns
                                                           * false is an externally-owned account (EOA) and not a contract.
                                                           *
                                                           * Among others, `isContract` will return false for the following
                                                           * types of addresses:
                                                           *
                                                           *  - an externally-owned account
                                                           *  - a contract in construction
                                                           *  - an address where a contract will be created
                                                           *  - an address where a contract lived, but was destroyed
                                                           * ====
                                                           */
                                                          function isContract(address account) internal view returns (bool) {
                                                            // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
                                                            // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
                                                            // for accounts without code, i.e. `keccak256('')`
                                                            bytes32 codehash;
                                                            bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
                                                            // solhint-disable-next-line no-inline-assembly
                                                            assembly {
                                                              codehash := extcodehash(account)
                                                            }
                                                            return (codehash != accountHash && codehash != 0x0);
                                                          }
                                                          /**
                                                           * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                                                           * `recipient`, forwarding all available gas and reverting on errors.
                                                           *
                                                           * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                                                           * of certain opcodes, possibly making contracts go over the 2300 gas limit
                                                           * imposed by `transfer`, making them unable to receive funds via
                                                           * `transfer`. {sendValue} removes this limitation.
                                                           *
                                                           * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                                                           *
                                                           * IMPORTANT: because control is transferred to `recipient`, care must be
                                                           * taken to not create reentrancy vulnerabilities. Consider using
                                                           * {ReentrancyGuard} or the
                                                           * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                                                           */
                                                          function sendValue(address payable recipient, uint256 amount) internal {
                                                            require(address(this).balance >= amount, 'Address: insufficient balance');
                                                            // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
                                                            (bool success, ) = recipient.call{value: amount}('');
                                                            require(success, 'Address: unable to send value, recipient may have reverted');
                                                          }
                                                        }
                                                        // SPDX-License-Identifier: MIT
                                                        pragma solidity 0.8.10;
                                                        /*
                                                         * @dev Provides information about the current execution context, including the
                                                         * sender of the transaction and its data. While these are generally available
                                                         * via msg.sender and msg.data, they should not be accessed in such a direct
                                                         * manner, since when dealing with GSN meta-transactions the account sending and
                                                         * paying for execution may not be the actual sender (as far as an application
                                                         * is concerned).
                                                         *
                                                         * This contract is only required for intermediate, library-like contracts.
                                                         */
                                                        abstract contract Context {
                                                          function _msgSender() internal view virtual returns (address payable) {
                                                            return payable(msg.sender);
                                                          }
                                                          function _msgData() internal view virtual returns (bytes memory) {
                                                            this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                                                            return msg.data;
                                                          }
                                                        }
                                                        // SPDX-License-Identifier: MIT
                                                        pragma solidity 0.8.10;
                                                        import './Context.sol';
                                                        /**
                                                         * @dev Contract module which provides a basic access control mechanism, where
                                                         * there is an account (an owner) that can be granted exclusive access to
                                                         * specific functions.
                                                         *
                                                         * By default, the owner account will be the one that deploys the contract. This
                                                         * can later be changed with {transferOwnership}.
                                                         *
                                                         * This module is used through inheritance. It will make available the modifier
                                                         * `onlyOwner`, which can be applied to your functions to restrict their use to
                                                         * the owner.
                                                         */
                                                        contract Ownable is Context {
                                                          address private _owner;
                                                          event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
                                                          /**
                                                           * @dev Initializes the contract setting the deployer as the initial owner.
                                                           */
                                                          constructor() {
                                                            address msgSender = _msgSender();
                                                            _owner = msgSender;
                                                            emit OwnershipTransferred(address(0), msgSender);
                                                          }
                                                          /**
                                                           * @dev Returns the address of the current owner.
                                                           */
                                                          function owner() public view returns (address) {
                                                            return _owner;
                                                          }
                                                          /**
                                                           * @dev Throws if called by any account other than the owner.
                                                           */
                                                          modifier onlyOwner() {
                                                            require(_owner == _msgSender(), 'Ownable: caller is not the owner');
                                                            _;
                                                          }
                                                          /**
                                                           * @dev Leaves the contract without owner. It will not be possible to call
                                                           * `onlyOwner` functions anymore. Can only be called by the current owner.
                                                           *
                                                           * NOTE: Renouncing ownership will leave the contract without an owner,
                                                           * thereby removing any functionality that is only available to the owner.
                                                           */
                                                          function renounceOwnership() public virtual onlyOwner {
                                                            emit OwnershipTransferred(_owner, address(0));
                                                            _owner = address(0);
                                                          }
                                                          /**
                                                           * @dev Transfers ownership of the contract to a new account (`newOwner`).
                                                           * Can only be called by the current owner.
                                                           */
                                                          function transferOwnership(address newOwner) public virtual onlyOwner {
                                                            require(newOwner != address(0), 'Ownable: new owner is the zero address');
                                                            emit OwnershipTransferred(_owner, newOwner);
                                                            _owner = newOwner;
                                                          }
                                                        }
                                                        // SPDX-License-Identifier: AGPL-3.0
                                                        pragma solidity 0.8.10;
                                                        import './Proxy.sol';
                                                        import '../contracts/Address.sol';
                                                        /**
                                                         * @title BaseUpgradeabilityProxy
                                                         * @dev This contract implements a proxy that allows to change the
                                                         * implementation address to which it will delegate.
                                                         * Such a change is called an implementation upgrade.
                                                         */
                                                        contract BaseUpgradeabilityProxy is Proxy {
                                                          /**
                                                           * @dev Emitted when the implementation is upgraded.
                                                           * @param implementation Address of the new implementation.
                                                           */
                                                          event Upgraded(address indexed implementation);
                                                          /**
                                                           * @dev Storage slot with the address of the current implementation.
                                                           * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
                                                           * validated in the constructor.
                                                           */
                                                          bytes32 internal constant IMPLEMENTATION_SLOT =
                                                            0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                                                          /**
                                                           * @dev Returns the current implementation.
                                                           * @return impl Address of the current implementation
                                                           */
                                                          function _implementation() internal view override returns (address impl) {
                                                            bytes32 slot = IMPLEMENTATION_SLOT;
                                                            //solium-disable-next-line
                                                            assembly {
                                                              impl := sload(slot)
                                                            }
                                                          }
                                                          /**
                                                           * @dev Upgrades the proxy to a new implementation.
                                                           * @param newImplementation Address of the new implementation.
                                                           */
                                                          function _upgradeTo(address newImplementation) internal {
                                                            _setImplementation(newImplementation);
                                                            emit Upgraded(newImplementation);
                                                          }
                                                          /**
                                                           * @dev Sets the implementation address of the proxy.
                                                           * @param newImplementation Address of the new implementation.
                                                           */
                                                          function _setImplementation(address newImplementation) internal {
                                                            require(
                                                              Address.isContract(newImplementation),
                                                              'Cannot set a proxy implementation to a non-contract address'
                                                            );
                                                            bytes32 slot = IMPLEMENTATION_SLOT;
                                                            //solium-disable-next-line
                                                            assembly {
                                                              sstore(slot, newImplementation)
                                                            }
                                                          }
                                                        }
                                                        // SPDX-License-Identifier: AGPL-3.0
                                                        pragma solidity 0.8.10;
                                                        import './BaseUpgradeabilityProxy.sol';
                                                        /**
                                                         * @title InitializableUpgradeabilityProxy
                                                         * @dev Extends BaseUpgradeabilityProxy with an initializer for initializing
                                                         * implementation and init data.
                                                         */
                                                        contract InitializableUpgradeabilityProxy is BaseUpgradeabilityProxy {
                                                          /**
                                                           * @dev Contract initializer.
                                                           * @param _logic Address of the initial implementation.
                                                           * @param _data Data to send as msg.data to the implementation to initialize the proxied contract.
                                                           * It should include the signature and the parameters of the function to be called, as described in
                                                           * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
                                                           * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.
                                                           */
                                                          function initialize(address _logic, bytes memory _data) public payable {
                                                            require(_implementation() == address(0));
                                                            assert(IMPLEMENTATION_SLOT == bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1));
                                                            _setImplementation(_logic);
                                                            if (_data.length > 0) {
                                                              (bool success, ) = _logic.delegatecall(_data);
                                                              require(success);
                                                            }
                                                          }
                                                        }
                                                        // SPDX-License-Identifier: AGPL-3.0
                                                        pragma solidity 0.8.10;
                                                        /**
                                                         * @title Proxy
                                                         * @dev Implements delegation of calls to other contracts, with proper
                                                         * forwarding of return values and bubbling of failures.
                                                         * It defines a fallback function that delegates all calls to the address
                                                         * returned by the abstract _implementation() internal function.
                                                         */
                                                        abstract contract Proxy {
                                                          /**
                                                           * @dev Fallback function.
                                                           * Will run if no other function in the contract matches the call data.
                                                           * Implemented entirely in `_fallback`.
                                                           */
                                                          fallback() external payable {
                                                            _fallback();
                                                          }
                                                          /**
                                                           * @return The Address of the implementation.
                                                           */
                                                          function _implementation() internal view virtual returns (address);
                                                          /**
                                                           * @dev Delegates execution to an implementation contract.
                                                           * This is a low level function that doesn't return to its internal call site.
                                                           * It will return to the external caller whatever the implementation returns.
                                                           * @param implementation Address to delegate.
                                                           */
                                                          function _delegate(address implementation) internal {
                                                            //solium-disable-next-line
                                                            assembly {
                                                              // Copy msg.data. We take full control of memory in this inline assembly
                                                              // block because it will not return to Solidity code. We overwrite the
                                                              // Solidity scratch pad at memory position 0.
                                                              calldatacopy(0, 0, calldatasize())
                                                              // Call the implementation.
                                                              // out and outsize are 0 because we don't know the size yet.
                                                              let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                                                              // Copy the returned data.
                                                              returndatacopy(0, 0, returndatasize())
                                                              switch result
                                                              // delegatecall returns 0 on error.
                                                              case 0 {
                                                                revert(0, returndatasize())
                                                              }
                                                              default {
                                                                return(0, returndatasize())
                                                              }
                                                            }
                                                          }
                                                          /**
                                                           * @dev Function that is run as the first thing in the fallback function.
                                                           * Can be redefined in derived contracts to add functionality.
                                                           * Redefinitions must call super._willFallback().
                                                           */
                                                          function _willFallback() internal virtual {}
                                                          /**
                                                           * @dev fallback implementation.
                                                           * Extracted to enable manual triggering.
                                                           */
                                                          function _fallback() internal {
                                                            _willFallback();
                                                            _delegate(_implementation());
                                                          }
                                                        }
                                                        // SPDX-License-Identifier: AGPL-3.0
                                                        pragma solidity ^0.8.0;
                                                        /**
                                                         * @title IPoolAddressesProvider
                                                         * @author Aave
                                                         * @notice Defines the basic interface for a Pool Addresses Provider.
                                                         */
                                                        interface IPoolAddressesProvider {
                                                          /**
                                                           * @dev Emitted when the market identifier is updated.
                                                           * @param oldMarketId The old id of the market
                                                           * @param newMarketId The new id of the market
                                                           */
                                                          event MarketIdSet(string indexed oldMarketId, string indexed newMarketId);
                                                          /**
                                                           * @dev Emitted when the pool is updated.
                                                           * @param oldAddress The old address of the Pool
                                                           * @param newAddress The new address of the Pool
                                                           */
                                                          event PoolUpdated(address indexed oldAddress, address indexed newAddress);
                                                          /**
                                                           * @dev Emitted when the pool configurator is updated.
                                                           * @param oldAddress The old address of the PoolConfigurator
                                                           * @param newAddress The new address of the PoolConfigurator
                                                           */
                                                          event PoolConfiguratorUpdated(address indexed oldAddress, address indexed newAddress);
                                                          /**
                                                           * @dev Emitted when the price oracle is updated.
                                                           * @param oldAddress The old address of the PriceOracle
                                                           * @param newAddress The new address of the PriceOracle
                                                           */
                                                          event PriceOracleUpdated(address indexed oldAddress, address indexed newAddress);
                                                          /**
                                                           * @dev Emitted when the ACL manager is updated.
                                                           * @param oldAddress The old address of the ACLManager
                                                           * @param newAddress The new address of the ACLManager
                                                           */
                                                          event ACLManagerUpdated(address indexed oldAddress, address indexed newAddress);
                                                          /**
                                                           * @dev Emitted when the ACL admin is updated.
                                                           * @param oldAddress The old address of the ACLAdmin
                                                           * @param newAddress The new address of the ACLAdmin
                                                           */
                                                          event ACLAdminUpdated(address indexed oldAddress, address indexed newAddress);
                                                          /**
                                                           * @dev Emitted when the price oracle sentinel is updated.
                                                           * @param oldAddress The old address of the PriceOracleSentinel
                                                           * @param newAddress The new address of the PriceOracleSentinel
                                                           */
                                                          event PriceOracleSentinelUpdated(address indexed oldAddress, address indexed newAddress);
                                                          /**
                                                           * @dev Emitted when the pool data provider is updated.
                                                           * @param oldAddress The old address of the PoolDataProvider
                                                           * @param newAddress The new address of the PoolDataProvider
                                                           */
                                                          event PoolDataProviderUpdated(address indexed oldAddress, address indexed newAddress);
                                                          /**
                                                           * @dev Emitted when a new proxy is created.
                                                           * @param id The identifier of the proxy
                                                           * @param proxyAddress The address of the created proxy contract
                                                           * @param implementationAddress The address of the implementation contract
                                                           */
                                                          event ProxyCreated(
                                                            bytes32 indexed id,
                                                            address indexed proxyAddress,
                                                            address indexed implementationAddress
                                                          );
                                                          /**
                                                           * @dev Emitted when a new non-proxied contract address is registered.
                                                           * @param id The identifier of the contract
                                                           * @param oldAddress The address of the old contract
                                                           * @param newAddress The address of the new contract
                                                           */
                                                          event AddressSet(bytes32 indexed id, address indexed oldAddress, address indexed newAddress);
                                                          /**
                                                           * @dev Emitted when the implementation of the proxy registered with id is updated
                                                           * @param id The identifier of the contract
                                                           * @param proxyAddress The address of the proxy contract
                                                           * @param oldImplementationAddress The address of the old implementation contract
                                                           * @param newImplementationAddress The address of the new implementation contract
                                                           */
                                                          event AddressSetAsProxy(
                                                            bytes32 indexed id,
                                                            address indexed proxyAddress,
                                                            address oldImplementationAddress,
                                                            address indexed newImplementationAddress
                                                          );
                                                          /**
                                                           * @notice Returns the id of the Aave market to which this contract points to.
                                                           * @return The market id
                                                           */
                                                          function getMarketId() external view returns (string memory);
                                                          /**
                                                           * @notice Associates an id with a specific PoolAddressesProvider.
                                                           * @dev This can be used to create an onchain registry of PoolAddressesProviders to
                                                           * identify and validate multiple Aave markets.
                                                           * @param newMarketId The market id
                                                           */
                                                          function setMarketId(string calldata newMarketId) external;
                                                          /**
                                                           * @notice Returns an address by its identifier.
                                                           * @dev The returned address might be an EOA or a contract, potentially proxied
                                                           * @dev It returns ZERO if there is no registered address with the given id
                                                           * @param id The id
                                                           * @return The address of the registered for the specified id
                                                           */
                                                          function getAddress(bytes32 id) external view returns (address);
                                                          /**
                                                           * @notice General function to update the implementation of a proxy registered with
                                                           * certain `id`. If there is no proxy registered, it will instantiate one and
                                                           * set as implementation the `newImplementationAddress`.
                                                           * @dev IMPORTANT Use this function carefully, only for ids that don't have an explicit
                                                           * setter function, in order to avoid unexpected consequences
                                                           * @param id The id
                                                           * @param newImplementationAddress The address of the new implementation
                                                           */
                                                          function setAddressAsProxy(bytes32 id, address newImplementationAddress) external;
                                                          /**
                                                           * @notice Sets an address for an id replacing the address saved in the addresses map.
                                                           * @dev IMPORTANT Use this function carefully, as it will do a hard replacement
                                                           * @param id The id
                                                           * @param newAddress The address to set
                                                           */
                                                          function setAddress(bytes32 id, address newAddress) external;
                                                          /**
                                                           * @notice Returns the address of the Pool proxy.
                                                           * @return The Pool proxy address
                                                           */
                                                          function getPool() external view returns (address);
                                                          /**
                                                           * @notice Updates the implementation of the Pool, or creates a proxy
                                                           * setting the new `pool` implementation when the function is called for the first time.
                                                           * @param newPoolImpl The new Pool implementation
                                                           */
                                                          function setPoolImpl(address newPoolImpl) external;
                                                          /**
                                                           * @notice Returns the address of the PoolConfigurator proxy.
                                                           * @return The PoolConfigurator proxy address
                                                           */
                                                          function getPoolConfigurator() external view returns (address);
                                                          /**
                                                           * @notice Updates the implementation of the PoolConfigurator, or creates a proxy
                                                           * setting the new `PoolConfigurator` implementation when the function is called for the first time.
                                                           * @param newPoolConfiguratorImpl The new PoolConfigurator implementation
                                                           */
                                                          function setPoolConfiguratorImpl(address newPoolConfiguratorImpl) external;
                                                          /**
                                                           * @notice Returns the address of the price oracle.
                                                           * @return The address of the PriceOracle
                                                           */
                                                          function getPriceOracle() external view returns (address);
                                                          /**
                                                           * @notice Updates the address of the price oracle.
                                                           * @param newPriceOracle The address of the new PriceOracle
                                                           */
                                                          function setPriceOracle(address newPriceOracle) external;
                                                          /**
                                                           * @notice Returns the address of the ACL manager.
                                                           * @return The address of the ACLManager
                                                           */
                                                          function getACLManager() external view returns (address);
                                                          /**
                                                           * @notice Updates the address of the ACL manager.
                                                           * @param newAclManager The address of the new ACLManager
                                                           */
                                                          function setACLManager(address newAclManager) external;
                                                          /**
                                                           * @notice Returns the address of the ACL admin.
                                                           * @return The address of the ACL admin
                                                           */
                                                          function getACLAdmin() external view returns (address);
                                                          /**
                                                           * @notice Updates the address of the ACL admin.
                                                           * @param newAclAdmin The address of the new ACL admin
                                                           */
                                                          function setACLAdmin(address newAclAdmin) external;
                                                          /**
                                                           * @notice Returns the address of the price oracle sentinel.
                                                           * @return The address of the PriceOracleSentinel
                                                           */
                                                          function getPriceOracleSentinel() external view returns (address);
                                                          /**
                                                           * @notice Updates the address of the price oracle sentinel.
                                                           * @param newPriceOracleSentinel The address of the new PriceOracleSentinel
                                                           */
                                                          function setPriceOracleSentinel(address newPriceOracleSentinel) external;
                                                          /**
                                                           * @notice Returns the address of the data provider.
                                                           * @return The address of the DataProvider
                                                           */
                                                          function getPoolDataProvider() external view returns (address);
                                                          /**
                                                           * @notice Updates the address of the data provider.
                                                           * @param newDataProvider The address of the new DataProvider
                                                           */
                                                          function setPoolDataProvider(address newDataProvider) external;
                                                        }
                                                        // SPDX-License-Identifier: BUSL-1.1
                                                        pragma solidity 0.8.10;
                                                        import {Ownable} from '../../dependencies/openzeppelin/contracts/Ownable.sol';
                                                        import {IPoolAddressesProvider} from '../../interfaces/IPoolAddressesProvider.sol';
                                                        import {InitializableImmutableAdminUpgradeabilityProxy} from '../libraries/aave-upgradeability/InitializableImmutableAdminUpgradeabilityProxy.sol';
                                                        /**
                                                         * @title PoolAddressesProvider
                                                         * @author Aave
                                                         * @notice Main registry of addresses part of or connected to the protocol, including permissioned roles
                                                         * @dev Acts as factory of proxies and admin of those, so with right to change its implementations
                                                         * @dev Owned by the Aave Governance
                                                         */
                                                        contract PoolAddressesProvider is Ownable, IPoolAddressesProvider {
                                                          // Identifier of the Aave Market
                                                          string private _marketId;
                                                          // Map of registered addresses (identifier => registeredAddress)
                                                          mapping(bytes32 => address) private _addresses;
                                                          // Main identifiers
                                                          bytes32 private constant POOL = 'POOL';
                                                          bytes32 private constant POOL_CONFIGURATOR = 'POOL_CONFIGURATOR';
                                                          bytes32 private constant PRICE_ORACLE = 'PRICE_ORACLE';
                                                          bytes32 private constant ACL_MANAGER = 'ACL_MANAGER';
                                                          bytes32 private constant ACL_ADMIN = 'ACL_ADMIN';
                                                          bytes32 private constant PRICE_ORACLE_SENTINEL = 'PRICE_ORACLE_SENTINEL';
                                                          bytes32 private constant DATA_PROVIDER = 'DATA_PROVIDER';
                                                          /**
                                                           * @dev Constructor.
                                                           * @param marketId The identifier of the market.
                                                           * @param owner The owner address of this contract.
                                                           */
                                                          constructor(string memory marketId, address owner) {
                                                            _setMarketId(marketId);
                                                            transferOwnership(owner);
                                                          }
                                                          /// @inheritdoc IPoolAddressesProvider
                                                          function getMarketId() external view override returns (string memory) {
                                                            return _marketId;
                                                          }
                                                          /// @inheritdoc IPoolAddressesProvider
                                                          function setMarketId(string memory newMarketId) external override onlyOwner {
                                                            _setMarketId(newMarketId);
                                                          }
                                                          /// @inheritdoc IPoolAddressesProvider
                                                          function getAddress(bytes32 id) public view override returns (address) {
                                                            return _addresses[id];
                                                          }
                                                          /// @inheritdoc IPoolAddressesProvider
                                                          function setAddress(bytes32 id, address newAddress) external override onlyOwner {
                                                            address oldAddress = _addresses[id];
                                                            _addresses[id] = newAddress;
                                                            emit AddressSet(id, oldAddress, newAddress);
                                                          }
                                                          /// @inheritdoc IPoolAddressesProvider
                                                          function setAddressAsProxy(bytes32 id, address newImplementationAddress)
                                                            external
                                                            override
                                                            onlyOwner
                                                          {
                                                            address proxyAddress = _addresses[id];
                                                            address oldImplementationAddress = _getProxyImplementation(id);
                                                            _updateImpl(id, newImplementationAddress);
                                                            emit AddressSetAsProxy(id, proxyAddress, oldImplementationAddress, newImplementationAddress);
                                                          }
                                                          /// @inheritdoc IPoolAddressesProvider
                                                          function getPool() external view override returns (address) {
                                                            return getAddress(POOL);
                                                          }
                                                          /// @inheritdoc IPoolAddressesProvider
                                                          function setPoolImpl(address newPoolImpl) external override onlyOwner {
                                                            address oldPoolImpl = _getProxyImplementation(POOL);
                                                            _updateImpl(POOL, newPoolImpl);
                                                            emit PoolUpdated(oldPoolImpl, newPoolImpl);
                                                          }
                                                          /// @inheritdoc IPoolAddressesProvider
                                                          function getPoolConfigurator() external view override returns (address) {
                                                            return getAddress(POOL_CONFIGURATOR);
                                                          }
                                                          /// @inheritdoc IPoolAddressesProvider
                                                          function setPoolConfiguratorImpl(address newPoolConfiguratorImpl) external override onlyOwner {
                                                            address oldPoolConfiguratorImpl = _getProxyImplementation(POOL_CONFIGURATOR);
                                                            _updateImpl(POOL_CONFIGURATOR, newPoolConfiguratorImpl);
                                                            emit PoolConfiguratorUpdated(oldPoolConfiguratorImpl, newPoolConfiguratorImpl);
                                                          }
                                                          /// @inheritdoc IPoolAddressesProvider
                                                          function getPriceOracle() external view override returns (address) {
                                                            return getAddress(PRICE_ORACLE);
                                                          }
                                                          /// @inheritdoc IPoolAddressesProvider
                                                          function setPriceOracle(address newPriceOracle) external override onlyOwner {
                                                            address oldPriceOracle = _addresses[PRICE_ORACLE];
                                                            _addresses[PRICE_ORACLE] = newPriceOracle;
                                                            emit PriceOracleUpdated(oldPriceOracle, newPriceOracle);
                                                          }
                                                          /// @inheritdoc IPoolAddressesProvider
                                                          function getACLManager() external view override returns (address) {
                                                            return getAddress(ACL_MANAGER);
                                                          }
                                                          /// @inheritdoc IPoolAddressesProvider
                                                          function setACLManager(address newAclManager) external override onlyOwner {
                                                            address oldAclManager = _addresses[ACL_MANAGER];
                                                            _addresses[ACL_MANAGER] = newAclManager;
                                                            emit ACLManagerUpdated(oldAclManager, newAclManager);
                                                          }
                                                          /// @inheritdoc IPoolAddressesProvider
                                                          function getACLAdmin() external view override returns (address) {
                                                            return getAddress(ACL_ADMIN);
                                                          }
                                                          /// @inheritdoc IPoolAddressesProvider
                                                          function setACLAdmin(address newAclAdmin) external override onlyOwner {
                                                            address oldAclAdmin = _addresses[ACL_ADMIN];
                                                            _addresses[ACL_ADMIN] = newAclAdmin;
                                                            emit ACLAdminUpdated(oldAclAdmin, newAclAdmin);
                                                          }
                                                          /// @inheritdoc IPoolAddressesProvider
                                                          function getPriceOracleSentinel() external view override returns (address) {
                                                            return getAddress(PRICE_ORACLE_SENTINEL);
                                                          }
                                                          /// @inheritdoc IPoolAddressesProvider
                                                          function setPriceOracleSentinel(address newPriceOracleSentinel) external override onlyOwner {
                                                            address oldPriceOracleSentinel = _addresses[PRICE_ORACLE_SENTINEL];
                                                            _addresses[PRICE_ORACLE_SENTINEL] = newPriceOracleSentinel;
                                                            emit PriceOracleSentinelUpdated(oldPriceOracleSentinel, newPriceOracleSentinel);
                                                          }
                                                          /// @inheritdoc IPoolAddressesProvider
                                                          function getPoolDataProvider() external view override returns (address) {
                                                            return getAddress(DATA_PROVIDER);
                                                          }
                                                          /// @inheritdoc IPoolAddressesProvider
                                                          function setPoolDataProvider(address newDataProvider) external override onlyOwner {
                                                            address oldDataProvider = _addresses[DATA_PROVIDER];
                                                            _addresses[DATA_PROVIDER] = newDataProvider;
                                                            emit PoolDataProviderUpdated(oldDataProvider, newDataProvider);
                                                          }
                                                          /**
                                                           * @notice Internal function to update the implementation of a specific proxied component of the protocol.
                                                           * @dev If there is no proxy registered with the given identifier, it creates the proxy setting `newAddress`
                                                           *   as implementation and calls the initialize() function on the proxy
                                                           * @dev If there is already a proxy registered, it just updates the implementation to `newAddress` and
                                                           *   calls the initialize() function via upgradeToAndCall() in the proxy
                                                           * @param id The id of the proxy to be updated
                                                           * @param newAddress The address of the new implementation
                                                           */
                                                          function _updateImpl(bytes32 id, address newAddress) internal {
                                                            address proxyAddress = _addresses[id];
                                                            InitializableImmutableAdminUpgradeabilityProxy proxy;
                                                            bytes memory params = abi.encodeWithSignature('initialize(address)', address(this));
                                                            if (proxyAddress == address(0)) {
                                                              proxy = new InitializableImmutableAdminUpgradeabilityProxy(address(this));
                                                              _addresses[id] = proxyAddress = address(proxy);
                                                              proxy.initialize(newAddress, params);
                                                              emit ProxyCreated(id, proxyAddress, newAddress);
                                                            } else {
                                                              proxy = InitializableImmutableAdminUpgradeabilityProxy(payable(proxyAddress));
                                                              proxy.upgradeToAndCall(newAddress, params);
                                                            }
                                                          }
                                                          /**
                                                           * @notice Updates the identifier of the Aave market.
                                                           * @param newMarketId The new id of the market
                                                           */
                                                          function _setMarketId(string memory newMarketId) internal {
                                                            string memory oldMarketId = _marketId;
                                                            _marketId = newMarketId;
                                                            emit MarketIdSet(oldMarketId, newMarketId);
                                                          }
                                                          /**
                                                           * @notice Returns the the implementation contract of the proxy contract by its identifier.
                                                           * @dev It returns ZERO if there is no registered address with the given id
                                                           * @dev It reverts if the registered address with the given id is not `InitializableImmutableAdminUpgradeabilityProxy`
                                                           * @param id The id
                                                           * @return The address of the implementation contract
                                                           */
                                                          function _getProxyImplementation(bytes32 id) internal returns (address) {
                                                            address proxyAddress = _addresses[id];
                                                            if (proxyAddress == address(0)) {
                                                              return address(0);
                                                            } else {
                                                              address payable payableProxyAddress = payable(proxyAddress);
                                                              return InitializableImmutableAdminUpgradeabilityProxy(payableProxyAddress).implementation();
                                                            }
                                                          }
                                                        }
                                                        // SPDX-License-Identifier: AGPL-3.0
                                                        pragma solidity 0.8.10;
                                                        import {BaseUpgradeabilityProxy} from '../../../dependencies/openzeppelin/upgradeability/BaseUpgradeabilityProxy.sol';
                                                        /**
                                                         * @title BaseImmutableAdminUpgradeabilityProxy
                                                         * @author Aave, inspired by the OpenZeppelin upgradeability proxy pattern
                                                         * @notice This contract combines an upgradeability proxy with an authorization
                                                         * mechanism for administrative tasks.
                                                         * @dev The admin role is stored in an immutable, which helps saving transactions costs
                                                         * All external functions in this contract must be guarded by the
                                                         * `ifAdmin` modifier. See ethereum/solidity#3864 for a Solidity
                                                         * feature proposal that would enable this to be done automatically.
                                                         */
                                                        contract BaseImmutableAdminUpgradeabilityProxy is BaseUpgradeabilityProxy {
                                                          address internal immutable _admin;
                                                          /**
                                                           * @dev Constructor.
                                                           * @param admin The address of the admin
                                                           */
                                                          constructor(address admin) {
                                                            _admin = admin;
                                                          }
                                                          modifier ifAdmin() {
                                                            if (msg.sender == _admin) {
                                                              _;
                                                            } else {
                                                              _fallback();
                                                            }
                                                          }
                                                          /**
                                                           * @notice Return the admin address
                                                           * @return The address of the proxy admin.
                                                           */
                                                          function admin() external ifAdmin returns (address) {
                                                            return _admin;
                                                          }
                                                          /**
                                                           * @notice Return the implementation address
                                                           * @return The address of the implementation.
                                                           */
                                                          function implementation() external ifAdmin returns (address) {
                                                            return _implementation();
                                                          }
                                                          /**
                                                           * @notice Upgrade the backing implementation of the proxy.
                                                           * @dev Only the admin can call this function.
                                                           * @param newImplementation The address of the new implementation.
                                                           */
                                                          function upgradeTo(address newImplementation) external ifAdmin {
                                                            _upgradeTo(newImplementation);
                                                          }
                                                          /**
                                                           * @notice Upgrade the backing implementation of the proxy and call a function
                                                           * on the new implementation.
                                                           * @dev This is useful to initialize the proxied contract.
                                                           * @param newImplementation The address of the new implementation.
                                                           * @param data Data to send as msg.data in the low level call.
                                                           * It should include the signature and the parameters of the function to be called, as described in
                                                           * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
                                                           */
                                                          function upgradeToAndCall(address newImplementation, bytes calldata data)
                                                            external
                                                            payable
                                                            ifAdmin
                                                          {
                                                            _upgradeTo(newImplementation);
                                                            (bool success, ) = newImplementation.delegatecall(data);
                                                            require(success);
                                                          }
                                                          /**
                                                           * @notice Only fall back when the sender is not the admin.
                                                           */
                                                          function _willFallback() internal virtual override {
                                                            require(msg.sender != _admin, 'Cannot call fallback function from the proxy admin');
                                                            super._willFallback();
                                                          }
                                                        }
                                                        // SPDX-License-Identifier: AGPL-3.0
                                                        pragma solidity 0.8.10;
                                                        import {InitializableUpgradeabilityProxy} from '../../../dependencies/openzeppelin/upgradeability/InitializableUpgradeabilityProxy.sol';
                                                        import {Proxy} from '../../../dependencies/openzeppelin/upgradeability/Proxy.sol';
                                                        import {BaseImmutableAdminUpgradeabilityProxy} from './BaseImmutableAdminUpgradeabilityProxy.sol';
                                                        /**
                                                         * @title InitializableAdminUpgradeabilityProxy
                                                         * @author Aave
                                                         * @dev Extends BaseAdminUpgradeabilityProxy with an initializer function
                                                         */
                                                        contract InitializableImmutableAdminUpgradeabilityProxy is
                                                          BaseImmutableAdminUpgradeabilityProxy,
                                                          InitializableUpgradeabilityProxy
                                                        {
                                                          /**
                                                           * @dev Constructor.
                                                           * @param admin The address of the admin
                                                           */
                                                          constructor(address admin) BaseImmutableAdminUpgradeabilityProxy(admin) {
                                                            // Intentionally left blank
                                                          }
                                                          /// @inheritdoc BaseImmutableAdminUpgradeabilityProxy
                                                          function _willFallback() internal override(BaseImmutableAdminUpgradeabilityProxy, Proxy) {
                                                            BaseImmutableAdminUpgradeabilityProxy._willFallback();
                                                          }
                                                        }
                                                        

                                                        File 12 of 13: 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 13 of 13: DefaultReserveInterestRateStrategyV2
                                                        // SPDX-License-Identifier: MIT
                                                        pragma solidity ^0.8.0;
                                                        import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol';
                                                        import {WadRayMath} from '../protocol/libraries/math/WadRayMath.sol';
                                                        import {PercentageMath} from '../protocol/libraries/math/PercentageMath.sol';
                                                        import {DataTypes} from '../protocol/libraries/types/DataTypes.sol';
                                                        import {Errors} from '../protocol/libraries/helpers/Errors.sol';
                                                        import {IDefaultInterestRateStrategyV2} from '../interfaces/IDefaultInterestRateStrategyV2.sol';
                                                        import {IReserveInterestRateStrategy} from '../interfaces/IReserveInterestRateStrategy.sol';
                                                        import {IPoolAddressesProvider} from '../interfaces/IPoolAddressesProvider.sol';
                                                        /**
                                                         * @title DefaultReserveInterestRateStrategyV2 contract
                                                         * @author BGD Labs
                                                         * @notice Default interest rate strategy used by the Aave protocol
                                                         * @dev Strategies are pool-specific: each contract CAN'T be used across different Aave pools
                                                         *   due to the caching of the PoolAddressesProvider and the usage of underlying addresses as
                                                         *   index of the _interestRateData
                                                         */
                                                        contract DefaultReserveInterestRateStrategyV2 is IDefaultInterestRateStrategyV2 {
                                                          using WadRayMath for uint256;
                                                          using PercentageMath for uint256;
                                                          struct CalcInterestRatesLocalVars {
                                                            uint256 availableLiquidity;
                                                            uint256 currentVariableBorrowRate;
                                                            uint256 currentLiquidityRate;
                                                            uint256 borrowUsageRatio;
                                                            uint256 supplyUsageRatio;
                                                            uint256 availableLiquidityPlusDebt;
                                                          }
                                                          /// @inheritdoc IDefaultInterestRateStrategyV2
                                                          IPoolAddressesProvider public immutable ADDRESSES_PROVIDER;
                                                          /// @inheritdoc IDefaultInterestRateStrategyV2
                                                          uint256 public constant MAX_BORROW_RATE = 1000_00;
                                                          /// @inheritdoc IDefaultInterestRateStrategyV2
                                                          uint256 public constant MIN_OPTIMAL_POINT = 1_00;
                                                          /// @inheritdoc IDefaultInterestRateStrategyV2
                                                          uint256 public constant MAX_OPTIMAL_POINT = 99_00;
                                                          /// @dev Map of reserves address and their interest rate data (reserveAddress => interestRateData)
                                                          mapping(address => InterestRateData) internal _interestRateData;
                                                          modifier onlyPoolConfigurator() {
                                                            require(
                                                              msg.sender == ADDRESSES_PROVIDER.getPoolConfigurator(),
                                                              Errors.CALLER_NOT_POOL_CONFIGURATOR
                                                            );
                                                            _;
                                                          }
                                                          /**
                                                           * @dev Constructor.
                                                           * @param provider The address of the PoolAddressesProvider of the associated Aave pool
                                                           */
                                                          constructor(address provider) {
                                                            require(provider != address(0), Errors.INVALID_ADDRESSES_PROVIDER);
                                                            ADDRESSES_PROVIDER = IPoolAddressesProvider(provider);
                                                          }
                                                          /// @inheritdoc IReserveInterestRateStrategy
                                                          function setInterestRateParams(
                                                            address reserve,
                                                            bytes calldata rateData
                                                          ) external onlyPoolConfigurator {
                                                            _setInterestRateParams(reserve, abi.decode(rateData, (InterestRateData)));
                                                          }
                                                          /// @inheritdoc IDefaultInterestRateStrategyV2
                                                          function setInterestRateParams(
                                                            address reserve,
                                                            InterestRateData calldata rateData
                                                          ) external onlyPoolConfigurator {
                                                            _setInterestRateParams(reserve, rateData);
                                                          }
                                                          /// @inheritdoc IDefaultInterestRateStrategyV2
                                                          function getInterestRateData(address reserve) external view returns (InterestRateDataRay memory) {
                                                            return _rayifyRateData(_interestRateData[reserve]);
                                                          }
                                                          /// @inheritdoc IDefaultInterestRateStrategyV2
                                                          function getInterestRateDataBps(address reserve) external view returns (InterestRateData memory) {
                                                            return _interestRateData[reserve];
                                                          }
                                                          /// @inheritdoc IDefaultInterestRateStrategyV2
                                                          function getOptimalUsageRatio(address reserve) external view returns (uint256) {
                                                            return _bpsToRay(uint256(_interestRateData[reserve].optimalUsageRatio));
                                                          }
                                                          /// @inheritdoc IDefaultInterestRateStrategyV2
                                                          function getVariableRateSlope1(address reserve) external view returns (uint256) {
                                                            return _bpsToRay(uint256(_interestRateData[reserve].variableRateSlope1));
                                                          }
                                                          /// @inheritdoc IDefaultInterestRateStrategyV2
                                                          function getVariableRateSlope2(address reserve) external view returns (uint256) {
                                                            return _bpsToRay(uint256(_interestRateData[reserve].variableRateSlope2));
                                                          }
                                                          /// @inheritdoc IDefaultInterestRateStrategyV2
                                                          function getBaseVariableBorrowRate(address reserve) external view override returns (uint256) {
                                                            return _bpsToRay(uint256(_interestRateData[reserve].baseVariableBorrowRate));
                                                          }
                                                          /// @inheritdoc IDefaultInterestRateStrategyV2
                                                          function getMaxVariableBorrowRate(address reserve) external view override returns (uint256) {
                                                            return
                                                              _bpsToRay(
                                                                uint256(
                                                                  _interestRateData[reserve].baseVariableBorrowRate +
                                                                    _interestRateData[reserve].variableRateSlope1 +
                                                                    _interestRateData[reserve].variableRateSlope2
                                                                )
                                                              );
                                                          }
                                                          /// @inheritdoc IReserveInterestRateStrategy
                                                          function calculateInterestRates(
                                                            DataTypes.CalculateInterestRatesParams memory params
                                                          ) external view virtual override returns (uint256, uint256) {
                                                            InterestRateDataRay memory rateData = _rayifyRateData(_interestRateData[params.reserve]);
                                                            // @note This is a short circuit to allow mintable assets (ex. GHO), which by definition cannot be supplied
                                                            // and thus do not use virtual underlying balances.
                                                            if (!params.usingVirtualBalance) {
                                                              return (0, rateData.baseVariableBorrowRate);
                                                            }
                                                            CalcInterestRatesLocalVars memory vars;
                                                            vars.currentLiquidityRate = 0;
                                                            vars.currentVariableBorrowRate = rateData.baseVariableBorrowRate;
                                                            if (params.totalDebt != 0) {
                                                              vars.availableLiquidity =
                                                                params.virtualUnderlyingBalance +
                                                                params.liquidityAdded -
                                                                params.liquidityTaken;
                                                              vars.availableLiquidityPlusDebt = vars.availableLiquidity + params.totalDebt;
                                                              vars.borrowUsageRatio = params.totalDebt.rayDiv(vars.availableLiquidityPlusDebt);
                                                              vars.supplyUsageRatio = params.totalDebt.rayDiv(
                                                                vars.availableLiquidityPlusDebt + params.unbacked
                                                              );
                                                            } else {
                                                              return (0, vars.currentVariableBorrowRate);
                                                            }
                                                            if (vars.borrowUsageRatio > rateData.optimalUsageRatio) {
                                                              uint256 excessBorrowUsageRatio = (vars.borrowUsageRatio - rateData.optimalUsageRatio).rayDiv(
                                                                WadRayMath.RAY - rateData.optimalUsageRatio
                                                              );
                                                              vars.currentVariableBorrowRate +=
                                                                rateData.variableRateSlope1 +
                                                                rateData.variableRateSlope2.rayMul(excessBorrowUsageRatio);
                                                            } else {
                                                              vars.currentVariableBorrowRate += rateData
                                                                .variableRateSlope1
                                                                .rayMul(vars.borrowUsageRatio)
                                                                .rayDiv(rateData.optimalUsageRatio);
                                                            }
                                                            vars.currentLiquidityRate = vars
                                                              .currentVariableBorrowRate
                                                              .rayMul(vars.supplyUsageRatio)
                                                              .percentMul(PercentageMath.PERCENTAGE_FACTOR - params.reserveFactor);
                                                            return (vars.currentLiquidityRate, vars.currentVariableBorrowRate);
                                                          }
                                                          /**
                                                           * @dev Doing validations and data update for an asset
                                                           * @param reserve address of the underlying asset of the reserve
                                                           * @param rateData Encoded reserve interest rate data to apply
                                                           */
                                                          function _setInterestRateParams(address reserve, InterestRateData memory rateData) internal {
                                                            require(reserve != address(0), Errors.ZERO_ADDRESS_NOT_VALID);
                                                            require(
                                                              rateData.optimalUsageRatio <= MAX_OPTIMAL_POINT &&
                                                                rateData.optimalUsageRatio >= MIN_OPTIMAL_POINT,
                                                              Errors.INVALID_OPTIMAL_USAGE_RATIO
                                                            );
                                                            require(
                                                              rateData.variableRateSlope1 <= rateData.variableRateSlope2,
                                                              Errors.SLOPE_2_MUST_BE_GTE_SLOPE_1
                                                            );
                                                            // The maximum rate should not be above certain threshold
                                                            require(
                                                              uint256(rateData.baseVariableBorrowRate) +
                                                                uint256(rateData.variableRateSlope1) +
                                                                uint256(rateData.variableRateSlope2) <=
                                                                MAX_BORROW_RATE,
                                                              Errors.INVALID_MAX_RATE
                                                            );
                                                            _interestRateData[reserve] = rateData;
                                                            emit RateDataUpdate(
                                                              reserve,
                                                              rateData.optimalUsageRatio,
                                                              rateData.baseVariableBorrowRate,
                                                              rateData.variableRateSlope1,
                                                              rateData.variableRateSlope2
                                                            );
                                                          }
                                                          /**
                                                           * @dev Transforms an InterestRateData struct to an InterestRateDataRay struct by multiplying all values
                                                           * by 1e23, turning them into ray values
                                                           *
                                                           * @param data The InterestRateData struct to transform
                                                           *
                                                           * @return The resulting InterestRateDataRay struct
                                                           */
                                                          function _rayifyRateData(
                                                            InterestRateData memory data
                                                          ) internal pure returns (InterestRateDataRay memory) {
                                                            return
                                                              InterestRateDataRay({
                                                                optimalUsageRatio: _bpsToRay(uint256(data.optimalUsageRatio)),
                                                                baseVariableBorrowRate: _bpsToRay(uint256(data.baseVariableBorrowRate)),
                                                                variableRateSlope1: _bpsToRay(uint256(data.variableRateSlope1)),
                                                                variableRateSlope2: _bpsToRay(uint256(data.variableRateSlope2))
                                                              });
                                                          }
                                                          // @dev helper function added here, as generally the protocol doesn't use bps
                                                          function _bpsToRay(uint256 n) internal pure returns (uint256) {
                                                            return n * 1e23;
                                                          }
                                                        }
                                                        // SPDX-License-Identifier: MIT
                                                        pragma solidity ^0.8.0;
                                                        /**
                                                         * @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: 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;
                                                        /**
                                                         * @title PercentageMath library
                                                         * @author Aave
                                                         * @notice Provides functions to perform percentage calculations
                                                         * @dev Percentages are defined by default with 2 decimals of precision (100.00). The precision is indicated by PERCENTAGE_FACTOR
                                                         * @dev Operations are rounded. If a value is >=.5, will be rounded up, otherwise rounded down.
                                                         */
                                                        library PercentageMath {
                                                          // Maximum percentage factor (100.00%)
                                                          uint256 internal constant PERCENTAGE_FACTOR = 1e4;
                                                          // Half percentage factor (50.00%)
                                                          uint256 internal constant HALF_PERCENTAGE_FACTOR = 0.5e4;
                                                          /**
                                                           * @notice Executes a percentage multiplication
                                                           * @dev assembly optimized for improved gas savings, see https://twitter.com/transmissions11/status/1451131036377571328
                                                           * @param value The value of which the percentage needs to be calculated
                                                           * @param percentage The percentage of the value to be calculated
                                                           * @return result value percentmul percentage
                                                           */
                                                          function percentMul(uint256 value, uint256 percentage) internal pure returns (uint256 result) {
                                                            // to avoid overflow, value <= (type(uint256).max - HALF_PERCENTAGE_FACTOR) / percentage
                                                            assembly {
                                                              if iszero(
                                                                or(
                                                                  iszero(percentage),
                                                                  iszero(gt(value, div(sub(not(0), HALF_PERCENTAGE_FACTOR), percentage)))
                                                                )
                                                              ) {
                                                                revert(0, 0)
                                                              }
                                                              result := div(add(mul(value, percentage), HALF_PERCENTAGE_FACTOR), PERCENTAGE_FACTOR)
                                                            }
                                                          }
                                                          /**
                                                           * @notice Executes a percentage division
                                                           * @dev assembly optimized for improved gas savings, see https://twitter.com/transmissions11/status/1451131036377571328
                                                           * @param value The value of which the percentage needs to be calculated
                                                           * @param percentage The percentage of the value to be calculated
                                                           * @return result value percentdiv percentage
                                                           */
                                                          function percentDiv(uint256 value, uint256 percentage) internal pure returns (uint256 result) {
                                                            // to avoid overflow, value <= (type(uint256).max - halfPercentage) / PERCENTAGE_FACTOR
                                                            assembly {
                                                              if or(
                                                                iszero(percentage),
                                                                iszero(iszero(gt(value, div(sub(not(0), div(percentage, 2)), PERCENTAGE_FACTOR))))
                                                              ) {
                                                                revert(0, 0)
                                                              }
                                                              result := div(add(mul(value, PERCENTAGE_FACTOR), div(percentage, 2)), percentage)
                                                            }
                                                          }
                                                        }
                                                        // SPDX-License-Identifier: MIT
                                                        pragma solidity ^0.8.0;
                                                        library DataTypes {
                                                          /**
                                                           * This exists specifically to maintain the `getReserveData()` interface, since the new, internal
                                                           * `ReserveData` struct includes the reserve's `virtualUnderlyingBalance`.
                                                           */
                                                          struct ReserveDataLegacy {
                                                            //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;
                                                            // DEPRECATED on v3.2.0
                                                            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;
                                                            // DEPRECATED on v3.2.0
                                                            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 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;
                                                            // DEPRECATED on v3.2.0
                                                            uint128 __deprecatedStableBorrowRate;
                                                            //timestamp of last update
                                                            uint40 lastUpdateTimestamp;
                                                            //the id of the reserve. Represents the position in the list of the active reserves
                                                            uint16 id;
                                                            //timestamp until when liquidations are not allowed on the reserve, if set to past liquidations will be allowed
                                                            uint40 liquidationGracePeriodUntil;
                                                            //aToken address
                                                            address aTokenAddress;
                                                            // DEPRECATED on v3.2.0
                                                            address __deprecatedStableDebtTokenAddress;
                                                            //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;
                                                            //the amount of underlying accounted for by the protocol
                                                            uint128 virtualUnderlyingBalance;
                                                          }
                                                          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: DEPRECATED: stable rate borrowing enabled
                                                            //bit 60: asset is paused
                                                            //bit 61: borrowing in isolation mode is enabled
                                                            //bit 62: siloed borrowing enabled
                                                            //bit 63: flashloaning enabled
                                                            //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: DEPRECATED: 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: virtual accounting is enabled for the reserve
                                                            //bit 253-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;
                                                          }
                                                          // DEPRECATED: kept for backwards compatibility, might be removed in a future version
                                                          struct EModeCategoryLegacy {
                                                            // each eMode category has a custom ltv and liquidation threshold
                                                            uint16 ltv;
                                                            uint16 liquidationThreshold;
                                                            uint16 liquidationBonus;
                                                            // DEPRECATED
                                                            address priceSource;
                                                            string label;
                                                          }
                                                          struct CollateralConfig {
                                                            uint16 ltv;
                                                            uint16 liquidationThreshold;
                                                            uint16 liquidationBonus;
                                                          }
                                                          struct EModeCategoryBaseConfiguration {
                                                            uint16 ltv;
                                                            uint16 liquidationThreshold;
                                                            uint16 liquidationBonus;
                                                            string label;
                                                          }
                                                          struct EModeCategory {
                                                            // each eMode category has a custom ltv and liquidation threshold
                                                            uint16 ltv;
                                                            uint16 liquidationThreshold;
                                                            uint16 liquidationBonus;
                                                            uint128 collateralBitmap;
                                                            string label;
                                                            uint128 borrowableBitmap;
                                                          }
                                                          enum InterestRateMode {
                                                            NONE,
                                                            __DEPRECATED,
                                                            VARIABLE
                                                          }
                                                          struct ReserveCache {
                                                            uint256 currScaledVariableDebt;
                                                            uint256 nextScaledVariableDebt;
                                                            uint256 currLiquidityIndex;
                                                            uint256 nextLiquidityIndex;
                                                            uint256 currVariableBorrowIndex;
                                                            uint256 nextVariableBorrowIndex;
                                                            uint256 currLiquidityRate;
                                                            uint256 currVariableBorrowRate;
                                                            uint256 reserveFactor;
                                                            ReserveConfigurationMap reserveConfiguration;
                                                            address aTokenAddress;
                                                            address variableDebtTokenAddress;
                                                            uint40 reserveLastUpdateTimestamp;
                                                          }
                                                          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 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 reservesCount;
                                                            address addressesProvider;
                                                            address pool;
                                                            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 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 totalDebt;
                                                            uint256 reserveFactor;
                                                            address reserve;
                                                            bool usingVirtualBalance;
                                                            uint256 virtualUnderlyingBalance;
                                                          }
                                                          struct InitReserveParams {
                                                            address asset;
                                                            address aTokenAddress;
                                                            address variableDebtAddress;
                                                            address interestRateStrategyAddress;
                                                            uint16 reservesCount;
                                                            uint16 maxNumberReserves;
                                                          }
                                                        }
                                                        // SPDX-License-Identifier: MIT
                                                        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 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 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_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 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_OR_LTV_ZERO = '62'; // 'User is in isolation mode or ltv is zero'
                                                          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 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 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
                                                          string public constant INVALID_MAX_RATE = '92'; // The expect maximum borrow rate is invalid
                                                          string public constant WITHDRAW_TO_ATOKEN = '93'; // Withdrawing to the aToken is not allowed
                                                          string public constant SUPPLY_TO_ATOKEN = '94'; // Supplying to the aToken is not allowed
                                                          string public constant SLOPE_2_MUST_BE_GTE_SLOPE_1 = '95'; // Variable interest rate slope 2 can not be lower than slope 1
                                                          string public constant CALLER_NOT_RISK_OR_POOL_OR_EMERGENCY_ADMIN = '96'; // 'The caller of the function is not a risk, pool or emergency admin'
                                                          string public constant LIQUIDATION_GRACE_SENTINEL_CHECK_FAILED = '97'; // 'Liquidation grace sentinel validation failed'
                                                          string public constant INVALID_GRACE_PERIOD = '98'; // Grace period above a valid range
                                                          string public constant INVALID_FREEZE_STATE = '99'; // Reserve is already in the passed freeze state
                                                          string public constant NOT_BORROWABLE_IN_EMODE = '100'; // Asset not borrowable in eMode
                                                        }
                                                        // SPDX-License-Identifier: MIT
                                                        pragma solidity ^0.8.0;
                                                        import {IReserveInterestRateStrategy} from './IReserveInterestRateStrategy.sol';
                                                        import {IPoolAddressesProvider} from './IPoolAddressesProvider.sol';
                                                        /**
                                                         * @title IDefaultInterestRateStrategyV2
                                                         * @author BGD Labs
                                                         * @notice Interface of the default interest rate strategy used by the Aave protocol
                                                         */
                                                        interface IDefaultInterestRateStrategyV2 is IReserveInterestRateStrategy {
                                                          /**
                                                           * @notice Holds the interest rate data for a given reserve
                                                           *
                                                           * @dev Since values are in bps, they are multiplied by 1e23 in order to become rays with 27 decimals. This
                                                           * in turn means that the maximum supported interest rate is 4294967295 (2**32-1) bps or 42949672.95%.
                                                           *
                                                           * @param optimalUsageRatio The optimal usage ratio, in bps
                                                           * @param baseVariableBorrowRate The base variable borrow rate, in bps
                                                           * @param variableRateSlope1 The slope of the variable interest curve, before hitting the optimal ratio, in bps
                                                           * @param variableRateSlope2 The slope of the variable interest curve, after hitting the optimal ratio, in bps
                                                           */
                                                          struct InterestRateData {
                                                            uint16 optimalUsageRatio;
                                                            uint32 baseVariableBorrowRate;
                                                            uint32 variableRateSlope1;
                                                            uint32 variableRateSlope2;
                                                          }
                                                          /**
                                                           * @notice The interest rate data, where all values are in ray (fixed-point 27 decimal numbers) for a given reserve,
                                                           * used in in-memory calculations.
                                                           *
                                                           * @param optimalUsageRatio The optimal usage ratio
                                                           * @param baseVariableBorrowRate The base variable borrow rate
                                                           * @param variableRateSlope1 The slope of the variable interest curve, before hitting the optimal ratio
                                                           * @param variableRateSlope2 The slope of the variable interest curve, after hitting the optimal ratio
                                                           */
                                                          struct InterestRateDataRay {
                                                            uint256 optimalUsageRatio;
                                                            uint256 baseVariableBorrowRate;
                                                            uint256 variableRateSlope1;
                                                            uint256 variableRateSlope2;
                                                          }
                                                          /**
                                                           * @notice emitted when new interest rate data is set in a reserve
                                                           *
                                                           * @param reserve address of the reserve that has new interest rate data set
                                                           * @param optimalUsageRatio The optimal usage ratio, in bps
                                                           * @param baseVariableBorrowRate The base variable borrow rate, in bps
                                                           * @param variableRateSlope1 The slope of the variable interest curve, before hitting the optimal ratio, in bps
                                                           * @param variableRateSlope2 The slope of the variable interest curve, after hitting the optimal ratio, in bps
                                                           */
                                                          event RateDataUpdate(
                                                            address indexed reserve,
                                                            uint256 optimalUsageRatio,
                                                            uint256 baseVariableBorrowRate,
                                                            uint256 variableRateSlope1,
                                                            uint256 variableRateSlope2
                                                          );
                                                          /**
                                                           * @notice Returns the address of the PoolAddressesProvider
                                                           * @return The address of the PoolAddressesProvider contract
                                                           */
                                                          function ADDRESSES_PROVIDER() external view returns (IPoolAddressesProvider);
                                                          /**
                                                           * @notice Returns the maximum value achievable for variable borrow rate, in bps
                                                           * @return The maximum rate
                                                           */
                                                          function MAX_BORROW_RATE() external view returns (uint256);
                                                          /**
                                                           * @notice Returns the minimum optimal point, in bps
                                                           * @return The optimal point
                                                           */
                                                          function MIN_OPTIMAL_POINT() external view returns (uint256);
                                                          /**
                                                           * @notice Returns the maximum optimal point, in bps
                                                           * @return The optimal point
                                                           */
                                                          function MAX_OPTIMAL_POINT() external view returns (uint256);
                                                          /**
                                                           * notice Returns the full InterestRateData object for the given reserve, in ray
                                                           *
                                                           * @param reserve The reserve to get the data of
                                                           *
                                                           * @return The InterestRateDataRay object for the given reserve
                                                           */
                                                          function getInterestRateData(address reserve) external view returns (InterestRateDataRay memory);
                                                          /**
                                                           * notice Returns the full InterestRateDataRay object for the given reserve, in bps
                                                           *
                                                           * @param reserve The reserve to get the data of
                                                           *
                                                           * @return The InterestRateData object for the given reserve
                                                           */
                                                          function getInterestRateDataBps(address reserve) external view returns (InterestRateData memory);
                                                          /**
                                                           * @notice Returns the optimal usage rate for the given reserve in ray
                                                           *
                                                           * @param reserve The reserve to get the optimal usage rate of
                                                           *
                                                           * @return The optimal usage rate is the level of borrow / collateral at which the borrow rate
                                                           */
                                                          function getOptimalUsageRatio(address reserve) external view returns (uint256);
                                                          /**
                                                           * @notice Returns the variable rate slope below optimal usage ratio in ray
                                                           * @dev It's the variable rate when usage ratio > 0 and <= OPTIMAL_USAGE_RATIO
                                                           *
                                                           * @param reserve The reserve to get the variable rate slope 1 of
                                                           *
                                                           * @return The variable rate slope
                                                           */
                                                          function getVariableRateSlope1(address reserve) external view returns (uint256);
                                                          /**
                                                           * @notice Returns the variable rate slope above optimal usage ratio in ray
                                                           * @dev It's the variable rate when usage ratio > OPTIMAL_USAGE_RATIO
                                                           *
                                                           * @param reserve The reserve to get the variable rate slope 2 of
                                                           *
                                                           * @return The variable rate slope
                                                           */
                                                          function getVariableRateSlope2(address reserve) external view returns (uint256);
                                                          /**
                                                           * @notice Returns the base variable borrow rate, in ray
                                                           *
                                                           * @param reserve The reserve to get the base variable borrow rate of
                                                           *
                                                           * @return The base variable borrow rate
                                                           */
                                                          function getBaseVariableBorrowRate(address reserve) external view returns (uint256);
                                                          /**
                                                           * @notice Returns the maximum variable borrow rate, in ray
                                                           *
                                                           * @param reserve The reserve to get the maximum variable borrow rate of
                                                           *
                                                           * @return The maximum variable borrow rate
                                                           */
                                                          function getMaxVariableBorrowRate(address reserve) external view returns (uint256);
                                                          /**
                                                           * @notice Sets interest rate data for an Aave rate strategy
                                                           * @param reserve The reserve to update
                                                           * @param rateData The reserve interest rate data to apply to the given reserve
                                                           *   Being specific to this custom implementation, with custom struct type,
                                                           *   overloading the function on the generic interface
                                                           */
                                                          function setInterestRateParams(address reserve, InterestRateData calldata rateData) external;
                                                        }
                                                        // SPDX-License-Identifier: MIT
                                                        pragma solidity ^0.8.0;
                                                        import {DataTypes} from '../protocol/libraries/types/DataTypes.sol';
                                                        /**
                                                         * @title IReserveInterestRateStrategy
                                                         * @author BGD Labs
                                                         * @notice Basic interface for any rate strategy used by the Aave protocol
                                                         */
                                                        interface IReserveInterestRateStrategy {
                                                          /**
                                                           * @notice Sets interest rate data for an Aave rate strategy
                                                           * @param reserve The reserve to update
                                                           * @param rateData The abi encoded reserve interest rate data to apply to the given reserve
                                                           *   Abstracted this way as rate strategies can be custom
                                                           */
                                                          function setInterestRateParams(address reserve, bytes calldata rateData) external;
                                                          /**
                                                           * @notice Calculates the interest rates depending on the reserve's state and configurations
                                                           * @param params The parameters needed to calculate interest rates
                                                           * @return liquidityRate The liquidity rate expressed in ray
                                                           * @return variableBorrowRate The variable borrow rate expressed in ray
                                                           */
                                                          function calculateInterestRates(
                                                            DataTypes.CalculateInterestRatesParams memory params
                                                          ) external view returns (uint256, uint256);
                                                        }
                                                        // SPDX-License-Identifier: MIT
                                                        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;
                                                        }