@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,465 @@
1
+ // SPDX-License-Identifier: Unlicense
2
+ pragma solidity 0.8.26;
3
+
4
+ import "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol";
5
+ import "@openzeppelin/contracts-upgradeable/utils/math/SafeMathUpgradeable.sol";
6
+ import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
7
+ import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
8
+ import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
9
+ import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
10
+ import "./interface/IGMXStrategy.sol";
11
+ import "./interface/IVault.sol";
12
+ import "./interface/IController.sol";
13
+ import "./interface/IUpgradeSource.sol";
14
+ import "./inheritance/ControllableInit.sol";
15
+ import "./VaultStorage.sol";
16
+ import "./interface/IERC4626.sol";
17
+
18
+ contract VaultV1GMX is ERC20Upgradeable, IUpgradeSource, ControllableInit, VaultStorage {
19
+ using SafeERC20Upgradeable for IERC20Upgradeable;
20
+ using AddressUpgradeable for address;
21
+ using SafeMathUpgradeable for uint256;
22
+
23
+ event Invest(uint256 amount);
24
+ event StrategyAnnounced(address newStrategy, uint256 time);
25
+ event StrategyChanged(address newStrategy, address oldStrategy);
26
+
27
+ event DepositStarted(address sender, address receiver, uint256 amountIn);
28
+ event WithdrawalStarted(address sender, address receiver, uint256 amountIn);
29
+
30
+ event DepositFailed(address sender, address receiver, uint256 amountIn);
31
+ event WithdrawalFailed(address sender, address receiver, uint256 amountIn);
32
+
33
+ struct PendingAction {
34
+ bool pending;
35
+ address sender;
36
+ address receiver;
37
+ uint256 amountIn;
38
+ }
39
+
40
+ mapping (bytes32 => PendingAction) public pendingDeposits;
41
+ mapping (bytes32 => PendingAction) public pendingWithdrawals;
42
+
43
+ uint256 internal pendingDepositAmount;
44
+ uint256 internal pendingWithdrawalAmount;
45
+
46
+ constructor() {
47
+ }
48
+
49
+ modifier onlyStrategy() {
50
+ require(msg.sender == strategy(), "Not strategy");
51
+ _;
52
+ }
53
+
54
+ // the function is name differently to not cause inheritance clash in truffle and allows tests
55
+ function initializeVault(
56
+ address _storage,
57
+ address _underlying,
58
+ uint256 _toInvestNumerator,
59
+ uint256 _toInvestDenominator
60
+ ) public initializer {
61
+ require(_toInvestNumerator <= _toInvestDenominator, "cannot invest more than 100%");
62
+ require(_toInvestDenominator != 0, "cannot divide by 0");
63
+
64
+ __ERC20_init(
65
+ string(abi.encodePacked("FARM_", ERC20Upgradeable(_underlying).symbol())),
66
+ string(abi.encodePacked("f", ERC20Upgradeable(_underlying).symbol()))
67
+ );
68
+ _setDecimals(ERC20Upgradeable(_underlying).decimals());
69
+
70
+ ControllableInit.initialize(
71
+ _storage
72
+ );
73
+
74
+ uint256 underlyingUnit = 10 ** uint256(ERC20Upgradeable(address(_underlying)).decimals());
75
+ VaultStorage.initialize(
76
+ _underlying,
77
+ _toInvestNumerator,
78
+ _toInvestDenominator,
79
+ underlyingUnit
80
+ );
81
+ }
82
+
83
+ function decimals() public view override returns(uint8) {
84
+ return uint8(_decimals());
85
+ }
86
+
87
+ function strategy() public view returns(address) {
88
+ return _strategy();
89
+ }
90
+
91
+ function underlying() public view returns(address) {
92
+ return _underlying();
93
+ }
94
+
95
+ function underlyingUnit() public view returns(uint256) {
96
+ return _underlyingUnit();
97
+ }
98
+
99
+ function vaultFractionToInvestNumerator() public view returns(uint256) {
100
+ return _vaultFractionToInvestNumerator();
101
+ }
102
+
103
+ function vaultFractionToInvestDenominator() public view returns(uint256) {
104
+ return _vaultFractionToInvestDenominator();
105
+ }
106
+
107
+ function nextImplementation() public view returns(address) {
108
+ return _nextImplementation();
109
+ }
110
+
111
+ function nextImplementationTimestamp() public view returns(uint256) {
112
+ return _nextImplementationTimestamp();
113
+ }
114
+
115
+ function nextImplementationDelay() public view returns (uint256) {
116
+ return IController(controller()).nextImplementationDelay();
117
+ }
118
+
119
+ modifier whenStrategyDefined() {
120
+ require(address(strategy()) != address(0), "Strategy must be defined");
121
+ _;
122
+ }
123
+
124
+ // Only smart contracts will be affected by this modifier
125
+ modifier defense() {
126
+ require(
127
+ (msg.sender == tx.origin) || // If it is a normal user and not smart contract,
128
+ // then the requirement will pass
129
+ !IController(controller()).greyList(msg.sender), // If it is a smart contract, then
130
+ "This smart contract has been grey listed" // make sure that it is not on our greyList.
131
+ );
132
+ _;
133
+ }
134
+
135
+ /**
136
+ * Chooses the best strategy and re-invests. If the strategy did not change, it just calls
137
+ * doHardWork on the current strategy. Call this through controller to claim hard rewards.
138
+ */
139
+ function doHardWork() whenStrategyDefined onlyControllerOrGovernance external {
140
+ // ensure that new funds are invested too
141
+ invest();
142
+ IGMXStrategy(strategy()).doHardWork();
143
+ }
144
+
145
+ /*
146
+ * Returns the cash balance across all users in this contract.
147
+ */
148
+ function underlyingBalanceInVault() view public returns (uint256) {
149
+ return IERC20Upgradeable(underlying()).balanceOf(address(this));
150
+ }
151
+
152
+ /* Returns the current underlying (e.g., DAI's) balance together with
153
+ * the invested amount (if DAI is invested elsewhere by the strategy).
154
+ */
155
+ function underlyingBalanceWithInvestment() view public returns (uint256) {
156
+ if (address(strategy()) == address(0)) {
157
+ // initial state, when not set
158
+ return underlyingBalanceInVault();
159
+ }
160
+ return underlyingBalanceInVault().add(IGMXStrategy(strategy()).investedUnderlyingBalance()).sub(pendingDepositAmount);
161
+ }
162
+
163
+ function getPricePerFullShare() public view returns (uint256) {
164
+ return totalSupply() == 0
165
+ ? underlyingUnit()
166
+ : underlyingUnit().mul(underlyingBalanceWithInvestment()).div(totalSupply().add(pendingWithdrawalAmount));
167
+ }
168
+
169
+ /* get the user's share (in underlying)
170
+ */
171
+ function underlyingBalanceWithInvestmentForHolder(address holder) view external returns (uint256) {
172
+ if (totalSupply() == 0) {
173
+ return 0;
174
+ }
175
+ return underlyingBalanceWithInvestment()
176
+ .mul(balanceOf(holder))
177
+ .div(totalSupply().add(pendingWithdrawalAmount));
178
+ }
179
+
180
+ function nextStrategy() public view returns (address) {
181
+ return _nextStrategy();
182
+ }
183
+
184
+ function nextStrategyTimestamp() public view returns (uint256) {
185
+ return _nextStrategyTimestamp();
186
+ }
187
+
188
+ function canUpdateStrategy(address _strategy) public view returns (bool) {
189
+ bool isStrategyNotSetYet = strategy() == address(0);
190
+ bool hasTimelockPassed = block.timestamp > nextStrategyTimestamp() && nextStrategyTimestamp() != 0;
191
+ return isStrategyNotSetYet || (_strategy == nextStrategy() && hasTimelockPassed);
192
+ }
193
+
194
+ /**
195
+ * Indicates that the strategy update will happen in the future
196
+ */
197
+ function announceStrategyUpdate(address _strategy) public onlyControllerOrGovernance {
198
+ // records a new timestamp
199
+ uint256 when = block.timestamp.add(nextImplementationDelay());
200
+ _setNextStrategyTimestamp(when);
201
+ _setNextStrategy(_strategy);
202
+ emit StrategyAnnounced(_strategy, when);
203
+ }
204
+
205
+ /**
206
+ * Finalizes (or cancels) the strategy update by resetting the data
207
+ */
208
+ function finalizeStrategyUpdate() public onlyControllerOrGovernance {
209
+ _setNextStrategyTimestamp(0);
210
+ _setNextStrategy(address(0));
211
+ }
212
+
213
+ function setStrategy(address _strategy) public onlyControllerOrGovernance {
214
+ require(canUpdateStrategy(_strategy),
215
+ "The strategy exists and switch timelock did not elapse yet");
216
+ require(_strategy != address(0), "new _strategy cannot be empty");
217
+ require(IGMXStrategy(_strategy).underlying() == address(underlying()), "Vault underlying must match Strategy underlying");
218
+ require(IGMXStrategy(_strategy).vault() == address(this), "the strategy does not belong to this vault");
219
+
220
+ emit StrategyChanged(_strategy, strategy());
221
+ if (address(_strategy) != address(strategy())) {
222
+ if (address(strategy()) != address(0)) { // if the original strategy (no underscore) is defined
223
+ require(underlyingBalanceWithInvestment() == underlyingBalanceInVault(), "Withdraw to vault first");
224
+ IERC20Upgradeable(underlying()).safeApprove(address(strategy()), 0);
225
+ }
226
+ _setStrategy(_strategy);
227
+ IERC20Upgradeable(underlying()).safeApprove(address(strategy()), 0);
228
+ IERC20Upgradeable(underlying()).safeApprove(address(strategy()), type(uint256).max);
229
+ }
230
+ finalizeStrategyUpdate();
231
+ }
232
+
233
+ function setVaultFractionToInvest(uint256 numerator, uint256 denominator) external onlyGovernance {
234
+ require(denominator > 0, "denominator must be greater than 0");
235
+ require(numerator <= denominator, "denominator must be greater than or equal to the numerator");
236
+ _setVaultFractionToInvestNumerator(numerator);
237
+ _setVaultFractionToInvestDenominator(denominator);
238
+ }
239
+
240
+ function availableToInvestOut() public view returns (uint256) {
241
+ uint256 wantInvestInTotal = underlyingBalanceWithInvestment()
242
+ .mul(vaultFractionToInvestNumerator())
243
+ .div(vaultFractionToInvestDenominator());
244
+ uint256 alreadyInvested = IGMXStrategy(strategy()).investedUnderlyingBalance();
245
+ if (alreadyInvested >= wantInvestInTotal) {
246
+ return 0;
247
+ } else {
248
+ uint256 remainingToInvest = wantInvestInTotal.sub(alreadyInvested);
249
+ return remainingToInvest <= underlyingBalanceInVault()
250
+ // TODO: we think that the "else" branch of the ternary operation is not
251
+ // going to get hit
252
+ ? remainingToInvest : underlyingBalanceInVault();
253
+ }
254
+ }
255
+
256
+ function invest() internal whenStrategyDefined {
257
+ uint256 availableAmount = availableToInvestOut();
258
+ if (availableAmount > 0) {
259
+ IERC20Upgradeable(underlying()).safeTransfer(address(strategy()), availableAmount);
260
+ emit Invest(availableAmount);
261
+ }
262
+ }
263
+
264
+ /*
265
+ * Allows for depositing the underlying asset in exchange for shares.
266
+ * Approval is assumed.
267
+ */
268
+ function deposit(uint256 amount) external nonReentrant defense returns (uint256 minted) {
269
+ minted = _deposit(amount, msg.sender, msg.sender);
270
+ }
271
+
272
+ /*
273
+ * Allows for depositing the underlying asset in exchange for shares
274
+ * assigned to the holder.
275
+ * This facilitates depositing for someone else (using DepositHelper)
276
+ */
277
+ function depositFor(uint256 amount, address holder) public nonReentrant defense returns (uint256 minted) {
278
+ minted = _deposit(amount, msg.sender, holder);
279
+ }
280
+
281
+ function withdraw(uint256 shares) external nonReentrant defense returns (uint256 amtUnderlying) {
282
+ amtUnderlying = _withdraw(shares, msg.sender, msg.sender);
283
+ }
284
+
285
+ function withdrawAll() public onlyControllerOrGovernance whenStrategyDefined {
286
+ bytes32 withdrawalHash = IGMXStrategy(strategy()).withdrawAllToVault();
287
+
288
+ pendingWithdrawals[withdrawalHash] = PendingAction(
289
+ true,
290
+ address(this),
291
+ address(this),
292
+ 0
293
+ );
294
+ }
295
+
296
+ function _deposit(uint256 amount, address sender, address beneficiary) internal returns (uint256) {
297
+ require(amount > 0, "Cannot deposit 0");
298
+ require(beneficiary != address(0), "holder must be defined");
299
+
300
+ if (address(strategy()) != address(0)) {
301
+ require(IGMXStrategy(strategy()).depositArbCheck(), "Too much arb");
302
+ }
303
+
304
+ IERC20Upgradeable(underlying()).safeTransferFrom(sender, address(this), amount);
305
+
306
+ invest();
307
+ bytes32 depositHash = IGMXStrategy(strategy()).doHardWork();
308
+
309
+ require(!pendingDeposits[depositHash].pending, "Deposit pending");
310
+
311
+ pendingDeposits[depositHash] = PendingAction(
312
+ true,
313
+ sender,
314
+ beneficiary,
315
+ amount
316
+ );
317
+ pendingDepositAmount += amount;
318
+
319
+ emit DepositStarted(sender, beneficiary, amount);
320
+
321
+ return 0;
322
+ }
323
+
324
+ function _finalizeDeposit(bool success, bytes32 depositHash, uint256 correctedAmount) internal {
325
+ PendingAction memory pendingDeposit = pendingDeposits[depositHash];
326
+ require(pendingDeposit.pending, "No pending deposit");
327
+
328
+ if (success) {
329
+ uint256 toMint = totalSupply() == 0
330
+ ? correctedAmount
331
+ : correctedAmount.mul(totalSupply().add(pendingWithdrawalAmount)).div(underlyingBalanceWithInvestment());
332
+ _mint(pendingDeposit.receiver, toMint);
333
+
334
+ // update the contribution amount for the beneficiary
335
+ emit IERC4626.Deposit(pendingDeposit.sender, pendingDeposit.receiver, pendingDeposit.amountIn, toMint);
336
+ } else {
337
+ IERC20Upgradeable(underlying()).safeTransfer(pendingDeposit.sender, pendingDeposit.amountIn);
338
+ emit DepositFailed(pendingDeposit.sender, pendingDeposit.receiver, pendingDeposit.amountIn);
339
+ }
340
+
341
+ pendingDepositAmount -= pendingDeposit.amountIn;
342
+ pendingDeposits[depositHash] = PendingAction(
343
+ false,
344
+ address(0),
345
+ address(0),
346
+ 0
347
+ );
348
+ }
349
+
350
+ function finalizeDeposit(bool success, bytes32 depositHash, uint256 correctedAmount) external onlyStrategy nonReentrant {
351
+ _finalizeDeposit(success, depositHash, correctedAmount);
352
+ }
353
+
354
+ function _withdraw(uint256 numberOfShares, address receiver, address owner) internal returns (uint256) {
355
+ require(totalSupply() > 0, "Vault has no shares");
356
+ require(numberOfShares > 0, "numberOfShares must be greater than 0");
357
+ uint256 totalSupply = totalSupply();
358
+
359
+ address sender = msg.sender;
360
+ if (sender != owner) {
361
+ uint256 currentAllowance = allowance(owner, sender);
362
+ if (currentAllowance != type(uint256).max) {
363
+ require(currentAllowance >= numberOfShares, "ERC20: transfer amount exceeds allowance");
364
+ _approve(owner, sender, currentAllowance - numberOfShares);
365
+ }
366
+ }
367
+ _burn(owner, numberOfShares);
368
+
369
+ uint256 underlyingAmountToWithdraw = underlyingBalanceWithInvestment()
370
+ .mul(numberOfShares)
371
+ .div(totalSupply);
372
+
373
+ if (underlyingAmountToWithdraw <= underlyingBalanceInVault()) {
374
+ IERC20Upgradeable(underlying()).safeTransfer(receiver, underlyingAmountToWithdraw);
375
+
376
+ emit IERC4626.Withdraw(sender, receiver, owner, underlyingAmountToWithdraw, numberOfShares);
377
+ return underlyingAmountToWithdraw;
378
+ }
379
+
380
+ bytes32 withdrawalHash;
381
+ if (numberOfShares == totalSupply) {
382
+ withdrawalHash = IGMXStrategy(strategy()).withdrawAllToVault();
383
+ } else {
384
+ withdrawalHash = IGMXStrategy(strategy()).withdrawToVault(underlyingAmountToWithdraw);
385
+ }
386
+
387
+ require(!pendingWithdrawals[withdrawalHash].pending, "Withdrawal pending");
388
+
389
+ if (withdrawalHash == bytes32(0)) {
390
+ pendingWithdrawals[withdrawalHash] = PendingAction(
391
+ true,
392
+ owner,
393
+ receiver,
394
+ numberOfShares
395
+ );
396
+ pendingWithdrawalAmount += numberOfShares;
397
+ _finalizeWithdrawal(true, withdrawalHash, underlyingAmountToWithdraw);
398
+ emit IERC4626.Withdraw(sender, receiver, owner, underlyingAmountToWithdraw, numberOfShares);
399
+ return underlyingAmountToWithdraw;
400
+ }
401
+
402
+ pendingWithdrawals[withdrawalHash] = PendingAction(
403
+ true,
404
+ owner,
405
+ receiver,
406
+ numberOfShares
407
+ );
408
+ pendingWithdrawalAmount += numberOfShares;
409
+
410
+ emit WithdrawalStarted(owner, receiver, numberOfShares);
411
+
412
+ return 0;
413
+ }
414
+
415
+ function _finalizeWithdrawal(bool success, bytes32 withdrawalHash, uint256 amountReceived) internal {
416
+ PendingAction memory pendingWithdrawal = pendingWithdrawals[withdrawalHash];
417
+ require(pendingWithdrawal.pending, "No pending withdrawal");
418
+
419
+ if (pendingWithdrawal.amountIn > 0) {
420
+ if (success) {
421
+ IERC20Upgradeable(underlying()).safeTransfer(pendingWithdrawal.receiver, amountReceived);
422
+
423
+ // update the withdrawal amount for the holder
424
+ emit IERC4626.Withdraw(pendingWithdrawal.sender, pendingWithdrawal.receiver, pendingWithdrawal.sender, amountReceived, pendingWithdrawal.amountIn);
425
+ } else {
426
+ _mint(pendingWithdrawal.sender, pendingWithdrawal.amountIn);
427
+ emit WithdrawalFailed(pendingWithdrawal.sender, pendingWithdrawal.receiver, pendingWithdrawal.amountIn);
428
+ }
429
+ }
430
+
431
+ pendingWithdrawalAmount -= pendingWithdrawal.amountIn;
432
+ pendingWithdrawals[withdrawalHash] = PendingAction(
433
+ false,
434
+ address(0),
435
+ address(0),
436
+ 0
437
+ );
438
+ }
439
+
440
+ function finalizeWithdrawal(bool success, bytes32 withdrawalHash, uint256 amountReceived) external onlyStrategy nonReentrant {
441
+ _finalizeWithdrawal(success, withdrawalHash, amountReceived);
442
+ }
443
+
444
+ /**
445
+ * Schedules an upgrade for this vault's proxy.
446
+ */
447
+ function scheduleUpgrade(address impl) public onlyGovernance {
448
+ _setNextImplementation(impl);
449
+ _setNextImplementationTimestamp(block.timestamp.add(nextImplementationDelay()));
450
+ }
451
+
452
+ function shouldUpgrade() external view override returns (bool, address) {
453
+ return (
454
+ nextImplementationTimestamp() != 0
455
+ && block.timestamp > nextImplementationTimestamp()
456
+ && nextImplementation() != address(0),
457
+ nextImplementation()
458
+ );
459
+ }
460
+
461
+ function finalizeUpgrade() external override onlyGovernance {
462
+ _setNextImplementation(address(0));
463
+ _setNextImplementationTimestamp(0);
464
+ }
465
+ }
@@ -0,0 +1,111 @@
1
+ // SPDX-License-Identifier: Unlicense
2
+ pragma solidity 0.8.26;
3
+
4
+ import "./interface/IERC4626.sol";
5
+ import "./VaultV1.sol";
6
+
7
+ contract VaultV2 is IERC4626, VaultV1 {
8
+
9
+ /// By default, the constant `10` is a uint8. This implicitly converts it to `uint256`
10
+ uint256 public constant TEN = 10;
11
+
12
+ function asset() public view override returns (address) {
13
+ return underlying();
14
+ }
15
+
16
+ function totalAssets() public view override returns (uint256) {
17
+ return underlyingBalanceWithInvestment();
18
+ }
19
+
20
+ function assetsPerShare() public view override returns (uint256) {
21
+ return convertToAssets(TEN ** decimals());
22
+ }
23
+
24
+ function assetsOf(address _depositor) public view override returns (uint256) {
25
+ return totalAssets() * balanceOf(_depositor) / totalSupply();
26
+ }
27
+
28
+ function maxDeposit(address /*caller*/) public pure override returns (uint256) {
29
+ return type(uint256).max;
30
+ }
31
+
32
+ function previewDeposit(uint256 _assets) public view override returns (uint256) {
33
+ return convertToShares(_assets);
34
+ }
35
+
36
+ function deposit(uint256 _assets, address _receiver) public override nonReentrant defense returns (uint256) {
37
+ uint256 shares = _deposit(_assets, msg.sender, _receiver);
38
+ return shares;
39
+ }
40
+
41
+ function maxMint(address /*caller*/) public pure override returns (uint256) {
42
+ return type(uint256).max;
43
+ }
44
+
45
+ function previewMint(uint256 _shares) public view override returns (uint256) {
46
+ return convertToAssets(_shares);
47
+ }
48
+
49
+ function mint(uint256 _shares, address _receiver) public override nonReentrant defense returns (uint256) {
50
+ uint assets = convertToAssets(_shares);
51
+ _deposit(assets, msg.sender, _receiver);
52
+ return assets;
53
+ }
54
+
55
+ function maxWithdraw(address _caller) public view override returns (uint256) {
56
+ return assetsOf(_caller);
57
+ }
58
+
59
+ function previewWithdraw(uint256 _assets) public view override returns (uint256) {
60
+ return convertToShares(_assets);
61
+ }
62
+
63
+ function withdraw(
64
+ uint256 _assets,
65
+ address _receiver,
66
+ address _owner
67
+ )
68
+ public override
69
+ nonReentrant
70
+ defense
71
+ returns (uint256) {
72
+ uint256 shares = convertToShares(_assets);
73
+ _withdraw(shares, _receiver, _owner);
74
+ return shares;
75
+ }
76
+
77
+ function maxRedeem(address _caller) public view override returns (uint256) {
78
+ return balanceOf(_caller);
79
+ }
80
+
81
+ function previewRedeem(uint256 _shares) public view override returns (uint256) {
82
+ return convertToAssets(_shares);
83
+ }
84
+
85
+ function redeem(
86
+ uint256 _shares,
87
+ address _receiver,
88
+ address _owner
89
+ )
90
+ public override
91
+ nonReentrant
92
+ defense
93
+ returns (uint256) {
94
+ uint256 assets = _withdraw(_shares, _receiver, _owner);
95
+ return assets;
96
+ }
97
+
98
+ // ========================= Conversion Functions =========================
99
+
100
+ function convertToAssets(uint256 _shares) public view returns (uint256) {
101
+ return totalAssets() == 0 || totalSupply() == 0
102
+ ? _shares * (TEN ** ERC20Upgradeable(underlying()).decimals()) / (TEN ** decimals())
103
+ : _shares * totalAssets() / totalSupply();
104
+ }
105
+
106
+ function convertToShares(uint256 _assets) public view returns (uint256) {
107
+ return totalAssets() == 0 || totalSupply() == 0
108
+ ? _assets * (TEN ** decimals()) / (TEN ** ERC20Upgradeable(underlying()).decimals())
109
+ : _assets * totalSupply() / totalAssets();
110
+ }
111
+ }
@@ -0,0 +1,111 @@
1
+ // SPDX-License-Identifier: Unlicense
2
+ pragma solidity 0.8.26;
3
+
4
+ import "./interface/IERC4626.sol";
5
+ import "./VaultV1GMX.sol";
6
+
7
+ contract VaultV2GMX is IERC4626, VaultV1GMX {
8
+
9
+ /// By default, the constant `10` is a uint8. This implicitly converts it to `uint256`
10
+ uint256 public constant TEN = 10;
11
+
12
+ function asset() public view override returns (address) {
13
+ return underlying();
14
+ }
15
+
16
+ function totalAssets() public view override returns (uint256) {
17
+ return underlyingBalanceWithInvestment();
18
+ }
19
+
20
+ function assetsPerShare() public view override returns (uint256) {
21
+ return convertToAssets(TEN ** decimals());
22
+ }
23
+
24
+ function assetsOf(address _depositor) public view override returns (uint256) {
25
+ return totalAssets() * balanceOf(_depositor) / totalSupply();
26
+ }
27
+
28
+ function maxDeposit(address /*caller*/) public view override returns (uint256) {
29
+ return type(uint256).max;
30
+ }
31
+
32
+ function previewDeposit(uint256 _assets) public view override returns (uint256) {
33
+ return convertToShares(_assets);
34
+ }
35
+
36
+ function deposit(uint256 _assets, address _receiver) public override nonReentrant defense returns (uint256) {
37
+ uint256 shares = _deposit(_assets, msg.sender, _receiver);
38
+ return shares;
39
+ }
40
+
41
+ function maxMint(address /*caller*/) public view override returns (uint256) {
42
+ return type(uint256).max;
43
+ }
44
+
45
+ function previewMint(uint256 _shares) public view override returns (uint256) {
46
+ return convertToAssets(_shares);
47
+ }
48
+
49
+ function mint(uint256 _shares, address _receiver) public override nonReentrant defense returns (uint256) {
50
+ uint assets = convertToAssets(_shares);
51
+ _deposit(assets, msg.sender, _receiver);
52
+ return assets;
53
+ }
54
+
55
+ function maxWithdraw(address _caller) public view override returns (uint256) {
56
+ return assetsOf(_caller);
57
+ }
58
+
59
+ function previewWithdraw(uint256 _assets) public view override returns (uint256) {
60
+ return convertToShares(_assets);
61
+ }
62
+
63
+ function withdraw(
64
+ uint256 _assets,
65
+ address _receiver,
66
+ address _owner
67
+ )
68
+ public override
69
+ nonReentrant
70
+ defense
71
+ returns (uint256) {
72
+ uint256 shares = convertToShares(_assets);
73
+ _withdraw(shares, _receiver, _owner);
74
+ return shares;
75
+ }
76
+
77
+ function maxRedeem(address _caller) public view override returns (uint256) {
78
+ return balanceOf(_caller);
79
+ }
80
+
81
+ function previewRedeem(uint256 _shares) public view override returns (uint256) {
82
+ return convertToAssets(_shares);
83
+ }
84
+
85
+ function redeem(
86
+ uint256 _shares,
87
+ address _receiver,
88
+ address _owner
89
+ )
90
+ public override
91
+ nonReentrant
92
+ defense
93
+ returns (uint256) {
94
+ uint256 assets = _withdraw(_shares, _receiver, _owner);
95
+ return assets;
96
+ }
97
+
98
+ // ========================= Conversion Functions =========================
99
+
100
+ function convertToAssets(uint256 _shares) public view returns (uint256) {
101
+ return totalAssets() == 0 || totalSupply() == 0
102
+ ? _shares * (TEN ** ERC20Upgradeable(underlying()).decimals()) / (TEN ** decimals())
103
+ : _shares * totalAssets() / totalSupply();
104
+ }
105
+
106
+ function convertToShares(uint256 _assets) public view returns (uint256) {
107
+ return totalAssets() == 0 || totalSupply() == 0
108
+ ? _assets * (TEN ** decimals()) / (TEN ** ERC20Upgradeable(underlying()).decimals())
109
+ : _assets * totalSupply() / totalAssets();
110
+ }
111
+ }