@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,591 @@
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/compound/CTokenInterface.sol";
10
+ import "../../base/interface/compound/IComptroller.sol";
11
+ import "../../base/interface/venus/IRewardsDistributor.sol";
12
+ import "../../base/interface/merkl/IDistributor.sol";
13
+ import "../../base/interface/balancer/IBVault.sol";
14
+
15
+ contract VenusFoldStrategy is BaseUpgradeableStrategy {
16
+
17
+ using SafeMath for uint256;
18
+ using SafeERC20 for IERC20;
19
+
20
+ address public constant harvestMSIG = address(0xf3D1A027E858976634F81B7c41B09A05A46EdA21);
21
+ address public constant bVault = address(0xBA12222222228d8Ba445958a75a0704d566BF2C8);
22
+
23
+ // additional storage slots (on top of BaseUpgradeableStrategy ones) are defined here
24
+ bytes32 internal constant _CTOKEN_SLOT = 0x316ad921d519813e6e41c0e056b79e4395192c2b101f8b61cf5b94999360d568;
25
+ bytes32 internal constant _COMPTROLLER_SLOT = 0x21864471ca9d8b67bc7f58951fb160897ce623fdb405c56534d08a363a47e235;
26
+ bytes32 internal constant _STORED_SUPPLIED_SLOT = 0x280539da846b4989609abdccfea039bd1453e4f710c670b29b9eeaca0730c1a2;
27
+ bytes32 internal constant _PENDING_FEE_SLOT = 0x0af7af9f5ccfa82c3497f40c7c382677637aee27293a6243a22216b51481bd97;
28
+ bytes32 internal constant _COLLATERALFACTORNUMERATOR_SLOT = 0x129eccdfbcf3761d8e2f66393221fa8277b7623ad13ed7693a0025435931c64a;
29
+ bytes32 internal constant _FACTORDENOMINATOR_SLOT = 0x4e92df66cc717205e8df80bec55fc1429f703d590a2d456b97b74f0008b4a3ee;
30
+ bytes32 internal constant _BORROWTARGETFACTORNUMERATOR_SLOT = 0xa65533f4b41f3786d877c8fdd4ae6d27ada84e1d9c62ea3aca309e9aa03af1cd;
31
+ bytes32 internal constant _FOLD_SLOT = 0x1841be4c16015a744c9fbf595f7c6b32d40278c16c1fc7cf2de88c6348de44ba;
32
+
33
+ bool internal makingFlashDeposit;
34
+ bool internal makingFlashWithdrawal;
35
+
36
+ // this would be reset on each upgrade
37
+ address[] public rewardTokens;
38
+
39
+ constructor() BaseUpgradeableStrategy() {
40
+ assert(_CTOKEN_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.cToken")) - 1));
41
+ assert(_COMPTROLLER_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.comptroller")) - 1));
42
+ assert(_STORED_SUPPLIED_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.storedSupplied")) - 1));
43
+ assert(_PENDING_FEE_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.pendingFee")) - 1));
44
+ assert(_COLLATERALFACTORNUMERATOR_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.collateralFactorNumerator")) - 1));
45
+ assert(_FACTORDENOMINATOR_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.factorDenominator")) - 1));
46
+ assert(_BORROWTARGETFACTORNUMERATOR_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.borrowTargetFactorNumerator")) - 1));
47
+ assert(_FOLD_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.fold")) - 1));
48
+ }
49
+
50
+ function initializeBaseStrategy(
51
+ address _storage,
52
+ address _underlying,
53
+ address _vault,
54
+ address _cToken,
55
+ address _comptroller,
56
+ address _rewardToken,
57
+ uint256 _borrowTargetFactorNumerator,
58
+ uint256 _collateralFactorNumerator,
59
+ uint256 _factorDenominator,
60
+ bool _fold
61
+ )
62
+ public initializer {
63
+ BaseUpgradeableStrategy.initialize(
64
+ _storage,
65
+ _underlying,
66
+ _vault,
67
+ _comptroller,
68
+ _rewardToken,
69
+ harvestMSIG
70
+ );
71
+
72
+ require(CTokenInterface(_cToken).underlying() == _underlying, "Underlying mismatch");
73
+
74
+ _setCToken(_cToken);
75
+ _setComptroller(_comptroller);
76
+
77
+ require(_collateralFactorNumerator < _factorDenominator, "Numerator should be smaller than denominator");
78
+ require(_borrowTargetFactorNumerator < _collateralFactorNumerator, "Target should be lower than limit");
79
+ _setFactorDenominator(_factorDenominator);
80
+ setUint256(_COLLATERALFACTORNUMERATOR_SLOT, _collateralFactorNumerator);
81
+ setUint256(_BORROWTARGETFACTORNUMERATOR_SLOT, _borrowTargetFactorNumerator);
82
+ setBoolean(_FOLD_SLOT, _fold);
83
+
84
+ address[] memory markets = new address[](1);
85
+ markets[0] = _cToken;
86
+ IComptroller(_comptroller).enterMarkets(markets);
87
+ }
88
+
89
+ function currentBalance() public returns (uint256) {
90
+ address _cToken = cToken();
91
+ // amount we supplied
92
+ uint256 suppliedInUnderlying = CTokenInterface(_cToken).balanceOfUnderlying(address(this));
93
+ // amount we borrowed
94
+ uint256 borrowedInUnderlying = CTokenInterface(_cToken).borrowBalanceCurrent(address(this));
95
+ return suppliedInUnderlying.sub(borrowedInUnderlying);
96
+ }
97
+
98
+ function storedBalance() public view returns (uint256) {
99
+ return getUint256(_STORED_SUPPLIED_SLOT);
100
+ }
101
+
102
+ function _updateStoredBalance() internal {
103
+ uint256 balance = currentBalance();
104
+ setUint256(_STORED_SUPPLIED_SLOT, balance);
105
+ }
106
+
107
+ function totalFeeNumerator() public view returns (uint256) {
108
+ return strategistFeeNumerator().add(platformFeeNumerator()).add(profitSharingNumerator());
109
+ }
110
+
111
+ function pendingFee() public view returns (uint256) {
112
+ return getUint256(_PENDING_FEE_SLOT);
113
+ }
114
+
115
+ function _accrueFee() internal {
116
+ uint256 fee;
117
+ if (currentBalance() > storedBalance()) {
118
+ uint256 balanceIncrease = currentBalance().sub(storedBalance());
119
+ fee = balanceIncrease.mul(totalFeeNumerator()).div(feeDenominator());
120
+ }
121
+ setUint256(_PENDING_FEE_SLOT, pendingFee().add(fee));
122
+ _updateStoredBalance();
123
+ }
124
+
125
+ function _handleFee() internal {
126
+ _accrueFee();
127
+ uint256 fee = pendingFee();
128
+ if (fee > 100) {
129
+ _redeem(fee);
130
+ address _underlying = underlying();
131
+ fee = Math.min(fee, IERC20(_underlying).balanceOf(address(this)));
132
+ uint256 balanceIncrease = fee.mul(feeDenominator()).div(totalFeeNumerator());
133
+ _notifyProfitInRewardToken(_underlying, balanceIncrease);
134
+ setUint256(_PENDING_FEE_SLOT, pendingFee().sub(fee));
135
+ }
136
+ }
137
+
138
+ function depositArbCheck() public pure returns (bool) {
139
+ // there's no arb here.
140
+ return true;
141
+ }
142
+
143
+ function unsalvagableTokens(address token) public view returns (bool) {
144
+ return (token == rewardToken() || token == underlying() || token == cToken());
145
+ }
146
+
147
+ function _investAllUnderlying() internal onlyNotPausedInvesting {
148
+ address _underlying = underlying();
149
+ uint256 underlyingBalance = IERC20(_underlying).balanceOf(address(this));
150
+ if (underlyingBalance > 0) {
151
+ _supply(underlyingBalance);
152
+ }
153
+ if (fold()) {
154
+ _depositWithFlashloan();
155
+ }
156
+ }
157
+
158
+ function withdrawAllToVault() public restricted {
159
+ address _underlying = underlying();
160
+ _withdrawMaximum(true);
161
+ uint256 balance = IERC20(_underlying).balanceOf(address(this));
162
+ if (balance > 0) {
163
+ IERC20(_underlying).safeTransfer(vault(), balance);
164
+ }
165
+ _updateStoredBalance();
166
+ }
167
+
168
+ function emergencyExit() external onlyGovernance {
169
+ _withdrawMaximum(false);
170
+ _setPausedInvesting(true);
171
+ _updateStoredBalance();
172
+ }
173
+
174
+ function _withdrawMaximum(bool claim) internal {
175
+ if (claim) {
176
+ _handleFee();
177
+ _claimReward();
178
+ _liquidateReward();
179
+ } else {
180
+ _accrueFee();
181
+ }
182
+ _redeemMaximum();
183
+ }
184
+
185
+ function continueInvesting() public onlyGovernance {
186
+ _setPausedInvesting(false);
187
+ }
188
+
189
+ function withdrawToVault(uint256 amountUnderlying) public restricted {
190
+ _accrueFee();
191
+ address _underlying = underlying();
192
+ uint256 balance = IERC20(_underlying).balanceOf(address(this));
193
+ if (amountUnderlying <= balance) {
194
+ IERC20(_underlying).safeTransfer(vault(), amountUnderlying);
195
+ return;
196
+ }
197
+ uint256 toRedeem = amountUnderlying.sub(balance);
198
+ // get some of the underlying
199
+ _redeemPartial(toRedeem);
200
+ // transfer the amount requested (or the amount we have) back to vault()
201
+ IERC20(_underlying).safeTransfer(vault(), amountUnderlying);
202
+ balance = IERC20(_underlying).balanceOf(address(this));
203
+ if (balance > 0) {
204
+ _investAllUnderlying();
205
+ }
206
+ _updateStoredBalance();
207
+ }
208
+
209
+ function _redeemPartial(uint256 amountUnderlying) internal {
210
+ address _underlying = underlying();
211
+ uint256 balanceBefore = IERC20(_underlying).balanceOf(address(this));
212
+ _redeemWithFlashloan(
213
+ amountUnderlying,
214
+ fold()? borrowTargetFactorNumerator():0
215
+ );
216
+ uint256 balanceAfter = IERC20(_underlying).balanceOf(address(this));
217
+ require(balanceAfter.sub(balanceBefore) >= amountUnderlying, "Unable to withdraw the entire amountUnderlying");
218
+ }
219
+
220
+ function doHardWork() public restricted {
221
+ _handleFee();
222
+ _claimReward();
223
+ _liquidateReward();
224
+ _investAllUnderlying();
225
+ _updateStoredBalance();
226
+ }
227
+
228
+ /**
229
+ * Salvages a token.
230
+ */
231
+ function salvage(address recipient, address token, uint256 amount) public onlyGovernance {
232
+ // To make sure that governance cannot come in and take away the coins
233
+ require(!unsalvagableTokens(token), "token is defined as not salvagable");
234
+ IERC20(token).safeTransfer(recipient, amount);
235
+ }
236
+
237
+ function _claimReward() internal {
238
+ address[] memory rewardDistributors = IComptroller(comptroller()).getRewardDistributors();
239
+ for (uint256 i = 0; i < rewardDistributors.length; i++) {
240
+ address rewardDistributor = rewardDistributors[i];
241
+ IRewardsDistributor(rewardDistributor).claimRewardToken(address(this));
242
+ }
243
+ }
244
+
245
+ function addRewardToken(address _token) public onlyGovernance {
246
+ rewardTokens.push(_token);
247
+ }
248
+
249
+ function _liquidateReward() internal {
250
+ if (!sell()) {
251
+ // Profits can be disabled for possible simplified and rapid exit
252
+ emit ProfitsNotCollected(sell(), false);
253
+ return;
254
+ }
255
+ address _rewardToken = rewardToken();
256
+ address _universalLiquidator = universalLiquidator();
257
+ address _underlying = underlying();
258
+ for(uint256 i = 0; i < rewardTokens.length; i++){
259
+ address token = rewardTokens[i];
260
+ uint256 balance = IERC20(token).balanceOf(address(this));
261
+
262
+ if (balance > 0 && token != _rewardToken){
263
+ IERC20(token).safeApprove(_universalLiquidator, 0);
264
+ IERC20(token).safeApprove(_universalLiquidator, balance);
265
+ IUniversalLiquidator(_universalLiquidator).swap(token, _rewardToken, balance, 1, address(this));
266
+ }
267
+ }
268
+
269
+ uint256 rewardBalance = IERC20(_rewardToken).balanceOf(address(this));
270
+ if (rewardBalance < 1e14) {
271
+ return;
272
+ }
273
+ _notifyProfitInRewardToken(_rewardToken, rewardBalance);
274
+ uint256 remainingRewardBalance = IERC20(_rewardToken).balanceOf(address(this));
275
+
276
+ if (remainingRewardBalance == 0) {
277
+ return;
278
+ }
279
+
280
+ if (_underlying != _rewardToken) {
281
+ IERC20(_rewardToken).safeApprove(_universalLiquidator, 0);
282
+ IERC20(_rewardToken).safeApprove(_universalLiquidator, remainingRewardBalance);
283
+ IUniversalLiquidator(_universalLiquidator).swap(_rewardToken, _underlying, remainingRewardBalance, 1, address(this));
284
+ }
285
+ }
286
+
287
+ /**
288
+ * Returns the current balance.
289
+ */
290
+ function investedUnderlyingBalance() public view returns (uint256) {
291
+ uint256 balance = IERC20(underlying()).balanceOf(address(this));
292
+ return balance.add(storedBalance()).sub(pendingFee());
293
+ }
294
+
295
+ function _supply(uint256 amountUnderlying) internal {
296
+ if (amountUnderlying == 0){
297
+ return;
298
+ }
299
+ address _underlying = underlying();
300
+ address _cToken = cToken();
301
+ uint256 supplyCap = IComptroller(comptroller()).supplyCaps(_cToken);
302
+ if (supplyCap == 0) {
303
+ supplyCap = type(uint256).max;
304
+ }
305
+ uint256 totalSupply = IERC20(_cToken).totalSupply().mul(CTokenInterface(_cToken).exchangeRateCurrent()).div(1e18);
306
+ if (totalSupply >= supplyCap) {
307
+ return;
308
+ } else if (supplyCap.sub(totalSupply) <= amountUnderlying) {
309
+ amountUnderlying = supplyCap.sub(totalSupply).sub(2);
310
+ }
311
+ IERC20(_underlying).safeApprove(_cToken, 0);
312
+ IERC20(_underlying).safeApprove(_cToken, amountUnderlying);
313
+ CTokenInterface(_cToken).mint(amountUnderlying);
314
+ }
315
+
316
+ function _borrow(uint256 amountUnderlying) internal {
317
+ if (amountUnderlying == 0){
318
+ return;
319
+ }
320
+ CTokenInterface(cToken()).borrow(amountUnderlying);
321
+ }
322
+
323
+ function _redeem(uint256 amountUnderlying) internal {
324
+ if (amountUnderlying == 0){
325
+ return;
326
+ }
327
+ address _cToken = cToken();
328
+ uint256 exchange = CTokenInterface(_cToken).exchangeRateCurrent();
329
+ if (amountUnderlying.mul(1e18) < exchange){
330
+ CTokenInterface(_cToken).redeem(1);
331
+ return;
332
+ }
333
+ CTokenInterface(_cToken).redeemUnderlying(amountUnderlying);
334
+ }
335
+
336
+ function _repay(uint256 amountUnderlying) internal {
337
+ if (amountUnderlying == 0){
338
+ return;
339
+ }
340
+ address _underlying = underlying();
341
+ address _cToken = cToken();
342
+ IERC20(_underlying).safeApprove(_cToken, 0);
343
+ IERC20(_underlying).safeApprove(_cToken, amountUnderlying);
344
+ CTokenInterface(_cToken).repayBorrow(amountUnderlying);
345
+ }
346
+
347
+ function _redeemMaximum() internal {
348
+ address _cToken = cToken();
349
+ uint256 available = CTokenInterface(_cToken).getCash();
350
+ // amount we supplied
351
+ uint256 supplied = CTokenInterface(_cToken).balanceOfUnderlying(address(this));
352
+ // amount we borrowed
353
+ uint256 borrowed = CTokenInterface(_cToken).borrowBalanceCurrent(address(this));
354
+ uint256 balance = supplied.sub(borrowed).sub(pendingFee());
355
+
356
+ _redeemWithFlashloan(Math.min(balance, available), 0);
357
+ available = CTokenInterface(_cToken).getCash();
358
+ supplied = CTokenInterface(_cToken).balanceOfUnderlying(address(this));
359
+ if (Math.min(supplied, available) > pendingFee()) {
360
+ _redeem(Math.min(supplied, available).sub(pendingFee().add(1)));
361
+ }
362
+ }
363
+
364
+ function _depositWithFlashloan() internal {
365
+ address _cToken = cToken();
366
+ uint256 _denom = factorDenominator();
367
+ uint256 _borrowNum = borrowTargetFactorNumerator();
368
+ // amount we supplied
369
+ uint256 supplied = CTokenInterface(_cToken).balanceOfUnderlying(address(this));
370
+ // amount we borrowed
371
+ uint256 borrowed = CTokenInterface(_cToken).borrowBalanceCurrent(address(this));
372
+ uint256 balance = supplied.sub(borrowed);
373
+ uint256 borrowTarget = balance.mul(_borrowNum).div(_denom.sub(_borrowNum));
374
+
375
+ if (borrowed > borrowTarget) {
376
+ _redeemPartial(0);
377
+ borrowTarget = borrowed;
378
+ } else {
379
+ address _comptroller = comptroller();
380
+ uint256 borrowCap = IComptroller(_comptroller).borrowCaps(_cToken);
381
+ uint256 supplyCap = IComptroller(_comptroller).supplyCaps(_cToken);
382
+ if (borrowCap == 0) {
383
+ borrowCap = type(uint256).max;
384
+ }
385
+ if (supplyCap == 0) {
386
+ supplyCap = type(uint256).max;
387
+ }
388
+ uint256 totalBorrow = CTokenInterface(_cToken).totalBorrows();
389
+ uint256 totalSupply = IERC20(_cToken).totalSupply().mul(CTokenInterface(_cToken).exchangeRateCurrent()).div(1e18);
390
+ uint256 borrowAvail;
391
+ if (totalBorrow < borrowCap) {
392
+ borrowAvail = borrowCap.sub(totalBorrow).sub(2);
393
+ if (totalSupply < supplyCap) {
394
+ borrowAvail = Math.min(supplyCap.sub(totalSupply).sub(2), borrowAvail);
395
+ } else {
396
+ borrowAvail = 0;
397
+ }
398
+ } else {
399
+ borrowAvail = 0;
400
+ }
401
+ borrowTarget = Math.min(borrowTarget, borrowed.add(borrowAvail));
402
+ }
403
+ uint256 borrowDiff = borrowTarget.sub(borrowed);
404
+ if (borrowDiff > 0) {
405
+ address _underlying = underlying();
406
+ uint256 balancerBalance = IERC20(_underlying).balanceOf(bVault);
407
+
408
+ if (borrowDiff > balancerBalance) {
409
+ _depositNoFlash(borrowTarget);
410
+ } else {
411
+ address[] memory tokens = new address[](1);
412
+ uint256[] memory amounts = new uint256[](1);
413
+ bytes memory userData = abi.encode(0);
414
+ tokens[0] = underlying();
415
+ amounts[0] = borrowDiff;
416
+ makingFlashDeposit = true;
417
+ IBVault(bVault).flashLoan(address(this), tokens, amounts, userData);
418
+ makingFlashDeposit = false;
419
+ }
420
+ }
421
+ }
422
+
423
+ function _redeemWithFlashloan(uint256 amount, uint256 _borrowTargetFactorNumerator) internal {
424
+ address _cToken = cToken();
425
+ // amount we supplied
426
+ uint256 supplied = CTokenInterface(_cToken).balanceOfUnderlying(address(this));
427
+ // amount we borrowed
428
+ uint256 borrowed = CTokenInterface(_cToken).borrowBalanceCurrent(address(this));
429
+ uint256 newBorrowTarget;
430
+ {
431
+ uint256 oldBalance = supplied.sub(borrowed);
432
+ uint256 newBalance = oldBalance.sub(amount);
433
+ newBorrowTarget = newBalance.mul(_borrowTargetFactorNumerator).div(factorDenominator().sub(_borrowTargetFactorNumerator));
434
+ }
435
+ uint256 borrowDiff;
436
+ if (borrowed < newBorrowTarget) {
437
+ borrowDiff = 0;
438
+ } else {
439
+ borrowDiff = borrowed.sub(newBorrowTarget);
440
+ }
441
+
442
+ if (borrowDiff > 0) {
443
+ address _underlying = underlying();
444
+ uint256 balancerBalance = IERC20(_underlying).balanceOf(bVault);
445
+
446
+ if (borrowDiff > balancerBalance) {
447
+ _redeemNoFlash(amount, newBorrowTarget);
448
+ } else {
449
+ address[] memory tokens = new address[](1);
450
+ uint256[] memory amounts = new uint256[](1);
451
+ bytes memory userData = abi.encode(0);
452
+ tokens[0] = _underlying;
453
+ amounts[0] = borrowDiff;
454
+ makingFlashWithdrawal = true;
455
+ IBVault(bVault).flashLoan(address(this), tokens, amounts, userData);
456
+ makingFlashWithdrawal = false;
457
+ _redeem(amount);
458
+ }
459
+ }
460
+ }
461
+
462
+ function receiveFlashLoan(IERC20[] memory /*tokens*/, uint256[] memory amounts, uint256[] memory feeAmounts, bytes memory /*userData*/) external {
463
+ require(msg.sender == bVault);
464
+ require(!makingFlashDeposit || !makingFlashWithdrawal, "Only one can be true");
465
+ require(makingFlashDeposit || makingFlashWithdrawal, "One has to be true");
466
+ address _underlying = underlying();
467
+ uint256 toRepay = amounts[0].add(feeAmounts[0]);
468
+ if (makingFlashDeposit){
469
+ _supply(amounts[0]);
470
+ _borrow(toRepay);
471
+ } else {
472
+ address _cToken = cToken();
473
+ uint256 borrowed = CTokenInterface(_cToken).borrowBalanceCurrent(address(this));
474
+ uint256 repaying = Math.min(amounts[0], borrowed);
475
+ IERC20(_underlying).safeApprove(_cToken, 0);
476
+ IERC20(_underlying).safeApprove(_cToken, repaying);
477
+ _repay(repaying);
478
+ _redeem(toRepay);
479
+ }
480
+ IERC20(_underlying).safeTransfer(bVault, toRepay);
481
+ }
482
+
483
+ function _depositNoFlash(uint256 borrowTarget) internal {
484
+ address _underlying = underlying();
485
+ address _cToken = cToken();
486
+ uint256 borrowed = CTokenInterface(_cToken).borrowBalanceCurrent(address(this));
487
+ uint256 supplied = CTokenInterface(_cToken).balanceOfUnderlying(address(this));
488
+
489
+ while (borrowed < borrowTarget) {
490
+ uint256 wantBorrow = borrowTarget.sub(borrowed);
491
+ uint256 maxBorrow = supplied.mul(collateralFactorNumerator()).div(factorDenominator()).sub(borrowed);
492
+ _borrow(Math.min(wantBorrow, maxBorrow));
493
+ uint256 underlyingBalance = IERC20(_underlying).balanceOf(address(this));
494
+ if (underlyingBalance > 0) {
495
+ _supply(underlyingBalance);
496
+ }
497
+ //update parameters
498
+ borrowed = CTokenInterface(_cToken).borrowBalanceCurrent(address(this));
499
+ supplied = CTokenInterface(_cToken).balanceOfUnderlying(address(this));
500
+ }
501
+ }
502
+
503
+ function _redeemNoFlash(uint256 amount, uint256 newBorrowTarget) internal {
504
+ address _underlying = underlying();
505
+ address _cToken = cToken();
506
+ uint256 borrowed = CTokenInterface(_cToken).borrowBalanceCurrent(address(this));
507
+ uint256 supplied = CTokenInterface(_cToken).balanceOfUnderlying(address(this));
508
+
509
+ while (borrowed > newBorrowTarget) {
510
+ uint256 requiredCollateral = borrowed.mul(factorDenominator()).div(collateralFactorNumerator());
511
+ uint256 toRepay = borrowed.sub(newBorrowTarget);
512
+ // redeem just as much as needed to repay the loan
513
+ // supplied - requiredCollateral = max redeemable, amount + repay = needed
514
+ uint256 toRedeem = Math.min(supplied.sub(requiredCollateral), amount.add(toRepay));
515
+ _redeem(toRedeem);
516
+ // now we can repay our borrowed amount
517
+ uint256 balance = IERC20(_underlying).balanceOf(address(this));
518
+ _repay(Math.min(toRepay, balance));
519
+ // update the parameters
520
+ borrowed = CTokenInterface(_cToken).borrowBalanceCurrent(address(this));
521
+ supplied = CTokenInterface(_cToken).balanceOfUnderlying(address(this));
522
+ }
523
+ uint256 underlyingBalance = IERC20(_underlying).balanceOf(address(this));
524
+ if (underlyingBalance < amount) {
525
+ uint256 toRedeem = amount.sub(underlyingBalance);
526
+ uint256 balance = supplied.sub(borrowed);
527
+ // redeem the most we can redeem
528
+ _redeem(Math.min(toRedeem, balance));
529
+ }
530
+ }
531
+
532
+ // updating collateral factor
533
+ // note 1: one should settle the loan first before calling this
534
+ // note 2: collateralFactorDenominator is 1000, therefore, for 20%, you need 200
535
+ function _setCollateralFactorNumerator(uint256 _numerator) public onlyGovernance {
536
+ require(_numerator <= factorDenominator(), "Collateral factor cannot be this high");
537
+ require(_numerator > borrowTargetFactorNumerator(), "Collateral factor should be higher than borrow target");
538
+ setUint256(_COLLATERALFACTORNUMERATOR_SLOT, _numerator);
539
+ }
540
+
541
+ function collateralFactorNumerator() public view returns (uint256) {
542
+ return getUint256(_COLLATERALFACTORNUMERATOR_SLOT);
543
+ }
544
+
545
+ function _setFactorDenominator(uint256 _denominator) internal {
546
+ setUint256(_FACTORDENOMINATOR_SLOT, _denominator);
547
+ }
548
+
549
+ function factorDenominator() public view returns (uint256) {
550
+ return getUint256(_FACTORDENOMINATOR_SLOT);
551
+ }
552
+
553
+ function setBorrowTargetFactorNumerator(uint256 _numerator) public onlyGovernance {
554
+ require(_numerator < collateralFactorNumerator(), "Target should be lower than collateral limit");
555
+ setUint256(_BORROWTARGETFACTORNUMERATOR_SLOT, _numerator);
556
+ }
557
+
558
+ function borrowTargetFactorNumerator() public view returns (uint256) {
559
+ return getUint256(_BORROWTARGETFACTORNUMERATOR_SLOT);
560
+ }
561
+
562
+ function setFold (bool _fold) public onlyGovernance {
563
+ setBoolean(_FOLD_SLOT, _fold);
564
+ }
565
+
566
+ function fold() public view returns (bool) {
567
+ return getBoolean(_FOLD_SLOT);
568
+ }
569
+
570
+ function _setCToken (address _target) internal {
571
+ setAddress(_CTOKEN_SLOT, _target);
572
+ }
573
+
574
+ function cToken() public view returns (address) {
575
+ return getAddress(_CTOKEN_SLOT);
576
+ }
577
+
578
+ function _setComptroller (address _target) internal {
579
+ setAddress(_COMPTROLLER_SLOT, _target);
580
+ }
581
+
582
+ function comptroller() public view returns (address) {
583
+ return getAddress(_COMPTROLLER_SLOT);
584
+ }
585
+
586
+ function finalizeUpgrade() external onlyGovernance {
587
+ _finalizeUpgrade();
588
+ }
589
+
590
+ receive() external payable {}
591
+ }
@@ -0,0 +1,32 @@
1
+ //SPDX-License-Identifier: Unlicense
2
+ pragma solidity 0.8.26;
3
+
4
+ import "./VenusFoldStrategy.sol";
5
+
6
+ contract VenusFoldStrategyMainnet_ARB is VenusFoldStrategy {
7
+
8
+ constructor() {}
9
+
10
+ function initializeStrategy(
11
+ address _storage,
12
+ address _vault
13
+ ) public initializer {
14
+ address underlying = address(0x912CE59144191C1204E64559FE8253a0e49E6548);
15
+ address cToken = address(0xAeB0FEd69354f34831fe1D16475D9A83ddaCaDA6);
16
+ address comptroller = address(0x317c1A5739F39046E20b08ac9BeEa3f10fD43326);
17
+ address xvs = address(0xc1Eb7689147C81aC840d4FF0D298489fc7986d52);
18
+ VenusFoldStrategy.initializeBaseStrategy(
19
+ _storage,
20
+ underlying,
21
+ _vault,
22
+ cToken,
23
+ comptroller,
24
+ xvs,
25
+ 150,
26
+ 549,
27
+ 1000,
28
+ true
29
+ );
30
+ rewardTokens = [xvs];
31
+ }
32
+ }
@@ -0,0 +1,32 @@
1
+ //SPDX-License-Identifier: Unlicense
2
+ pragma solidity 0.8.26;
3
+
4
+ import "./VenusFoldStrategy.sol";
5
+
6
+ contract VenusFoldStrategyMainnet_ETH_core is VenusFoldStrategy {
7
+
8
+ constructor() {}
9
+
10
+ function initializeStrategy(
11
+ address _storage,
12
+ address _vault
13
+ ) public initializer {
14
+ address underlying = address(0x82aF49447D8a07e3bd95BD0d56f35241523fBab1);
15
+ address cToken = address(0x68a34332983f4Bf866768DD6D6E638b02eF5e1f0);
16
+ address comptroller = address(0x317c1A5739F39046E20b08ac9BeEa3f10fD43326);
17
+ address xvs = address(0xc1Eb7689147C81aC840d4FF0D298489fc7986d52);
18
+ VenusFoldStrategy.initializeBaseStrategy(
19
+ _storage,
20
+ underlying,
21
+ _vault,
22
+ cToken,
23
+ comptroller,
24
+ xvs,
25
+ 730,
26
+ 749,
27
+ 1000,
28
+ true
29
+ );
30
+ rewardTokens = [xvs];
31
+ }
32
+ }
@@ -0,0 +1,32 @@
1
+ //SPDX-License-Identifier: Unlicense
2
+ pragma solidity 0.8.26;
3
+
4
+ import "./VenusFoldStrategy.sol";
5
+
6
+ contract VenusFoldStrategyMainnet_ETH_lsd is VenusFoldStrategy {
7
+
8
+ constructor() {}
9
+
10
+ function initializeStrategy(
11
+ address _storage,
12
+ address _vault
13
+ ) public initializer {
14
+ address underlying = address(0x82aF49447D8a07e3bd95BD0d56f35241523fBab1);
15
+ address cToken = address(0x39D6d13Ea59548637104E40e729E4aABE27FE106);
16
+ address comptroller = address(0x52bAB1aF7Ff770551BD05b9FC2329a0Bf5E23F16);
17
+ address xvs = address(0xc1Eb7689147C81aC840d4FF0D298489fc7986d52);
18
+ VenusFoldStrategy.initializeBaseStrategy(
19
+ _storage,
20
+ underlying,
21
+ _vault,
22
+ cToken,
23
+ comptroller,
24
+ xvs,
25
+ 0,
26
+ 1,
27
+ 1000,
28
+ false
29
+ );
30
+ rewardTokens = [xvs];
31
+ }
32
+ }