@harvest-finance/harvest-strategy-arbitrum 0.0.1-security → 1.0.0

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.

Potentially problematic release.


This version of @harvest-finance/harvest-strategy-arbitrum might be problematic. Click here for more details.

Files changed (199) hide show
  1. package/README.md +127 -5
  2. package/contracts/base/Controller.sol +358 -0
  3. package/contracts/base/Drip.sol +86 -0
  4. package/contracts/base/PotPool.sol +367 -0
  5. package/contracts/base/ProfitSharingReceiver.sol +38 -0
  6. package/contracts/base/Reader.sol +54 -0
  7. package/contracts/base/RewardForwarder.sol +109 -0
  8. package/contracts/base/VaultProxy.sol +34 -0
  9. package/contracts/base/VaultStorage.sol +205 -0
  10. package/contracts/base/VaultV1.sol +371 -0
  11. package/contracts/base/VaultV1GMX.sol +465 -0
  12. package/contracts/base/VaultV2.sol +111 -0
  13. package/contracts/base/VaultV2GMX.sol +111 -0
  14. package/contracts/base/factory/MegaFactory.sol +120 -0
  15. package/contracts/base/factory/interface/IPoolFactory.sol +6 -0
  16. package/contracts/base/factory/interface/IStrategyFactory.sol +6 -0
  17. package/contracts/base/factory/interface/IVaultFactory.sol +7 -0
  18. package/contracts/base/factory/pool/PotPoolFactory.sol +41 -0
  19. package/contracts/base/factory/strategy/UpgradableStrategyFactory.sol +19 -0
  20. package/contracts/base/factory/vault/RegularVaultFactory.sol +34 -0
  21. package/contracts/base/incentives/GlobalIncentivesExecutor.sol +85 -0
  22. package/contracts/base/incentives/GlobalIncentivesHelper.sol +174 -0
  23. package/contracts/base/incentives/NotifyHelperGeneric.sol +61 -0
  24. package/contracts/base/incentives/NotifyHelperStateful.sol +290 -0
  25. package/contracts/base/incentives/ViewerNotifyHelperStateful.sol +25 -0
  26. package/contracts/base/inheritance/Controllable.sol +25 -0
  27. package/contracts/base/inheritance/ControllableInit.sol +30 -0
  28. package/contracts/base/inheritance/Governable.sol +28 -0
  29. package/contracts/base/inheritance/GovernableInit.sol +50 -0
  30. package/contracts/base/inheritance/IUpgradeSource.sol +7 -0
  31. package/contracts/base/inheritance/OwnableWhitelist.sol +17 -0
  32. package/contracts/base/inheritance/Storage.sol +35 -0
  33. package/contracts/base/interface/IBalDex.sol +7 -0
  34. package/contracts/base/interface/IController.sol +132 -0
  35. package/contracts/base/interface/IDex.sol +9 -0
  36. package/contracts/base/interface/IERC4626.sol +261 -0
  37. package/contracts/base/interface/IGMXStrategy.sol +37 -0
  38. package/contracts/base/interface/IGlobalIncentivesHelper.sol +6 -0
  39. package/contracts/base/interface/IPotPool.sol +70 -0
  40. package/contracts/base/interface/IProfitSharingReceiver.sol +9 -0
  41. package/contracts/base/interface/IRewardForwarder.sol +57 -0
  42. package/contracts/base/interface/IStrategy.sol +37 -0
  43. package/contracts/base/interface/IUniversalLiquidator.sol +21 -0
  44. package/contracts/base/interface/IUniversalLiquidatorRegistry.sol +20 -0
  45. package/contracts/base/interface/IUpgradeSource.sol +9 -0
  46. package/contracts/base/interface/IVault.sol +58 -0
  47. package/contracts/base/interface/IVaultGMX.sol +71 -0
  48. package/contracts/base/interface/aura/IAuraBaseRewardPool.sol +25 -0
  49. package/contracts/base/interface/aura/IAuraBooster.sol +17 -0
  50. package/contracts/base/interface/aura/IAuraDepositor.sol +7 -0
  51. package/contracts/base/interface/balancer/Gauge.sol +22 -0
  52. package/contracts/base/interface/balancer/IBVault.sol +580 -0
  53. package/contracts/base/interface/balancer/IBalancerMinter.sol +114 -0
  54. package/contracts/base/interface/balancer/IGyroPool.sol +7 -0
  55. package/contracts/base/interface/balancer/linearPool/ILinearPool.sol +184 -0
  56. package/contracts/base/interface/balancer/linearPool/ILinearPoolFactory.sol +16 -0
  57. package/contracts/base/interface/balancer/linearPool/ILinearPoolRebalancer.sol +8 -0
  58. package/contracts/base/interface/balancer/linearPool/IPoolSwapStructs.sol +56 -0
  59. package/contracts/base/interface/compound/CTokenInterface.sol +29 -0
  60. package/contracts/base/interface/compound/IComptroller.sol +9 -0
  61. package/contracts/base/interface/dolomite/IDepositWithdraw.sol +13 -0
  62. package/contracts/base/interface/dolomite/IDolomiteMargin.sol +15 -0
  63. package/contracts/base/interface/dolomite/IRewardsDistributor.sol +11 -0
  64. package/contracts/base/interface/gamma/IClearing.sol +7 -0
  65. package/contracts/base/interface/gamma/IHypervisor.sol +9 -0
  66. package/contracts/base/interface/gamma/IUniProxy.sol +14 -0
  67. package/contracts/base/interface/gmx/EventUtils.sol +253 -0
  68. package/contracts/base/interface/gmx/ICallbackReceiver.sol +119 -0
  69. package/contracts/base/interface/gmx/IDataStore.sol +7 -0
  70. package/contracts/base/interface/gmx/IExchangeRouter.sol +38 -0
  71. package/contracts/base/interface/gmx/IGMXViewer.sol +7 -0
  72. package/contracts/base/interface/gmx/IHandler.sol +12 -0
  73. package/contracts/base/interface/gmx/IMarket.sol +7 -0
  74. package/contracts/base/interface/gmx/IOracle.sol +6 -0
  75. package/contracts/base/interface/gmx/IPriceFeed.sol +12 -0
  76. package/contracts/base/interface/gmx/IReader.sol +49 -0
  77. package/contracts/base/interface/gmx/IRoleStore.sol +6 -0
  78. package/contracts/base/interface/ipor/Errors.sol +20 -0
  79. package/contracts/base/interface/ipor/FuseStorageLib.sol +71 -0
  80. package/contracts/base/interface/ipor/FusesLib.sol +149 -0
  81. package/contracts/base/interface/ipor/IFuseCommon.sol +9 -0
  82. package/contracts/base/interface/ipor/IFuseInstantWithdraw.sol +14 -0
  83. package/contracts/base/interface/ipor/IMarketBalanceFuse.sol +10 -0
  84. package/contracts/base/interface/ipor/IPriceOracleMiddleware.sol +42 -0
  85. package/contracts/base/interface/ipor/IporMath.sol +110 -0
  86. package/contracts/base/interface/ipor/PlasmaVaultConfigLib.sol +106 -0
  87. package/contracts/base/interface/ipor/PlasmaVaultLib.sol +293 -0
  88. package/contracts/base/interface/ipor/PlasmaVaultStorageLib.sol +352 -0
  89. package/contracts/base/interface/merkl/IDistributor.sol +6 -0
  90. package/contracts/base/interface/notional/INProxy.sol +44 -0
  91. package/contracts/base/interface/notional/IPrimeToken.sol +6 -0
  92. package/contracts/base/interface/venus/IRewardsDistributor.sol +6 -0
  93. package/contracts/base/interface/weth/IWETH.sol +39 -0
  94. package/contracts/base/ipor/Erc4626BalanceFuse.sol +54 -0
  95. package/contracts/base/ipor/Erc4626SupplyFuse.sol +134 -0
  96. package/contracts/base/noop/NoopStrategyUpgradeable.sol +90 -0
  97. package/contracts/base/upgradability/BaseUpgradeabilityProxy.sol +60 -0
  98. package/contracts/base/upgradability/BaseUpgradeableStrategy.sol +144 -0
  99. package/contracts/base/upgradability/BaseUpgradeableStrategyStorage.sol +284 -0
  100. package/contracts/base/upgradability/IUpgradable.sol +7 -0
  101. package/contracts/base/upgradability/ReentrancyGuardUpgradeable.sol +51 -0
  102. package/contracts/base/upgradability/StrategyProxy.sol +34 -0
  103. package/contracts/strategies/aura/AuraStrategy.sol +403 -0
  104. package/contracts/strategies/aura/AuraStrategyMainnet_MORE_GYD.sol +32 -0
  105. package/contracts/strategies/aura/AuraStrategyMainnet_sUSDe_GYD.sol +31 -0
  106. package/contracts/strategies/aura/AuraStrategyMainnet_waFRAX_sFRAX.sol +31 -0
  107. package/contracts/strategies/aura/AuraStrategyMainnet_waGHO_GYD.sol +31 -0
  108. package/contracts/strategies/aura/AuraStrategyMainnet_waUSDC_GHO.sol +32 -0
  109. package/contracts/strategies/aura/AuraStrategyMainnet_waUSDC_GYD.sol +31 -0
  110. package/contracts/strategies/aura/AuraStrategyMainnet_waUSDT_GYD.sol +31 -0
  111. package/contracts/strategies/aura/AuraStrategyMainnet_wstETH_GYD.sol +31 -0
  112. package/contracts/strategies/camelot/CamelotV3Strategy.sol +304 -0
  113. package/contracts/strategies/camelot/CamelotV3StrategyMainnet_ARB_USDC.sol +28 -0
  114. package/contracts/strategies/camelot/CamelotV3StrategyMainnet_ETH_USDC.sol +28 -0
  115. package/contracts/strategies/camelot/CamelotV3StrategyMainnet_ETH_USDT.sol +28 -0
  116. package/contracts/strategies/camelot/CamelotV3StrategyMainnet_GMX_ETH.sol +28 -0
  117. package/contracts/strategies/camelot/CamelotV3StrategyMainnet_GRAIL_ETH.sol +28 -0
  118. package/contracts/strategies/camelot/CamelotV3StrategyMainnet_USDC_USDT.sol +28 -0
  119. package/contracts/strategies/camelot/CamelotV3StrategyMainnet_WBTC_ETH.sol +28 -0
  120. package/contracts/strategies/dolomite/DolomiteLendStrategy.sol +273 -0
  121. package/contracts/strategies/dolomite/DolomiteLendStrategyMainnet_DAI.sol +26 -0
  122. package/contracts/strategies/dolomite/DolomiteLendStrategyMainnet_GMX.sol +26 -0
  123. package/contracts/strategies/dolomite/DolomiteLendStrategyMainnet_USDC.sol +26 -0
  124. package/contracts/strategies/dolomite/DolomiteLendStrategyMainnet_USDCe.sol +26 -0
  125. package/contracts/strategies/dolomite/DolomiteLendStrategyMainnet_USDT.sol +26 -0
  126. package/contracts/strategies/dolomite/DolomiteLendStrategyMainnet_WBTC.sol +26 -0
  127. package/contracts/strategies/dolomite/DolomiteLendStrategyMainnet_WETH.sol +26 -0
  128. package/contracts/strategies/fluid/FluidLendStrategy.sol +241 -0
  129. package/contracts/strategies/fluid/FluidLendStrategyMainnet_ETH.sol +25 -0
  130. package/contracts/strategies/fluid/FluidLendStrategyMainnet_USDC.sol +25 -0
  131. package/contracts/strategies/fluid/FluidLendStrategyMainnet_USDT.sol +25 -0
  132. package/contracts/strategies/gmx/GMXStrategy.sol +472 -0
  133. package/contracts/strategies/gmx/GMXStrategyMainnet_WBTC.sol +25 -0
  134. package/contracts/strategies/gmx/GMXViewer.sol +110 -0
  135. package/contracts/strategies/notional/NotionalStrategy.sol +223 -0
  136. package/contracts/strategies/notional/NotionalStrategyMainnet_nETH.sol +27 -0
  137. package/contracts/strategies/notional/NotionalStrategyMainnet_nUSDC.sol +27 -0
  138. package/contracts/strategies/notional/NotionalStrategyMainnet_nUSDT.sol +27 -0
  139. package/contracts/strategies/notional/NotionalStrategyMainnet_nwstETH.sol +27 -0
  140. package/contracts/strategies/venus/VenusFoldStrategy.sol +591 -0
  141. package/contracts/strategies/venus/VenusFoldStrategyMainnet_ARB.sol +32 -0
  142. package/contracts/strategies/venus/VenusFoldStrategyMainnet_ETH_core.sol +32 -0
  143. package/contracts/strategies/venus/VenusFoldStrategyMainnet_ETH_lsd.sol +32 -0
  144. package/contracts/strategies/venus/VenusFoldStrategyMainnet_USDC.sol +32 -0
  145. package/contracts/strategies/venus/VenusFoldStrategyMainnet_USDT.sol +32 -0
  146. package/contracts/strategies/venus/VenusFoldStrategyMainnet_WBTC.sol +32 -0
  147. package/hardhat.config.js +60 -0
  148. package/index.js +42 -0
  149. package/package.json +38 -6
  150. package/scripts/01-deploy-vault-regular-with-upgradable-strategy.js +41 -0
  151. package/scripts/02-deploy-vault-regular.js +35 -0
  152. package/scripts/03-deploy-upgradable-strategy.js +40 -0
  153. package/scripts/04-deploy-new-implementation.js +24 -0
  154. package/scripts/05-deploy-GMXViewer.js +17 -0
  155. package/scripts/06-deploy-GMXVault.js +49 -0
  156. package/scripts/07-deploy-ipor-fuses.js +29 -0
  157. package/scripts/08-deploy-drip.js +20 -0
  158. package/scripts/README.md +55 -0
  159. package/scripts/utils.js +22 -0
  160. package/test/aura/more-gyd.js +140 -0
  161. package/test/aura/susde-gyd.js +140 -0
  162. package/test/aura/wafrax-sfrax.js +140 -0
  163. package/test/aura/wagho-gyd.js +140 -0
  164. package/test/aura/wausdc-gho.js +141 -0
  165. package/test/aura/wausdc-gyd.js +140 -0
  166. package/test/aura/wausdt-gyd.js +140 -0
  167. package/test/aura/wsteth-gyd.js +138 -0
  168. package/test/camelot/arb-usdc.js +125 -0
  169. package/test/camelot/eth-usdc.js +125 -0
  170. package/test/camelot/eth-usdt.js +125 -0
  171. package/test/camelot/gmx-eth.js +125 -0
  172. package/test/camelot/grail-eth.js +125 -0
  173. package/test/camelot/usdc-usdt.js +125 -0
  174. package/test/camelot/wbtc-eth.js +125 -0
  175. package/test/dolomite/dai.js +127 -0
  176. package/test/dolomite/gmx.js +134 -0
  177. package/test/dolomite/usdc.js +127 -0
  178. package/test/dolomite/usdce.js +127 -0
  179. package/test/dolomite/usdt.js +127 -0
  180. package/test/dolomite/wbtc.js +127 -0
  181. package/test/dolomite/weth.js +127 -0
  182. package/test/fluid/eth.js +127 -0
  183. package/test/fluid/usdc.js +134 -0
  184. package/test/fluid/usdt.js +134 -0
  185. package/test/gmx/wbtc.js +184 -0
  186. package/test/notional/neth.js +133 -0
  187. package/test/notional/nusdc.js +133 -0
  188. package/test/notional/nusdt.js +133 -0
  189. package/test/notional/nwsteth.js +133 -0
  190. package/test/test-config.js +28 -0
  191. package/test/utilities/Utils.js +96 -0
  192. package/test/utilities/hh-utils.js +248 -0
  193. package/test/utilities/make-vault.js +16 -0
  194. package/test/venus/arb.js +135 -0
  195. package/test/venus/eth-core.js +133 -0
  196. package/test/venus/eth-lsd.js +133 -0
  197. package/test/venus/usdc.js +133 -0
  198. package/test/venus/usdt.js +133 -0
  199. package/test/venus/wbtc.js +133 -0
@@ -0,0 +1,273 @@
1
+ // SPDX-License-Identifier: Unlicense
2
+ pragma solidity 0.8.26;
3
+
4
+ import "@openzeppelin/contracts/utils/math/Math.sol";
5
+ import "@openzeppelin/contracts/utils/math/SafeMath.sol";
6
+ import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
7
+ import "../../base/interface/IUniversalLiquidator.sol";
8
+ import "../../base/upgradability/BaseUpgradeableStrategy.sol";
9
+ import "../../base/interface/dolomite/IDolomiteMargin.sol";
10
+ import "../../base/interface/dolomite/IDepositWithdraw.sol";
11
+ import "../../base/interface/dolomite/IRewardsDistributor.sol";
12
+
13
+ contract DolomiteLendStrategy is BaseUpgradeableStrategy {
14
+
15
+ using SafeMath for uint256;
16
+ using SafeERC20 for IERC20;
17
+
18
+ address public constant weth = address(0x82aF49447D8a07e3bd95BD0d56f35241523fBab1);
19
+ address public constant harvestMSIG = address(0xf3D1A027E858976634F81B7c41B09A05A46EdA21);
20
+
21
+ // additional storage slots (on top of BaseUpgradeableStrategy ones) are defined here
22
+ bytes32 internal constant _MARKET_ID_SLOT = 0x54fed29e040f8360ca8b822de4be5728a7f0714b74e8d5dd23a1d1ac0c75c6a7;
23
+ bytes32 internal constant _DOLOMITE_MARGIN_SLOT = 0xeb52083a303441dc22b6905f2ddc3b6ee13a44944ed7f2ebb0bcb3baf59e4e61;
24
+ bytes32 internal constant _DEPOSIT_WITHDRAW_SLOT = 0x096b7d9b1b276278667b14db2373be3a19524b5b48b8b667178d1ae019f52912;
25
+ bytes32 internal constant _STORED_SUPPLIED_SLOT = 0x280539da846b4989609abdccfea039bd1453e4f710c670b29b9eeaca0730c1a2;
26
+ bytes32 internal constant _PENDING_FEE_SLOT = 0x0af7af9f5ccfa82c3497f40c7c382677637aee27293a6243a22216b51481bd97;
27
+
28
+ // this would be reset on each upgrade
29
+ address[] public rewardTokens;
30
+
31
+ constructor() BaseUpgradeableStrategy() {
32
+ assert(_MARKET_ID_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.marketId")) - 1));
33
+ assert(_DOLOMITE_MARGIN_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.dolomiteMargin")) - 1));
34
+ assert(_DEPOSIT_WITHDRAW_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.depositWithdraw")) - 1));
35
+ assert(_STORED_SUPPLIED_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.storedSupplied")) - 1));
36
+ assert(_PENDING_FEE_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.pendingFee")) - 1));
37
+ }
38
+
39
+ function initializeBaseStrategy(
40
+ address _storage,
41
+ address _underlying,
42
+ address _vault,
43
+ address _dolomiteMargin,
44
+ address _depositWithdraw,
45
+ uint256 _marketId,
46
+ address _rewardToken
47
+ )
48
+ public initializer {
49
+ BaseUpgradeableStrategy.initialize(
50
+ _storage,
51
+ _underlying,
52
+ _vault,
53
+ _dolomiteMargin,
54
+ _rewardToken,
55
+ harvestMSIG
56
+ );
57
+
58
+ require(IDolomiteMargin(_dolomiteMargin).getMarketIdByTokenAddress(_underlying) == _marketId, "Underlying mismatch");
59
+ _setDolomiteMargin(_dolomiteMargin);
60
+ _setDepositWithdraw(_depositWithdraw);
61
+ _setMarketId(_marketId);
62
+ }
63
+
64
+ function currentBalance() public view returns (uint256) {
65
+ IDolomiteMargin.Info memory account;
66
+ account.owner = address(this);
67
+ IDolomiteMargin.Wei memory balanceInfo = IDolomiteMargin(dolomiteMargin()).getAccountWei(account, marketId());
68
+ uint256 underlyingBalance = balanceInfo.value;
69
+ return underlyingBalance;
70
+ }
71
+
72
+ function storedBalance() public view returns (uint256) {
73
+ return getUint256(_STORED_SUPPLIED_SLOT);
74
+ }
75
+
76
+ function _updateStoredBalance() internal {
77
+ uint256 balance = currentBalance();
78
+ setUint256(_STORED_SUPPLIED_SLOT, balance);
79
+ }
80
+
81
+ function totalFeeNumerator() public view returns (uint256) {
82
+ return strategistFeeNumerator().add(platformFeeNumerator()).add(profitSharingNumerator());
83
+ }
84
+
85
+ function pendingFee() public view returns (uint256) {
86
+ return getUint256(_PENDING_FEE_SLOT);
87
+ }
88
+
89
+ function _accrueFee() internal {
90
+ uint256 fee;
91
+ if (currentBalance() > storedBalance()) {
92
+ uint256 balanceIncrease = currentBalance().sub(storedBalance());
93
+ fee = balanceIncrease.mul(totalFeeNumerator()).div(feeDenominator());
94
+ }
95
+ setUint256(_PENDING_FEE_SLOT, pendingFee().add(fee));
96
+ _updateStoredBalance();
97
+ }
98
+
99
+ function _handleFee() internal {
100
+ _accrueFee();
101
+ uint256 fee = pendingFee();
102
+ if (fee > 0) {
103
+ uint256 balanceIncrease = fee.mul(feeDenominator()).div(totalFeeNumerator());
104
+ _redeem(fee);
105
+ address _underlying = underlying();
106
+ if (IERC20(_underlying).balanceOf(address(this)) < fee) {
107
+ balanceIncrease = IERC20(_underlying).balanceOf(address(this)).mul(feeDenominator()).div(totalFeeNumerator());
108
+ }
109
+ _notifyProfitInRewardToken(_underlying, balanceIncrease);
110
+ setUint256(_PENDING_FEE_SLOT, 0);
111
+ }
112
+ }
113
+
114
+ function depositArbCheck() public pure returns (bool) {
115
+ // there's no arb here.
116
+ return true;
117
+ }
118
+
119
+ function unsalvagableTokens(address token) public view returns (bool) {
120
+ return (token == rewardToken() || token == underlying());
121
+ }
122
+
123
+ /**
124
+ * The strategy invests by supplying the underlying as a collateral.
125
+ */
126
+ function _investAllUnderlying() internal onlyNotPausedInvesting {
127
+ address _underlying = underlying();
128
+ uint256 underlyingBalance = IERC20(_underlying).balanceOf(address(this));
129
+ if (underlyingBalance > 0) {
130
+ _supply(underlyingBalance);
131
+ }
132
+ }
133
+
134
+ function withdrawAllToVault() public restricted {
135
+ _liquidateRewards();
136
+ address _underlying = underlying();
137
+ _redeemAll();
138
+ if (IERC20(_underlying).balanceOf(address(this)) > 0) {
139
+ IERC20(_underlying).safeTransfer(vault(), IERC20(_underlying).balanceOf(address(this)));
140
+ }
141
+ _updateStoredBalance();
142
+ }
143
+
144
+ function emergencyExit() external onlyGovernance {
145
+ _accrueFee();
146
+ _redeemAll();
147
+ _setPausedInvesting(true);
148
+ _updateStoredBalance();
149
+ }
150
+
151
+ function continueInvesting() public onlyGovernance {
152
+ _setPausedInvesting(false);
153
+ }
154
+
155
+ function withdrawToVault(uint256 amountUnderlying) public restricted {
156
+ _accrueFee();
157
+ address _underlying = underlying();
158
+ uint256 balance = IERC20(_underlying).balanceOf(address(this));
159
+ if (amountUnderlying <= balance) {
160
+ IERC20(_underlying).safeTransfer(vault(), amountUnderlying);
161
+ return;
162
+ }
163
+ uint256 toRedeem = amountUnderlying.sub(balance);
164
+ // get some of the underlying
165
+ _redeem(toRedeem);
166
+ balance = IERC20(_underlying).balanceOf(address(this));
167
+ // transfer the amount requested (or the amount we have) back to vault()
168
+ IERC20(_underlying).safeTransfer(vault(), Math.min(amountUnderlying, balance));
169
+ balance = IERC20(_underlying).balanceOf(address(this));
170
+ if (balance > 1e1) {
171
+ _investAllUnderlying();
172
+ }
173
+ _updateStoredBalance();
174
+ }
175
+
176
+ /**
177
+ * Withdraws all assets, liquidates XVS, and invests again in the required ratio.
178
+ */
179
+ function doHardWork() public restricted {
180
+ _liquidateRewards();
181
+ _investAllUnderlying();
182
+ _updateStoredBalance();
183
+ }
184
+
185
+ /**
186
+ * Salvages a token.
187
+ */
188
+ function salvage(address recipient, address token, uint256 amount) public onlyGovernance {
189
+ // To make sure that governance cannot come in and take away the coins
190
+ require(!unsalvagableTokens(token), "token is defined as not salvagable");
191
+ IERC20(token).safeTransfer(recipient, amount);
192
+ }
193
+
194
+ function addRewardToken(address _token) public onlyGovernance {
195
+ rewardTokens.push(_token);
196
+ }
197
+
198
+ function _liquidateRewards() internal {
199
+ if (!sell()) {
200
+ // Profits can be disabled for possible simplified and rapid exit
201
+ emit ProfitsNotCollected(sell(), false);
202
+ return;
203
+ }
204
+ _handleFee();
205
+ }
206
+
207
+ /**
208
+ * Returns the current balance.
209
+ */
210
+ function investedUnderlyingBalance() public view returns (uint256) {
211
+ return IERC20(underlying()).balanceOf(address(this))
212
+ .add(storedBalance())
213
+ .sub(pendingFee());
214
+ }
215
+
216
+ function _supply(uint256 amount) internal {
217
+ address _underlying = underlying();
218
+ address _dolomiteMargin = dolomiteMargin();
219
+ IERC20(_underlying).safeApprove(_dolomiteMargin, 0);
220
+ IERC20(_underlying).safeApprove(_dolomiteMargin, amount);
221
+ IDepositWithdraw(depositWithdraw()).depositWeiIntoDefaultAccount(marketId(), amount);
222
+ }
223
+
224
+ function _redeem(uint256 amountUnderlying) internal {
225
+ IDepositWithdraw(depositWithdraw()).withdrawWeiFromDefaultAccount(
226
+ marketId(),
227
+ amountUnderlying,
228
+ IDepositWithdraw.BalanceCheckFlag.From
229
+ );
230
+ }
231
+
232
+ function _redeemAll() internal {
233
+ IDepositWithdraw(depositWithdraw()).withdrawWeiFromDefaultAccount(
234
+ marketId(),
235
+ currentBalance(),
236
+ IDepositWithdraw.BalanceCheckFlag.From
237
+ );
238
+ }
239
+
240
+ function _setDolomiteMargin (address _target) internal {
241
+ setAddress(_DOLOMITE_MARGIN_SLOT, _target);
242
+ }
243
+
244
+ function dolomiteMargin() public view returns (address) {
245
+ return getAddress(_DOLOMITE_MARGIN_SLOT);
246
+ }
247
+
248
+ function _setDepositWithdraw (address _target) internal {
249
+ setAddress(_DEPOSIT_WITHDRAW_SLOT, _target);
250
+ }
251
+
252
+ function depositWithdraw() public view returns (address) {
253
+ return getAddress(_DEPOSIT_WITHDRAW_SLOT);
254
+ }
255
+
256
+ function _setMarketId (uint256 _target) internal {
257
+ setUint256(_MARKET_ID_SLOT, _target);
258
+ }
259
+
260
+ function marketId() public view returns (uint256) {
261
+ return getUint256(_MARKET_ID_SLOT);
262
+ }
263
+
264
+ function finalizeUpgrade() external onlyGovernance {
265
+ _finalizeUpgrade();
266
+ }
267
+
268
+ function claimRewards(IRewardsDistributor.ClaimInfo[] calldata _claimInfo) external {
269
+ IRewardsDistributor(0x2E3D10CC42227aF0ce908F00C76fFe1dE1728b4B).claim(_claimInfo);
270
+ }
271
+
272
+ receive() external payable {}
273
+ }
@@ -0,0 +1,26 @@
1
+ //SPDX-License-Identifier: Unlicense
2
+ pragma solidity 0.8.26;
3
+
4
+ import "./DolomiteLendStrategy.sol";
5
+
6
+ contract DolomiteLendStrategyMainnet_DAI is DolomiteLendStrategy {
7
+
8
+ constructor() {}
9
+
10
+ function initializeStrategy(
11
+ address _storage,
12
+ address _vault
13
+ ) public initializer {
14
+ address underlying = address(0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1);
15
+ address weth = address(0x82aF49447D8a07e3bd95BD0d56f35241523fBab1);
16
+ DolomiteLendStrategy.initializeBaseStrategy(
17
+ _storage,
18
+ underlying,
19
+ _vault,
20
+ address(0x6Bd780E7fDf01D77e4d475c821f1e7AE05409072),
21
+ address(0xAdB9D68c613df4AA363B42161E1282117C7B9594),
22
+ 1,
23
+ weth
24
+ );
25
+ }
26
+ }
@@ -0,0 +1,26 @@
1
+ //SPDX-License-Identifier: Unlicense
2
+ pragma solidity 0.8.26;
3
+
4
+ import "./DolomiteLendStrategy.sol";
5
+
6
+ contract DolomiteLendStrategyMainnet_GMX is DolomiteLendStrategy {
7
+
8
+ constructor() {}
9
+
10
+ function initializeStrategy(
11
+ address _storage,
12
+ address _vault
13
+ ) public initializer {
14
+ address underlying = address(0xfc5A1A6EB076a2C7aD06eD22C90d7E710E35ad0a);
15
+ address weth = address(0x82aF49447D8a07e3bd95BD0d56f35241523fBab1);
16
+ DolomiteLendStrategy.initializeBaseStrategy(
17
+ _storage,
18
+ underlying,
19
+ _vault,
20
+ address(0x6Bd780E7fDf01D77e4d475c821f1e7AE05409072),
21
+ address(0xAdB9D68c613df4AA363B42161E1282117C7B9594),
22
+ 29,
23
+ weth
24
+ );
25
+ }
26
+ }
@@ -0,0 +1,26 @@
1
+ //SPDX-License-Identifier: Unlicense
2
+ pragma solidity 0.8.26;
3
+
4
+ import "./DolomiteLendStrategy.sol";
5
+
6
+ contract DolomiteLendStrategyMainnet_USDC is DolomiteLendStrategy {
7
+
8
+ constructor() {}
9
+
10
+ function initializeStrategy(
11
+ address _storage,
12
+ address _vault
13
+ ) public initializer {
14
+ address underlying = address(0xaf88d065e77c8cC2239327C5EDb3A432268e5831);
15
+ address weth = address(0x82aF49447D8a07e3bd95BD0d56f35241523fBab1);
16
+ DolomiteLendStrategy.initializeBaseStrategy(
17
+ _storage,
18
+ underlying,
19
+ _vault,
20
+ address(0x6Bd780E7fDf01D77e4d475c821f1e7AE05409072),
21
+ address(0xAdB9D68c613df4AA363B42161E1282117C7B9594),
22
+ 17,
23
+ weth
24
+ );
25
+ }
26
+ }
@@ -0,0 +1,26 @@
1
+ //SPDX-License-Identifier: Unlicense
2
+ pragma solidity 0.8.26;
3
+
4
+ import "./DolomiteLendStrategy.sol";
5
+
6
+ contract DolomiteLendStrategyMainnet_USDCe is DolomiteLendStrategy {
7
+
8
+ constructor() {}
9
+
10
+ function initializeStrategy(
11
+ address _storage,
12
+ address _vault
13
+ ) public initializer {
14
+ address underlying = address(0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8);
15
+ address weth = address(0x82aF49447D8a07e3bd95BD0d56f35241523fBab1);
16
+ DolomiteLendStrategy.initializeBaseStrategy(
17
+ _storage,
18
+ underlying,
19
+ _vault,
20
+ address(0x6Bd780E7fDf01D77e4d475c821f1e7AE05409072),
21
+ address(0xAdB9D68c613df4AA363B42161E1282117C7B9594),
22
+ 2,
23
+ weth
24
+ );
25
+ }
26
+ }
@@ -0,0 +1,26 @@
1
+ //SPDX-License-Identifier: Unlicense
2
+ pragma solidity 0.8.26;
3
+
4
+ import "./DolomiteLendStrategy.sol";
5
+
6
+ contract DolomiteLendStrategyMainnet_USDT is DolomiteLendStrategy {
7
+
8
+ constructor() {}
9
+
10
+ function initializeStrategy(
11
+ address _storage,
12
+ address _vault
13
+ ) public initializer {
14
+ address underlying = address(0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9);
15
+ address weth = address(0x82aF49447D8a07e3bd95BD0d56f35241523fBab1);
16
+ DolomiteLendStrategy.initializeBaseStrategy(
17
+ _storage,
18
+ underlying,
19
+ _vault,
20
+ address(0x6Bd780E7fDf01D77e4d475c821f1e7AE05409072),
21
+ address(0xAdB9D68c613df4AA363B42161E1282117C7B9594),
22
+ 5,
23
+ weth
24
+ );
25
+ }
26
+ }
@@ -0,0 +1,26 @@
1
+ //SPDX-License-Identifier: Unlicense
2
+ pragma solidity 0.8.26;
3
+
4
+ import "./DolomiteLendStrategy.sol";
5
+
6
+ contract DolomiteLendStrategyMainnet_WBTC is DolomiteLendStrategy {
7
+
8
+ constructor() {}
9
+
10
+ function initializeStrategy(
11
+ address _storage,
12
+ address _vault
13
+ ) public initializer {
14
+ address underlying = address(0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f);
15
+ address weth = address(0x82aF49447D8a07e3bd95BD0d56f35241523fBab1);
16
+ DolomiteLendStrategy.initializeBaseStrategy(
17
+ _storage,
18
+ underlying,
19
+ _vault,
20
+ address(0x6Bd780E7fDf01D77e4d475c821f1e7AE05409072),
21
+ address(0xAdB9D68c613df4AA363B42161E1282117C7B9594),
22
+ 4,
23
+ weth
24
+ );
25
+ }
26
+ }
@@ -0,0 +1,26 @@
1
+ //SPDX-License-Identifier: Unlicense
2
+ pragma solidity 0.8.26;
3
+
4
+ import "./DolomiteLendStrategy.sol";
5
+
6
+ contract DolomiteLendStrategyMainnet_WETH is DolomiteLendStrategy {
7
+
8
+ constructor() {}
9
+
10
+ function initializeStrategy(
11
+ address _storage,
12
+ address _vault
13
+ ) public initializer {
14
+ address underlying = address(0x82aF49447D8a07e3bd95BD0d56f35241523fBab1);
15
+ address weth = address(0x82aF49447D8a07e3bd95BD0d56f35241523fBab1);
16
+ DolomiteLendStrategy.initializeBaseStrategy(
17
+ _storage,
18
+ underlying,
19
+ _vault,
20
+ address(0x6Bd780E7fDf01D77e4d475c821f1e7AE05409072),
21
+ address(0xAdB9D68c613df4AA363B42161E1282117C7B9594),
22
+ 0,
23
+ weth
24
+ );
25
+ }
26
+ }
@@ -0,0 +1,241 @@
1
+ // SPDX-License-Identifier: Unlicense
2
+ pragma solidity 0.8.26;
3
+
4
+ import "@openzeppelin/contracts/utils/math/Math.sol";
5
+ import "@openzeppelin/contracts/utils/math/SafeMath.sol";
6
+ import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
7
+ import "../../base/interface/IUniversalLiquidator.sol";
8
+ import "../../base/upgradability/BaseUpgradeableStrategy.sol";
9
+ import "../../base/interface/IERC4626.sol";
10
+
11
+ contract FluidLendStrategy is BaseUpgradeableStrategy {
12
+
13
+ using SafeMath for uint256;
14
+ using SafeERC20 for IERC20;
15
+
16
+ address public constant weth = address(0x82aF49447D8a07e3bd95BD0d56f35241523fBab1);
17
+ address public constant harvestMSIG = address(0xf3D1A027E858976634F81B7c41B09A05A46EdA21);
18
+
19
+ // additional storage slots (on top of BaseUpgradeableStrategy ones) are defined here
20
+ bytes32 internal constant _FTOKEN_SLOT = 0x462e4d44c9bae3e0ee3d71929710bef82ca7c929ce31980e75572ea415835b0e;
21
+ bytes32 internal constant _STORED_SUPPLIED_SLOT = 0x280539da846b4989609abdccfea039bd1453e4f710c670b29b9eeaca0730c1a2;
22
+ bytes32 internal constant _PENDING_FEE_SLOT = 0x0af7af9f5ccfa82c3497f40c7c382677637aee27293a6243a22216b51481bd97;
23
+
24
+ // this would be reset on each upgrade
25
+ address[] public rewardTokens;
26
+
27
+ constructor() BaseUpgradeableStrategy() {
28
+ assert(_FTOKEN_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.fToken")) - 1));
29
+ assert(_STORED_SUPPLIED_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.storedSupplied")) - 1));
30
+ assert(_PENDING_FEE_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.pendingFee")) - 1));
31
+ }
32
+
33
+ function initializeBaseStrategy(
34
+ address _storage,
35
+ address _underlying,
36
+ address _vault,
37
+ address _fToken,
38
+ address _rewardToken
39
+ )
40
+ public initializer {
41
+ BaseUpgradeableStrategy.initialize(
42
+ _storage,
43
+ _underlying,
44
+ _vault,
45
+ _fToken,
46
+ _rewardToken,
47
+ harvestMSIG
48
+ );
49
+
50
+ require(IERC4626(_fToken).asset() == _underlying, "Underlying mismatch");
51
+ _setFToken(_fToken);
52
+ }
53
+
54
+ function currentBalance() public view returns (uint256) {
55
+ address _fToken = fToken();
56
+ uint256 underlyingBalance = IERC4626(_fToken).previewRedeem(IERC20(_fToken).balanceOf(address(this)));
57
+ return underlyingBalance;
58
+ }
59
+
60
+ function storedBalance() public view returns (uint256) {
61
+ return getUint256(_STORED_SUPPLIED_SLOT);
62
+ }
63
+
64
+ function _updateStoredBalance() internal {
65
+ uint256 balance = currentBalance();
66
+ setUint256(_STORED_SUPPLIED_SLOT, balance);
67
+ }
68
+
69
+ function totalFeeNumerator() public view returns (uint256) {
70
+ return strategistFeeNumerator().add(platformFeeNumerator()).add(profitSharingNumerator());
71
+ }
72
+
73
+ function pendingFee() public view returns (uint256) {
74
+ return getUint256(_PENDING_FEE_SLOT);
75
+ }
76
+
77
+ function _accrueFee() internal {
78
+ uint256 fee;
79
+ if (currentBalance() > storedBalance()) {
80
+ uint256 balanceIncrease = currentBalance().sub(storedBalance());
81
+ fee = balanceIncrease.mul(totalFeeNumerator()).div(feeDenominator());
82
+ }
83
+ setUint256(_PENDING_FEE_SLOT, pendingFee().add(fee));
84
+ _updateStoredBalance();
85
+ }
86
+
87
+ function _handleFee() internal {
88
+ _accrueFee();
89
+ uint256 fee = pendingFee();
90
+ if (fee > 0) {
91
+ uint256 balanceIncrease = fee.mul(feeDenominator()).div(totalFeeNumerator());
92
+ _redeem(fee);
93
+ address _underlying = underlying();
94
+ if (IERC20(_underlying).balanceOf(address(this)) < fee) {
95
+ balanceIncrease = IERC20(_underlying).balanceOf(address(this)).mul(feeDenominator()).div(totalFeeNumerator());
96
+ }
97
+ _notifyProfitInRewardToken(_underlying, balanceIncrease);
98
+ setUint256(_PENDING_FEE_SLOT, 0);
99
+ }
100
+ }
101
+
102
+ function depositArbCheck() public pure returns (bool) {
103
+ // there's no arb here.
104
+ return true;
105
+ }
106
+
107
+ function unsalvagableTokens(address token) public view returns (bool) {
108
+ return (token == rewardToken() || token == underlying());
109
+ }
110
+
111
+ /**
112
+ * The strategy invests by supplying the underlying as a collateral.
113
+ */
114
+ function _investAllUnderlying() internal onlyNotPausedInvesting {
115
+ address _underlying = underlying();
116
+ uint256 underlyingBalance = IERC20(_underlying).balanceOf(address(this));
117
+ if (underlyingBalance > 1e1) {
118
+ _supply(underlyingBalance);
119
+ }
120
+ }
121
+
122
+ function withdrawAllToVault() public restricted {
123
+ _liquidateRewards();
124
+ address _underlying = underlying();
125
+ _redeemAll();
126
+ if (IERC20(_underlying).balanceOf(address(this)) > 0) {
127
+ IERC20(_underlying).safeTransfer(vault(), IERC20(_underlying).balanceOf(address(this)));
128
+ }
129
+ _updateStoredBalance();
130
+ }
131
+
132
+ function emergencyExit() external onlyGovernance {
133
+ _accrueFee();
134
+ _redeemAll();
135
+ _setPausedInvesting(true);
136
+ _updateStoredBalance();
137
+ }
138
+
139
+ function continueInvesting() public onlyGovernance {
140
+ _setPausedInvesting(false);
141
+ }
142
+
143
+ function withdrawToVault(uint256 amountUnderlying) public restricted {
144
+ _accrueFee();
145
+ address _underlying = underlying();
146
+ uint256 balance = IERC20(_underlying).balanceOf(address(this));
147
+ if (amountUnderlying <= balance) {
148
+ IERC20(_underlying).safeTransfer(vault(), amountUnderlying);
149
+ return;
150
+ }
151
+ uint256 toRedeem = amountUnderlying.sub(balance);
152
+ // get some of the underlying
153
+ _redeem(toRedeem);
154
+ balance = IERC20(_underlying).balanceOf(address(this));
155
+ // transfer the amount requested (or the amount we have) back to vault()
156
+ IERC20(_underlying).safeTransfer(vault(), Math.min(amountUnderlying, balance));
157
+ balance = IERC20(_underlying).balanceOf(address(this));
158
+ if (balance > 1e1) {
159
+ _investAllUnderlying();
160
+ }
161
+ _updateStoredBalance();
162
+ }
163
+
164
+ /**
165
+ * Withdraws all assets, liquidates XVS, and invests again in the required ratio.
166
+ */
167
+ function doHardWork() public restricted {
168
+ _liquidateRewards();
169
+ _investAllUnderlying();
170
+ _updateStoredBalance();
171
+ }
172
+
173
+ /**
174
+ * Salvages a token.
175
+ */
176
+ function salvage(address recipient, address token, uint256 amount) public onlyGovernance {
177
+ // To make sure that governance cannot come in and take away the coins
178
+ require(!unsalvagableTokens(token), "token is defined as not salvagable");
179
+ IERC20(token).safeTransfer(recipient, amount);
180
+ }
181
+
182
+ function addRewardToken(address _token) public onlyGovernance {
183
+ rewardTokens.push(_token);
184
+ }
185
+
186
+ function _liquidateRewards() internal {
187
+ if (!sell()) {
188
+ // Profits can be disabled for possible simplified and rapid exit
189
+ emit ProfitsNotCollected(sell(), false);
190
+ return;
191
+ }
192
+ _handleFee();
193
+ }
194
+
195
+ /**
196
+ * Returns the current balance.
197
+ */
198
+ function investedUnderlyingBalance() public view returns (uint256) {
199
+ return IERC20(underlying()).balanceOf(address(this))
200
+ .add(storedBalance())
201
+ .sub(pendingFee());
202
+ }
203
+
204
+ function _supply(uint256 amount) internal {
205
+ address _underlying = underlying();
206
+ address _fToken = fToken();
207
+ IERC20(_underlying).safeApprove(_fToken, 0);
208
+ IERC20(_underlying).safeApprove(_fToken, amount);
209
+ IERC4626(_fToken).deposit(amount, address(this));
210
+ }
211
+
212
+ function _redeem(uint256 amountUnderlying) internal {
213
+ address _fToken = fToken();
214
+ IERC4626(_fToken).withdraw(amountUnderlying, address(this), address(this));
215
+ }
216
+
217
+ function _redeemAll() internal {
218
+ address _fToken = fToken();
219
+ if (IERC20(_fToken).balanceOf(address(this)) > 0) {
220
+ IERC4626(_fToken).redeem(
221
+ IERC20(_fToken).balanceOf(address(this)),
222
+ address(this),
223
+ address(this)
224
+ );
225
+ }
226
+ }
227
+
228
+ function _setFToken (address _target) internal {
229
+ setAddress(_FTOKEN_SLOT, _target);
230
+ }
231
+
232
+ function fToken() public view returns (address) {
233
+ return getAddress(_FTOKEN_SLOT);
234
+ }
235
+
236
+ function finalizeUpgrade() external onlyGovernance {
237
+ _finalizeUpgrade();
238
+ }
239
+
240
+ receive() external payable {}
241
+ }