Transaction Hash:
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 | ||
|---|---|---|---|---|---|
| 0x23878914...A74D4086a | |||||
| 0x2b817B82...796CA37E0 | |||||
|
0x39634336...6fb82Aa49
Miner
| (quasarbuilder) | 20.85011031507206426 Eth | 20.850110329343503785 Eth | 0.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
File 2 of 13: InitializableImmutableAdminUpgradeabilityProxy
File 3 of 13: MapleTreasury
File 4 of 13: TetherToken
File 5 of 13: MaplePool
File 6 of 13: MapleAaveStrategy
File 7 of 13: NonTransparentProxy
File 8 of 13: MapleGlobals
File 9 of 13: Proxy
File 10 of 13: MaplePoolManager
File 11 of 13: PoolAddressesProvider
File 12 of 13: InitializableImmutableAdminUpgradeabilityProxy
File 13 of 13: DefaultReserveInterestRateStrategyV2
// 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;
}