@ensuro/core 1.2.7 → 2.0.0-beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -17
- package/build/contracts/EToken.sol/EToken.json +122 -177
- package/build/contracts/FlightDelayRiskModule.sol/FlightDelayRiskModule.json +101 -323
- package/build/contracts/LPManualWhitelist.sol/LPManualWhitelist.json +15 -2
- package/build/contracts/Policy.sol/Policy.json +2 -2
- package/build/contracts/PolicyNFT.sol/PolicyNFT.json +16 -3
- package/build/contracts/PolicyPool.sol/PolicyPool.json +105 -351
- package/build/contracts/PolicyPoolComponent.sol/PolicyPoolComponent.json +13 -0
- package/build/contracts/PolicyPoolConfig.sol/PolicyPoolConfig.json +77 -72
- package/build/contracts/PremiumsAccount.sol/PremiumsAccount.json +761 -0
- package/build/contracts/{BaseAssetManager.sol/BaseAssetManager.json → Reserve.sol/Reserve.json} +15 -202
- package/build/contracts/RiskModule.sol/RiskModule.json +83 -310
- package/build/contracts/TimeScaled.sol/TimeScaled.json +24 -0
- package/build/contracts/TrustfulRiskModule.sol/TrustfulRiskModule.json +131 -333
- package/build/contracts/dependencies/ChainlinkClientUpgradeable.sol/ChainlinkClientUpgradeable.json +15 -2
- package/build/contracts/dependencies/ERC1967Proxy.sol/ERC1967Proxy.json +64 -0
- package/build/{interfaces/IExchange.sol/IExchange.json → contracts/dependencies/IERC20Metadata.sol/IERC20Metadata.json} +83 -79
- package/build/{interfaces → contracts/interfaces}/IEToken.sol/IEToken.json +32 -97
- package/build/{interfaces → contracts/interfaces}/ILPWhitelist.sol/ILPWhitelist.json +1 -1
- package/build/{interfaces → contracts/interfaces}/IPolicyHolder.sol/IPolicyHolder.json +1 -1
- package/build/{interfaces → contracts/interfaces}/IPolicyNFT.sol/IPolicyNFT.json +1 -1
- package/build/{interfaces → contracts/interfaces}/IPolicyPool.sol/IPolicyPool.json +121 -108
- package/build/{interfaces → contracts/interfaces}/IPolicyPoolComponent.sol/IPolicyPoolComponent.json +1 -1
- package/build/{interfaces → contracts/interfaces}/IPolicyPoolConfig.sol/IPolicyPoolConfig.json +20 -36
- package/build/contracts/interfaces/IPremiumsAccount.sol/IPremiumsAccount.json +302 -0
- package/build/{interfaces → contracts/interfaces}/IRiskModule.sol/IRiskModule.json +58 -34
- package/build/contracts/mocks/ForwardProxy.sol/ForwardProxy.json +43 -0
- package/build/{interfaces/IInsolvencyHook.sol/IInsolvencyHook.json → contracts/mocks/IMintableERC20.sol/IMintableERC20.json} +13 -8
- package/build/contracts/mocks/LinkTokenMock.sol/LinkTokenMock.json +370 -0
- package/build/contracts/mocks/PolicyHolderMock.sol/PolicyHolderMock.json +202 -0
- package/build/contracts/mocks/PolicyPoolComponentMock.sol/PolicyPoolComponentMock.json +35 -0
- package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMock.json +603 -0
- package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMockForward.json +92 -0
- package/build/contracts/mocks/TestCurrency.sol/TestCurrency.json +343 -0
- package/build/contracts/mocks/TestCurrencyUUPS.sol/TestCurrencyUUPS.json +353 -0
- package/build/contracts/mocks/TestNFT.sol/TestNFT.json +388 -0
- package/build/contracts/upgraded/PolicyNFTv1.sol/PolicyNFTv1.json +16 -3
- package/build/contracts/upgraded/PolicyNFTv1.sol/PolicyNFTv1_Upgrade.json +16 -3
- package/contracts/EToken.sol +188 -269
- package/contracts/FlightDelayRiskModule.sol +30 -21
- package/contracts/LPManualWhitelist.sol +3 -3
- package/contracts/Policy.sol +48 -44
- package/contracts/PolicyNFT.sol +2 -2
- package/contracts/PolicyPool.sol +114 -467
- package/contracts/PolicyPoolComponent.sol +8 -3
- package/contracts/PolicyPoolConfig.sol +30 -73
- package/contracts/PremiumsAccount.sol +274 -0
- package/contracts/Reserve.sol +34 -0
- package/contracts/RiskModule.sol +216 -164
- package/contracts/TimeScaled.sol +134 -0
- package/contracts/TrustfulRiskModule.sol +23 -21
- package/contracts/dependencies/ERC1967Proxy.sol +19 -0
- package/contracts/dependencies/IERC20Metadata.sol +19 -0
- package/contracts/interfaces/IEToken.sol +172 -0
- package/{interfaces → contracts/interfaces}/ILPWhitelist.sol +0 -0
- package/{interfaces → contracts/interfaces}/IPolicyHolder.sol +0 -0
- package/{interfaces → contracts/interfaces}/IPolicyNFT.sol +0 -0
- package/contracts/interfaces/IPolicyPool.sol +138 -0
- package/{interfaces → contracts/interfaces}/IPolicyPoolComponent.sol +0 -0
- package/{interfaces → contracts/interfaces}/IPolicyPoolConfig.sol +29 -20
- package/contracts/interfaces/IPremiumsAccount.sol +71 -0
- package/contracts/interfaces/IRiskModule.sol +60 -0
- package/contracts/mocks/ForwardProxy.sol +66 -0
- package/contracts/mocks/IMintableERC20.sol +13 -0
- package/contracts/mocks/LinkTokenMock.sol +30 -0
- package/contracts/mocks/PolicyHolderMock.sol +68 -0
- package/contracts/mocks/PolicyPoolComponentMock.sol +17 -0
- package/contracts/mocks/PolicyPoolMock.sol +122 -0
- package/contracts/mocks/TestCurrency.sol +35 -0
- package/contracts/mocks/TestNFT.sol +23 -0
- package/contracts/upgraded/PolicyNFTv1.sol +1 -1
- package/js/test-utils.js +278 -0
- package/package.json +2 -2
- package/build/contracts/AaveAssetManager.sol/AaveAssetManager.json +0 -742
- package/build/contracts/DataTypes.sol/DataTypes.json +0 -10
- package/build/contracts/Exchange.sol/Exchange.json +0 -591
- package/build/contracts/extras/IPriceRiskModule.sol/IPriceRiskModule.json +0 -253
- package/build/contracts/extras/PriceRiskModule.sol/PriceRiskModule.json +0 -1055
- package/build/interfaces/IAssetManager.sol/IAssetManager.json +0 -31
- package/build/interfaces/IExchange.sol/IPriceOracle.json +0 -30
- package/contracts/AaveAssetManager.sol +0 -298
- package/contracts/BaseAssetManager.sol +0 -301
- package/contracts/DataTypes.sol +0 -287
- package/contracts/Exchange.sol +0 -189
- package/contracts/extras/IPriceRiskModule.sol +0 -41
- package/contracts/extras/PriceRiskModule.sol +0 -243
- package/interfaces/IAssetManager.sol +0 -23
- package/interfaces/IEToken.sol +0 -48
- package/interfaces/IExchange.sol +0 -59
- package/interfaces/IInsolvencyHook.sol +0 -27
- package/interfaces/IPolicyPool.sol +0 -44
- package/interfaces/IRiskModule.sol +0 -29
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"_format": "hh-sol-artifact-1",
|
|
3
|
-
"contractName": "IAssetManager",
|
|
4
|
-
"sourceName": "interfaces/IAssetManager.sol",
|
|
5
|
-
"abi": [
|
|
6
|
-
{
|
|
7
|
-
"inputs": [],
|
|
8
|
-
"name": "deinvestAll",
|
|
9
|
-
"outputs": [],
|
|
10
|
-
"stateMutability": "nonpayable",
|
|
11
|
-
"type": "function"
|
|
12
|
-
},
|
|
13
|
-
{
|
|
14
|
-
"inputs": [
|
|
15
|
-
{
|
|
16
|
-
"internalType": "uint256",
|
|
17
|
-
"name": "paymentAmount",
|
|
18
|
-
"type": "uint256"
|
|
19
|
-
}
|
|
20
|
-
],
|
|
21
|
-
"name": "refillWallet",
|
|
22
|
-
"outputs": [],
|
|
23
|
-
"stateMutability": "nonpayable",
|
|
24
|
-
"type": "function"
|
|
25
|
-
}
|
|
26
|
-
],
|
|
27
|
-
"bytecode": "0x",
|
|
28
|
-
"deployedBytecode": "0x",
|
|
29
|
-
"linkReferences": {},
|
|
30
|
-
"deployedLinkReferences": {}
|
|
31
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"_format": "hh-sol-artifact-1",
|
|
3
|
-
"contractName": "IPriceOracle",
|
|
4
|
-
"sourceName": "interfaces/IExchange.sol",
|
|
5
|
-
"abi": [
|
|
6
|
-
{
|
|
7
|
-
"inputs": [
|
|
8
|
-
{
|
|
9
|
-
"internalType": "address",
|
|
10
|
-
"name": "asset",
|
|
11
|
-
"type": "address"
|
|
12
|
-
}
|
|
13
|
-
],
|
|
14
|
-
"name": "getAssetPrice",
|
|
15
|
-
"outputs": [
|
|
16
|
-
{
|
|
17
|
-
"internalType": "uint256",
|
|
18
|
-
"name": "",
|
|
19
|
-
"type": "uint256"
|
|
20
|
-
}
|
|
21
|
-
],
|
|
22
|
-
"stateMutability": "view",
|
|
23
|
-
"type": "function"
|
|
24
|
-
}
|
|
25
|
-
],
|
|
26
|
-
"bytecode": "0x",
|
|
27
|
-
"deployedBytecode": "0x",
|
|
28
|
-
"linkReferences": {},
|
|
29
|
-
"deployedLinkReferences": {}
|
|
30
|
-
}
|
|
@@ -1,298 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
pragma solidity ^0.8.0;
|
|
3
|
-
|
|
4
|
-
import {AddressUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
|
|
5
|
-
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
|
|
6
|
-
import {BaseAssetManager} from "./BaseAssetManager.sol";
|
|
7
|
-
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
|
8
|
-
import {IPolicyPool} from "../interfaces/IPolicyPool.sol";
|
|
9
|
-
import {IPolicyPoolConfig} from "../interfaces/IPolicyPoolConfig.sol";
|
|
10
|
-
import {IExchange} from "../interfaces/IExchange.sol";
|
|
11
|
-
import {WadRayMath} from "./WadRayMath.sol";
|
|
12
|
-
import {ILendingPoolAddressesProvider} from "@aave/protocol-v2/contracts/interfaces/ILendingPoolAddressesProvider.sol";
|
|
13
|
-
import {ILendingPool} from "@aave/protocol-v2/contracts/interfaces/ILendingPool.sol";
|
|
14
|
-
import {IAToken} from "@aave/protocol-v2/contracts/interfaces/IAToken.sol";
|
|
15
|
-
import {AaveProtocolDataProvider} from "@aave/protocol-v2/contracts/misc/AaveProtocolDataProvider.sol";
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* @title AssetManager that reinvests the capital in AAVE
|
|
19
|
-
* @dev Deposits and withdraw from AAVE, also converts the rewards.
|
|
20
|
-
* Invest into AAVE AToken for the underlying asset (ex. USDC) getting lending interests.
|
|
21
|
-
* When needs to deinvest, first deinvest from AAVE, but also can liquidate the rewards
|
|
22
|
-
* (AAVE in mainnet or MATIC in Polygon) using a DEX.
|
|
23
|
-
* Above a given threshold, the rewards are claimed. Also, above a given threshold they are also reinvested
|
|
24
|
-
* to accrue additional interests and rewards.
|
|
25
|
-
* An authorized user (SWAP_REWARDS_ROLE) can force the swap of the rewards for the pool's currency.
|
|
26
|
-
* @custom:security-contact security@ensuro.co
|
|
27
|
-
* @author Ensuro
|
|
28
|
-
*/
|
|
29
|
-
contract AaveAssetManager is BaseAssetManager {
|
|
30
|
-
using SafeERC20 for IERC20Metadata;
|
|
31
|
-
using WadRayMath for uint256;
|
|
32
|
-
using AddressUpgradeable for address;
|
|
33
|
-
|
|
34
|
-
bytes32 public constant SWAP_REWARDS_ROLE = keccak256("SWAP_REWARDS_ROLE");
|
|
35
|
-
|
|
36
|
-
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
|
|
37
|
-
ILendingPoolAddressesProvider internal immutable _aaveAddrProv;
|
|
38
|
-
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
|
|
39
|
-
IAToken internal immutable _aToken;
|
|
40
|
-
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
|
|
41
|
-
IAToken internal immutable _rewardAToken;
|
|
42
|
-
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
|
|
43
|
-
IERC20Metadata internal immutable _rewardToken;
|
|
44
|
-
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
|
|
45
|
-
uint256 internal _claimRewardsMin; // Minimum amount of rewards accumulated to claim
|
|
46
|
-
uint256 internal _reinvestRewardsMin; // Minimum amount of rewards to reinvest into AAVE
|
|
47
|
-
|
|
48
|
-
bytes32 internal constant DATA_PROVIDER_ID =
|
|
49
|
-
0x0100000000000000000000000000000000000000000000000000000000000000;
|
|
50
|
-
|
|
51
|
-
uint256 internal constant SECONDS_PER_YEAR = 365 days;
|
|
52
|
-
|
|
53
|
-
event RewardSwapped(uint256 rewardIn, uint256 currencyOut);
|
|
54
|
-
|
|
55
|
-
/// @custom:oz-upgrades-unsafe-allow constructor
|
|
56
|
-
constructor(IPolicyPool policyPool_, ILendingPoolAddressesProvider aaveAddrProv_)
|
|
57
|
-
BaseAssetManager(policyPool_)
|
|
58
|
-
{
|
|
59
|
-
_aaveAddrProv = aaveAddrProv_;
|
|
60
|
-
AaveProtocolDataProvider dataProvider = AaveProtocolDataProvider(
|
|
61
|
-
aaveAddrProv_.getAddress(DATA_PROVIDER_ID)
|
|
62
|
-
);
|
|
63
|
-
(address aToken_, , ) = dataProvider.getReserveTokensAddresses(address(policyPool_.currency()));
|
|
64
|
-
_aToken = IAToken(aToken_);
|
|
65
|
-
address rewardToken_ = IAToken(aToken_).getIncentivesController().REWARD_TOKEN();
|
|
66
|
-
_rewardToken = IERC20Metadata(rewardToken_);
|
|
67
|
-
(address rewardAToken_, , ) = dataProvider.getReserveTokensAddresses(address(rewardToken_));
|
|
68
|
-
_rewardAToken = IAToken(rewardAToken_);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function initialize(
|
|
72
|
-
uint256 liquidityMin_,
|
|
73
|
-
uint256 liquidityMiddle_,
|
|
74
|
-
uint256 liquidityMax_,
|
|
75
|
-
uint256 claimRewardsMin_,
|
|
76
|
-
uint256 reinvestRewardsMin_
|
|
77
|
-
) public initializer {
|
|
78
|
-
__BaseAssetManager_init(liquidityMin_, liquidityMiddle_, liquidityMax_);
|
|
79
|
-
__AaveAssetManager_init(claimRewardsMin_, reinvestRewardsMin_);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// solhint-disable-next-line func-name-mixedcase
|
|
83
|
-
function __AaveAssetManager_init(uint256 claimRewardsMin_, uint256 reinvestRewardsMin_)
|
|
84
|
-
internal
|
|
85
|
-
initializer
|
|
86
|
-
{
|
|
87
|
-
_claimRewardsMin = claimRewardsMin_;
|
|
88
|
-
_reinvestRewardsMin = reinvestRewardsMin_;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function getInvestmentValue() public view override returns (uint256) {
|
|
92
|
-
uint256 balance = aToken().balanceOf(address(this));
|
|
93
|
-
uint256 rewardBalance = rewardToken().balanceOf(address(this)) +
|
|
94
|
-
rewardAToken().balanceOf(address(this));
|
|
95
|
-
// Don't count unclaimedRewards as part of investmentValue to save gas and because if doing that will
|
|
96
|
-
// also need to claim rewards as part of _deinvest process
|
|
97
|
-
return balance + _rewardToCurrency(rewardBalance);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function unclaimedRewards() public view returns (uint256) {
|
|
101
|
-
// Also add unclaimed rewards
|
|
102
|
-
IAToken atk = aToken();
|
|
103
|
-
address[] memory atks = new address[](2);
|
|
104
|
-
atks[0] = address(atk);
|
|
105
|
-
atks[1] = address(rewardAToken());
|
|
106
|
-
return atk.getIncentivesController().getRewardsBalance(atks, address(this));
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function _claimRewards(bool ignoreMin) internal returns (uint256) {
|
|
110
|
-
if (ignoreMin || unclaimedRewards() > _claimRewardsMin) {
|
|
111
|
-
IAToken atk = aToken();
|
|
112
|
-
address[] memory atks = new address[](2);
|
|
113
|
-
atks[0] = address(atk);
|
|
114
|
-
atks[1] = address(rewardAToken());
|
|
115
|
-
return atk.getIncentivesController().claimRewards(atks, type(uint256).max, address(this));
|
|
116
|
-
} else {
|
|
117
|
-
return 0;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function lendingPool() public view returns (ILendingPool) {
|
|
122
|
-
return ILendingPool(_aaveAddrProv.getLendingPool());
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function _aaveDataProvider() internal view returns (AaveProtocolDataProvider) {
|
|
126
|
-
return AaveProtocolDataProvider(_aaveAddrProv.getAddress(DATA_PROVIDER_ID));
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function _exchange() internal view returns (IExchange) {
|
|
130
|
-
return policyPool().config().exchange();
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function aToken() public view returns (IAToken) {
|
|
134
|
-
return _aToken;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
function rewardToken() public view returns (IERC20Metadata) {
|
|
138
|
-
return _rewardToken;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
function rewardAToken() public view returns (IAToken) {
|
|
142
|
-
return _rewardAToken;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function _exchangePath() internal view returns (address[] memory) {
|
|
146
|
-
address[] memory path = new address[](2);
|
|
147
|
-
path[0] = address(rewardToken());
|
|
148
|
-
path[1] = address(currency());
|
|
149
|
-
return path;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
function _rewardToCurrency(uint256 amount) internal view returns (uint256) {
|
|
153
|
-
return _exchange().convert(address(rewardToken()), address(currency()), amount);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
function reinvestRewardToken() public {
|
|
157
|
-
ILendingPool lendingPool_ = lendingPool();
|
|
158
|
-
IERC20Metadata token = rewardToken();
|
|
159
|
-
uint256 rewardBalance = token.balanceOf(address(this));
|
|
160
|
-
if (rewardBalance <= _reinvestRewardsMin) return;
|
|
161
|
-
token.approve(address(lendingPool_), rewardBalance);
|
|
162
|
-
lendingPool_.deposit(address(token), rewardBalance, address(this), 0);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
function _swapRewards(uint256 amount, address outAddr) internal returns (uint256, uint256) {
|
|
166
|
-
IERC20Metadata rw = rewardToken();
|
|
167
|
-
uint256 swapIn = rw.balanceOf(address(this));
|
|
168
|
-
if (swapIn < amount) {
|
|
169
|
-
uint256 toWithdraw = amount - swapIn;
|
|
170
|
-
if (rewardAToken().balanceOf(address(this)) < toWithdraw) {
|
|
171
|
-
toWithdraw = type(uint256).max; // if not enought withdraw all
|
|
172
|
-
}
|
|
173
|
-
swapIn += lendingPool().withdraw(address(rw), toWithdraw, address(this));
|
|
174
|
-
} else {
|
|
175
|
-
swapIn = amount;
|
|
176
|
-
}
|
|
177
|
-
address swapRouter = _exchange().getSwapRouter();
|
|
178
|
-
rw.approve(swapRouter, swapIn);
|
|
179
|
-
bytes memory swapCall = _exchange().sell(
|
|
180
|
-
address(rw),
|
|
181
|
-
address(currency()),
|
|
182
|
-
swapIn,
|
|
183
|
-
outAddr,
|
|
184
|
-
block.timestamp
|
|
185
|
-
);
|
|
186
|
-
|
|
187
|
-
bytes memory response = swapRouter.functionCall(swapCall, "Swap operation failed");
|
|
188
|
-
uint256 swapOut = _exchange().decodeSwapOut(response);
|
|
189
|
-
emit RewardSwapped(swapIn, swapOut);
|
|
190
|
-
return (swapIn, swapOut);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
function swapRewards(uint256 amount)
|
|
194
|
-
external
|
|
195
|
-
onlyPoolRole(SWAP_REWARDS_ROLE)
|
|
196
|
-
returns (uint256, uint256)
|
|
197
|
-
{
|
|
198
|
-
(uint256 swapIn, uint256 swapOut) = _swapRewards(amount, address(this));
|
|
199
|
-
ILendingPool lendingPool_ = lendingPool();
|
|
200
|
-
IERC20Metadata token = currency();
|
|
201
|
-
token.approve(address(lendingPool_), swapOut);
|
|
202
|
-
lendingPool_.deposit(address(token), swapOut, address(this), 0);
|
|
203
|
-
return (swapIn, swapOut);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
function rebalance() public virtual override whenNotPaused {
|
|
207
|
-
_claimRewards(false);
|
|
208
|
-
super.rebalance();
|
|
209
|
-
reinvestRewardToken();
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
function _invest(uint256 amount) internal override {
|
|
213
|
-
ILendingPool lendingPool_ = lendingPool();
|
|
214
|
-
IERC20Metadata token = currency();
|
|
215
|
-
token.safeTransferFrom(address(_policyPool), address(this), amount);
|
|
216
|
-
token.approve(address(lendingPool_), amount);
|
|
217
|
-
lendingPool_.deposit(address(token), amount, address(this), 0);
|
|
218
|
-
super._invest(amount);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
function _deinvest(uint256 amount) internal override {
|
|
222
|
-
uint256 remainingAmount = amount;
|
|
223
|
-
uint256 toWithdraw = amount;
|
|
224
|
-
if (aToken().balanceOf(address(this)) < toWithdraw) {
|
|
225
|
-
toWithdraw = type(uint256).max;
|
|
226
|
-
}
|
|
227
|
-
remainingAmount -= lendingPool().withdraw(
|
|
228
|
-
address(currency()),
|
|
229
|
-
toWithdraw,
|
|
230
|
-
address(_policyPool) // Withdraw directly to _policyPool
|
|
231
|
-
);
|
|
232
|
-
if (remainingAmount > 0) {
|
|
233
|
-
// In this case, it's safe using getAmountsIn to compute how many rewards are needed to swap
|
|
234
|
-
// but then, when I do the swap I validate the slippage with the market price (given by AAVE's Oracle)
|
|
235
|
-
// is acceptable
|
|
236
|
-
uint256 requiredRewards = _exchange().getAmountIn(
|
|
237
|
-
address(rewardToken()),
|
|
238
|
-
address(currency()),
|
|
239
|
-
remainingAmount
|
|
240
|
-
);
|
|
241
|
-
(, uint256 currencyOut) = _swapRewards(requiredRewards, address(_policyPool));
|
|
242
|
-
if (currencyOut < remainingAmount) {
|
|
243
|
-
remainingAmount -= currencyOut;
|
|
244
|
-
} else {
|
|
245
|
-
remainingAmount = 0;
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
super._deinvest(amount - remainingAmount);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
/**
|
|
252
|
-
* @dev Deinvest all the assets and return the cash back to the PolicyPool.
|
|
253
|
-
* Called from PolicyPool when new asset manager is assigned
|
|
254
|
-
*/
|
|
255
|
-
function _liquidateAll() internal virtual override {
|
|
256
|
-
_claimRewards(true);
|
|
257
|
-
lendingPool().withdraw(
|
|
258
|
-
address(currency()),
|
|
259
|
-
type(uint256).max,
|
|
260
|
-
address(_policyPool) // Withdraw directly to _policyPool
|
|
261
|
-
);
|
|
262
|
-
// Withdraw all rewards
|
|
263
|
-
lendingPool().withdraw(address(_rewardToken), type(uint256).max, address(this));
|
|
264
|
-
_swapRewards(_rewardToken.balanceOf(address(this)), address(_policyPool));
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
// Contract parameters
|
|
268
|
-
function claimRewardsMin() external view returns (uint256) {
|
|
269
|
-
return _claimRewardsMin;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
function reinvestRewardsMin() external view returns (uint256) {
|
|
273
|
-
return _reinvestRewardsMin;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
function setClaimRewardsMin(uint256 newValue) external onlyPoolRole2(LEVEL2_ROLE, LEVEL3_ROLE) {
|
|
277
|
-
bool tweak = !hasPoolRole(LEVEL2_ROLE);
|
|
278
|
-
require(
|
|
279
|
-
!tweak || _isTweakWad(_claimRewardsMin, newValue, 3e26),
|
|
280
|
-
"Tweak exceeded: claimRewardsMin tweaks only up to 30%"
|
|
281
|
-
);
|
|
282
|
-
_claimRewardsMin = newValue;
|
|
283
|
-
_parameterChanged(IPolicyPoolConfig.GovernanceActions.setClaimRewardsMin, newValue, tweak);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
function setReinvestRewardsMin(uint256 newValue)
|
|
287
|
-
external
|
|
288
|
-
onlyPoolRole2(LEVEL2_ROLE, LEVEL3_ROLE)
|
|
289
|
-
{
|
|
290
|
-
bool tweak = !hasPoolRole(LEVEL2_ROLE);
|
|
291
|
-
require(
|
|
292
|
-
!tweak || _isTweakWad(_reinvestRewardsMin, newValue, 3e26),
|
|
293
|
-
"Tweak exceeded: reinvestRewardsMin tweaks only up to 30%"
|
|
294
|
-
);
|
|
295
|
-
_reinvestRewardsMin = newValue;
|
|
296
|
-
_parameterChanged(IPolicyPoolConfig.GovernanceActions.setReinvestRewardsMin, newValue, tweak);
|
|
297
|
-
}
|
|
298
|
-
}
|
|
@@ -1,301 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
pragma solidity ^0.8.0;
|
|
3
|
-
|
|
4
|
-
import {WadRayMath} from "./WadRayMath.sol";
|
|
5
|
-
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
6
|
-
import {IPolicyPool} from "../interfaces/IPolicyPool.sol";
|
|
7
|
-
import {PolicyPoolComponent} from "./PolicyPoolComponent.sol";
|
|
8
|
-
import {IAssetManager} from "../interfaces/IAssetManager.sol";
|
|
9
|
-
import {IEToken} from "../interfaces/IEToken.sol";
|
|
10
|
-
import {IPolicyPoolConfig} from "../interfaces/IPolicyPoolConfig.sol";
|
|
11
|
-
import {Policy} from "./Policy.sol";
|
|
12
|
-
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* @title Ensuro Asset Manager base contract
|
|
16
|
-
* @dev Base class for asset managers that reinvest the assets of the protocol to get additional returns.
|
|
17
|
-
* The specific asset management strategy needs to be implemented by child contracts.
|
|
18
|
-
* Settings liquidityMin, liquidityMiddle, liquidityMax are the thresholds used to define how much liquidity
|
|
19
|
-
* to keep in the PolicyPool and when to invest/deinvest. Every invest/deinvest operation tries to leave the
|
|
20
|
-
* PolicyPool at liquidityMiddle.
|
|
21
|
-
* @custom:security-contact security@ensuro.co
|
|
22
|
-
* @author Ensuro
|
|
23
|
-
*/
|
|
24
|
-
abstract contract BaseAssetManager is IAssetManager, PolicyPoolComponent {
|
|
25
|
-
using WadRayMath for uint256;
|
|
26
|
-
|
|
27
|
-
uint256 internal _liquidityMin;
|
|
28
|
-
uint256 internal _liquidityMiddle;
|
|
29
|
-
uint256 internal _liquidityMax;
|
|
30
|
-
|
|
31
|
-
uint256 internal _lastInvestmentValue;
|
|
32
|
-
|
|
33
|
-
event MoneyInvested(uint256 amount);
|
|
34
|
-
event MoneyDeinvested(uint256 amount);
|
|
35
|
-
event EarningsDistributed(bool positive, uint256 amount);
|
|
36
|
-
|
|
37
|
-
/// @custom:oz-upgrades-unsafe-allow constructor
|
|
38
|
-
// solhint-disable-next-line no-empty-blocks
|
|
39
|
-
constructor(IPolicyPool policyPool_) PolicyPoolComponent(policyPool_) {}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* @dev Initializes the asset manager
|
|
43
|
-
* @param liquidityMin_ Minimal liquidity to keep in pool's wallet
|
|
44
|
-
* @param liquidityMiddle_ Target liquidity when doing rebalance
|
|
45
|
-
* @param liquidityMax_ Maximum liquidity to keep in pool's wallet
|
|
46
|
-
*/
|
|
47
|
-
// solhint-disable-next-line func-name-mixedcase
|
|
48
|
-
function __BaseAssetManager_init(
|
|
49
|
-
uint256 liquidityMin_,
|
|
50
|
-
uint256 liquidityMiddle_,
|
|
51
|
-
uint256 liquidityMax_
|
|
52
|
-
) internal initializer {
|
|
53
|
-
__PolicyPoolComponent_init();
|
|
54
|
-
__BaseAssetManager_init_unchained(liquidityMin_, liquidityMiddle_, liquidityMax_);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// solhint-disable-next-line func-name-mixedcase
|
|
58
|
-
function __BaseAssetManager_init_unchained(
|
|
59
|
-
uint256 liquidityMin_,
|
|
60
|
-
uint256 liquidityMiddle_,
|
|
61
|
-
uint256 liquidityMax_
|
|
62
|
-
) internal initializer {
|
|
63
|
-
/*
|
|
64
|
-
_lastInvestmentValue = 0;
|
|
65
|
-
*/
|
|
66
|
-
_liquidityMin = liquidityMin_;
|
|
67
|
-
_liquidityMiddle = liquidityMiddle_;
|
|
68
|
-
_liquidityMax = liquidityMax_;
|
|
69
|
-
_validateParameters();
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function _validateParameters() internal view override {
|
|
73
|
-
require(
|
|
74
|
-
_liquidityMin <= _liquidityMiddle && _liquidityMiddle <= _liquidityMax,
|
|
75
|
-
"Validation: Liquidity limits are invalid"
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* @dev Returns the total amount that is available to invest by the asset manager
|
|
81
|
-
*/
|
|
82
|
-
function totalInvestable() public view returns (uint256) {
|
|
83
|
-
uint256 poolInvestable = _policyPool.getInvestable();
|
|
84
|
-
uint256 etksInvestable = 0;
|
|
85
|
-
for (uint256 i = 0; i < _policyPool.getETokenCount(); i++) {
|
|
86
|
-
IEToken etk = _policyPool.getETokenAt(i);
|
|
87
|
-
etksInvestable += etk.getInvestable();
|
|
88
|
-
}
|
|
89
|
-
return poolInvestable + etksInvestable;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* @dev Calculates asset earnings and distributes them updating accounting in PolicyPool and eTokens
|
|
94
|
-
*/
|
|
95
|
-
function distributeEarnings() public virtual whenNotPaused {
|
|
96
|
-
// TODO Check: Anyone can call this funcion. This could be a potencial surface of flash loan attack?
|
|
97
|
-
_distributeEarnings(getInvestmentValue());
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function _distributeEarnings(uint256 investmentValue) internal virtual whenNotPaused {
|
|
101
|
-
bool positive;
|
|
102
|
-
uint256 earnings;
|
|
103
|
-
if (investmentValue > _lastInvestmentValue) {
|
|
104
|
-
earnings = investmentValue - _lastInvestmentValue;
|
|
105
|
-
positive = true;
|
|
106
|
-
} else if (investmentValue < _lastInvestmentValue) {
|
|
107
|
-
earnings = _lastInvestmentValue - investmentValue;
|
|
108
|
-
positive = false;
|
|
109
|
-
} else {
|
|
110
|
-
return; // No earnings
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
uint256 totalInv = totalInvestable();
|
|
114
|
-
|
|
115
|
-
uint256 remaining = earnings;
|
|
116
|
-
for (uint256 i = 0; i < _policyPool.getETokenCount(); i++) {
|
|
117
|
-
IEToken etk = _policyPool.getETokenAt(i);
|
|
118
|
-
uint256 aux = earnings.wadMul(etk.getInvestable().wadDiv(totalInv));
|
|
119
|
-
if (aux > 0) {
|
|
120
|
-
etk.assetEarnings(aux, positive);
|
|
121
|
-
remaining -= aux;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
if (remaining > 0) _policyPool.assetEarnings(remaining, positive);
|
|
126
|
-
|
|
127
|
-
_lastInvestmentValue = investmentValue;
|
|
128
|
-
emit EarningsDistributed(positive, earnings);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* @dev Returns the current value of the investment portfolio
|
|
133
|
-
*/
|
|
134
|
-
function getInvestmentValue() public view virtual returns (uint256);
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* @dev Rebalances cash between PolicyPool wallet and
|
|
138
|
-
*/
|
|
139
|
-
function rebalance() public virtual whenNotPaused {
|
|
140
|
-
// TODO Check: Anyone can call this funcion. This could be a potencial surface of flash loan attack?
|
|
141
|
-
uint256 poolCash = currency().balanceOf(address(_policyPool));
|
|
142
|
-
if (poolCash > _liquidityMax) {
|
|
143
|
-
_invest(poolCash - _liquidityMiddle);
|
|
144
|
-
} else if (poolCash < _liquidityMin) {
|
|
145
|
-
uint256 deinvestAmount = Math.min(getInvestmentValue(), _liquidityMiddle - poolCash);
|
|
146
|
-
if (deinvestAmount > 0) {
|
|
147
|
-
_deinvest(deinvestAmount);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* @dev Function to be called automatically by a crontask - Distributes and rebalances
|
|
154
|
-
*/
|
|
155
|
-
function checkpoint() external {
|
|
156
|
-
distributeEarnings();
|
|
157
|
-
rebalance();
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* @dev This is called from PolicyPool when doesn't have enought money for payment.
|
|
162
|
-
* After the call, there should be enought money in PolicyPool.currency().balanceOf(this) to
|
|
163
|
-
* do the payment
|
|
164
|
-
* @param paymentAmount The amount of the payment
|
|
165
|
-
*/
|
|
166
|
-
function refillWallet(uint256 paymentAmount) external override onlyPolicyPool {
|
|
167
|
-
uint256 poolCash = currency().balanceOf(address(_policyPool));
|
|
168
|
-
require(poolCash < paymentAmount, "No need to refill the wallet for this payment");
|
|
169
|
-
uint256 investmentValue = getInvestmentValue();
|
|
170
|
-
// try to leave the pool balance at liquidity_middle after the payment
|
|
171
|
-
uint256 deinvest = paymentAmount + _liquidityMiddle - poolCash;
|
|
172
|
-
if (deinvest > investmentValue) deinvest = investmentValue;
|
|
173
|
-
_deinvest(deinvest);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
function _invest(uint256 amount) internal virtual {
|
|
177
|
-
_lastInvestmentValue += amount;
|
|
178
|
-
emit MoneyInvested(amount);
|
|
179
|
-
// must be reimplemented do the actual cash movement
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
function _deinvest(uint256 amount) internal virtual {
|
|
183
|
-
_lastInvestmentValue -= Math.min(_lastInvestmentValue, amount);
|
|
184
|
-
emit MoneyDeinvested(amount);
|
|
185
|
-
// must be reimplemented do the actual cash movement
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* @dev Deinvest all the assets and return the cash back to the PolicyPool.
|
|
190
|
-
* Called from PolicyPool when new asset manager is assigned
|
|
191
|
-
*/
|
|
192
|
-
function deinvestAll() external virtual override onlyPolicyPool {
|
|
193
|
-
uint256 poolBalanceBefore = currency().balanceOf(address(_policyPool));
|
|
194
|
-
_liquidateAll();
|
|
195
|
-
uint256 poolBalanceAfter = currency().balanceOf(address(_policyPool));
|
|
196
|
-
_distributeEarnings(poolBalanceAfter - poolBalanceBefore);
|
|
197
|
-
_lastInvestmentValue = 0;
|
|
198
|
-
emit MoneyDeinvested(poolBalanceAfter - poolBalanceBefore);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
function _liquidateAll() internal virtual;
|
|
202
|
-
|
|
203
|
-
function liquidityMin() external view returns (uint256) {
|
|
204
|
-
return _liquidityMin;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
function liquidityMiddle() external view returns (uint256) {
|
|
208
|
-
return _liquidityMiddle;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
function liquidityMax() external view returns (uint256) {
|
|
212
|
-
return _liquidityMax;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
function setLiquidityMin(uint256 newValue) external onlyPoolRole2(LEVEL2_ROLE, LEVEL3_ROLE) {
|
|
216
|
-
bool tweak = !hasPoolRole(LEVEL2_ROLE);
|
|
217
|
-
require(
|
|
218
|
-
!tweak || _isTweakRay(_liquidityMin, newValue, 3e26),
|
|
219
|
-
"Tweak exceeded: liquidityMin tweaks only up to 30%"
|
|
220
|
-
);
|
|
221
|
-
_liquidityMin = newValue;
|
|
222
|
-
_parameterChanged(IPolicyPoolConfig.GovernanceActions.setLiquidityMin, newValue, tweak);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
function setLiquidityMiddle(uint256 newValue) external onlyPoolRole2(LEVEL2_ROLE, LEVEL3_ROLE) {
|
|
226
|
-
bool tweak = !hasPoolRole(LEVEL2_ROLE);
|
|
227
|
-
require(
|
|
228
|
-
!tweak || _isTweakRay(_liquidityMiddle, newValue, 3e26),
|
|
229
|
-
"Tweak exceeded: liquidityMiddle tweaks only up to 30%"
|
|
230
|
-
);
|
|
231
|
-
_liquidityMiddle = newValue;
|
|
232
|
-
_parameterChanged(IPolicyPoolConfig.GovernanceActions.setLiquidityMiddle, newValue, tweak);
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
function setLiquidityMax(uint256 newValue) external onlyPoolRole2(LEVEL2_ROLE, LEVEL3_ROLE) {
|
|
236
|
-
bool tweak = !hasPoolRole(LEVEL2_ROLE);
|
|
237
|
-
require(
|
|
238
|
-
!tweak || _isTweakRay(_liquidityMax, newValue, 3e26),
|
|
239
|
-
"Tweak exceeded: liquidityMax tweaks only up to 30%"
|
|
240
|
-
);
|
|
241
|
-
_liquidityMax = newValue;
|
|
242
|
-
_parameterChanged(IPolicyPoolConfig.GovernanceActions.setLiquidityMax, newValue, tweak);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
function setLiquidityMultiple(
|
|
246
|
-
uint256 min,
|
|
247
|
-
uint256 middle,
|
|
248
|
-
uint256 max
|
|
249
|
-
) external onlyPoolRole2(LEVEL2_ROLE, LEVEL3_ROLE) {
|
|
250
|
-
bool setMin = min != type(uint256).max;
|
|
251
|
-
bool setMiddle = middle != type(uint256).max;
|
|
252
|
-
bool setMax = max != type(uint256).max;
|
|
253
|
-
bool tweak = !hasPoolRole(LEVEL2_ROLE);
|
|
254
|
-
// First set all - Then call _parameterChanged
|
|
255
|
-
if (setMin) {
|
|
256
|
-
require(
|
|
257
|
-
!tweak || _isTweakRay(_liquidityMin, min, 3e26),
|
|
258
|
-
"Tweak exceeded: liquidityMin tweaks only up to 30%"
|
|
259
|
-
);
|
|
260
|
-
_liquidityMin = min;
|
|
261
|
-
}
|
|
262
|
-
if (setMiddle) {
|
|
263
|
-
require(
|
|
264
|
-
!tweak || _isTweakRay(_liquidityMiddle, middle, 3e26),
|
|
265
|
-
"Tweak exceeded: liquidityMiddle tweaks only up to 30%"
|
|
266
|
-
);
|
|
267
|
-
_liquidityMiddle = middle;
|
|
268
|
-
}
|
|
269
|
-
if (setMax) {
|
|
270
|
-
require(
|
|
271
|
-
!tweak || _isTweakRay(_liquidityMax, max, 3e26),
|
|
272
|
-
"Tweak exceeded: liquidityMax tweaks only up to 30%"
|
|
273
|
-
);
|
|
274
|
-
_liquidityMax = max;
|
|
275
|
-
}
|
|
276
|
-
if (setMin) _parameterChanged(IPolicyPoolConfig.GovernanceActions.setLiquidityMin, min, tweak);
|
|
277
|
-
if (setMiddle)
|
|
278
|
-
_parameterChanged(IPolicyPoolConfig.GovernanceActions.setLiquidityMiddle, middle, tweak);
|
|
279
|
-
if (setMax) _parameterChanged(IPolicyPoolConfig.GovernanceActions.setLiquidityMax, max, tweak);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
function _setLiquidityMiddle(uint256 newValue) internal {
|
|
283
|
-
bool tweak = !hasPoolRole(LEVEL2_ROLE);
|
|
284
|
-
require(
|
|
285
|
-
!tweak || _isTweakRay(_liquidityMiddle, newValue, 3e26),
|
|
286
|
-
"Tweak exceeded: liquidityMiddle tweaks only up to 30%"
|
|
287
|
-
);
|
|
288
|
-
_liquidityMiddle = newValue;
|
|
289
|
-
_parameterChanged(IPolicyPoolConfig.GovernanceActions.setLiquidityMiddle, newValue, tweak);
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
function _setLiquidityMax(uint256 newValue) internal {
|
|
293
|
-
bool tweak = !hasPoolRole(LEVEL2_ROLE);
|
|
294
|
-
require(
|
|
295
|
-
!tweak || _isTweakRay(_liquidityMax, newValue, 3e26),
|
|
296
|
-
"Tweak exceeded: liquidityMax tweaks only up to 30%"
|
|
297
|
-
);
|
|
298
|
-
_liquidityMax = newValue;
|
|
299
|
-
_parameterChanged(IPolicyPoolConfig.GovernanceActions.setLiquidityMax, newValue, tweak);
|
|
300
|
-
}
|
|
301
|
-
}
|