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

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 +39 -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,367 @@
1
+ // SPDX-License-Identifier: Unlicense
2
+ pragma solidity 0.8.26;
3
+
4
+ import "./inheritance/Controllable.sol";
5
+ import "./interface/IController.sol";
6
+
7
+ import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
8
+ import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
9
+ import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
10
+ import "@openzeppelin/contracts/utils/math/SafeMath.sol";
11
+ import "@openzeppelin/contracts/utils/math/Math.sol";
12
+ import "@openzeppelin/contracts/utils/Address.sol";
13
+ import "@openzeppelin/contracts/access/Ownable.sol";
14
+
15
+ abstract contract IRewardDistributionRecipient is Ownable {
16
+
17
+ mapping (address => bool) public rewardDistribution;
18
+
19
+ constructor(address[] memory _rewardDistributions) {
20
+ // multisig on Arbitrum
21
+ rewardDistribution[0xf3D1A027E858976634F81B7c41B09A05A46EdA21] = true;
22
+ // NotifyHelper
23
+ rewardDistribution[0xC0cE53f755feAe93Fd219b2Cd0F58a4Fd0d535Dd] = true;
24
+
25
+ for(uint256 i = 0; i < _rewardDistributions.length; i++) {
26
+ rewardDistribution[_rewardDistributions[i]] = true;
27
+ }
28
+ }
29
+
30
+ function notifyTargetRewardAmount(address rewardToken, uint256 reward) external virtual;
31
+ function notifyRewardAmount(uint256 reward) external virtual;
32
+
33
+ modifier onlyRewardDistribution() {
34
+ require(rewardDistribution[_msgSender()], "Caller is not reward distribution");
35
+ _;
36
+ }
37
+
38
+ function setRewardDistribution(address[] calldata _newRewardDistribution, bool _flag)
39
+ external
40
+ onlyOwner
41
+ {
42
+ for(uint256 i = 0; i < _newRewardDistribution.length; i++){
43
+ rewardDistribution[_newRewardDistribution[i]] = _flag;
44
+ }
45
+ }
46
+ }
47
+
48
+ contract PotPool is IRewardDistributionRecipient, Controllable, ERC20 {
49
+
50
+ using Address for address;
51
+ using SafeERC20 for IERC20;
52
+ using SafeMath for uint256;
53
+
54
+ address public lpToken;
55
+ uint256 public duration; // making it not a constant is less gas efficient, but portable
56
+
57
+ mapping(address => uint256) public stakedBalanceOf;
58
+
59
+ mapping (address => bool) smartContractStakers;
60
+ address[] public rewardTokens;
61
+ mapping(address => uint256) public periodFinishForToken;
62
+ mapping(address => uint256) public rewardRateForToken;
63
+ mapping(address => uint256) public lastUpdateTimeForToken;
64
+ mapping(address => uint256) public rewardPerTokenStoredForToken;
65
+ mapping(address => mapping(address => uint256)) public userRewardPerTokenPaidForToken;
66
+ mapping(address => mapping(address => uint256)) public rewardsForToken;
67
+
68
+ event RewardAdded(address rewardToken, uint256 reward);
69
+ event Staked(address indexed user, uint256 amount);
70
+ event Withdrawn(address indexed user, uint256 amount);
71
+ event RewardPaid(address indexed user, address rewardToken, uint256 reward);
72
+ event RewardDenied(address indexed user, address rewardToken, uint256 reward);
73
+ event SmartContractRecorded(address indexed smartContractAddress, address indexed smartContractInitiator);
74
+
75
+ modifier onlyGovernanceOrRewardDistribution() {
76
+ require(msg.sender == governance() || rewardDistribution[msg.sender], "Not governance nor reward distribution");
77
+ _;
78
+ }
79
+
80
+ modifier updateRewards(address account) {
81
+ for(uint256 i = 0; i < rewardTokens.length; i++ ){
82
+ address rt = rewardTokens[i];
83
+ rewardPerTokenStoredForToken[rt] = rewardPerToken(rt);
84
+ lastUpdateTimeForToken[rt] = lastTimeRewardApplicable(rt);
85
+ if (account != address(0)) {
86
+ rewardsForToken[rt][account] = earned(rt, account);
87
+ userRewardPerTokenPaidForToken[rt][account] = rewardPerTokenStoredForToken[rt];
88
+ }
89
+ }
90
+ _;
91
+ }
92
+
93
+ modifier updateReward(address account, address rt){
94
+ rewardPerTokenStoredForToken[rt] = rewardPerToken(rt);
95
+ lastUpdateTimeForToken[rt] = lastTimeRewardApplicable(rt);
96
+ if (account != address(0)) {
97
+ rewardsForToken[rt][account] = earned(rt, account);
98
+ userRewardPerTokenPaidForToken[rt][account] = rewardPerTokenStoredForToken[rt];
99
+ }
100
+ _;
101
+ }
102
+
103
+ /** View functions to respect old interface */
104
+ function rewardToken() public view returns(address) {
105
+ return rewardTokens[0];
106
+ }
107
+
108
+ function rewardPerToken() public view returns(uint256) {
109
+ return rewardPerToken(rewardTokens[0]);
110
+ }
111
+
112
+ function periodFinish() public view returns(uint256) {
113
+ return periodFinishForToken[rewardTokens[0]];
114
+ }
115
+
116
+ function rewardRate() public view returns(uint256) {
117
+ return rewardRateForToken[rewardTokens[0]];
118
+ }
119
+
120
+ function lastUpdateTime() public view returns(uint256) {
121
+ return lastUpdateTimeForToken[rewardTokens[0]];
122
+ }
123
+
124
+ function rewardPerTokenStored() public view returns(uint256) {
125
+ return rewardPerTokenStoredForToken[rewardTokens[0]];
126
+ }
127
+
128
+ function userRewardPerTokenPaid(address user) public view returns(uint256) {
129
+ return userRewardPerTokenPaidForToken[rewardTokens[0]][user];
130
+ }
131
+
132
+ function rewards(address user) public view returns(uint256) {
133
+ return rewardsForToken[rewardTokens[0]][user];
134
+ }
135
+
136
+ // [Hardwork] setting the reward, lpToken, duration, and rewardDistribution for each pool
137
+ constructor(
138
+ address[] memory _rewardTokens,
139
+ address _lpToken,
140
+ uint256 _duration,
141
+ address[] memory _rewardDistribution,
142
+ address _storage,
143
+ string memory _name,
144
+ string memory _symbol,
145
+ uint8 _decimals
146
+ )
147
+ ERC20(_name, _symbol)
148
+ IRewardDistributionRecipient(_rewardDistribution)
149
+ Controllable(_storage) // only used for referencing the grey list
150
+ {
151
+ require(_decimals == ERC20(_lpToken).decimals(), "decimals has to be aligned with the lpToken");
152
+ require(_rewardTokens.length != 0, "should initialize with at least 1 rewardToken");
153
+ rewardTokens = _rewardTokens;
154
+ lpToken = _lpToken;
155
+ duration = _duration;
156
+ }
157
+
158
+ //Overwrite ERC20's transfer function to block transfer of pTokens,
159
+ //as transferring the token does not transfer the rewards or rights to unstake.
160
+ function transfer(address /*recipient*/, uint256 amount) public override returns (bool) {
161
+ if (amount > 0) {
162
+ revert("Staked assets cannot be transferred");
163
+ }
164
+ }
165
+
166
+ function lastTimeRewardApplicable(uint256 i) public view returns (uint256) {
167
+ return lastTimeRewardApplicable(rewardTokens[i]);
168
+ }
169
+
170
+ function lastTimeRewardApplicable(address rt) public view returns (uint256) {
171
+ return Math.min(block.timestamp, periodFinishForToken[rt]);
172
+ }
173
+
174
+ function lastTimeRewardApplicable() public view returns (uint256) {
175
+ return lastTimeRewardApplicable(rewardTokens[0]);
176
+ }
177
+
178
+ function rewardPerToken(uint256 i) public view returns (uint256) {
179
+ return rewardPerToken(rewardTokens[i]);
180
+ }
181
+
182
+ function rewardPerToken(address rt) public view returns (uint256) {
183
+ if (totalSupply() == 0) {
184
+ return rewardPerTokenStoredForToken[rt];
185
+ }
186
+ return
187
+ rewardPerTokenStoredForToken[rt].add(
188
+ lastTimeRewardApplicable(rt)
189
+ .sub(lastUpdateTimeForToken[rt])
190
+ .mul(rewardRateForToken[rt])
191
+ .mul(1e18)
192
+ .div(totalSupply())
193
+ );
194
+ }
195
+
196
+ function earned(uint256 i, address account) public view returns (uint256) {
197
+ return earned(rewardTokens[i], account);
198
+ }
199
+
200
+ function earned(address account) public view returns (uint256) {
201
+ return earned(rewardTokens[0], account);
202
+ }
203
+
204
+ function earned(address rt, address account) public view returns (uint256) {
205
+ return
206
+ stakedBalanceOf[account]
207
+ .mul(rewardPerToken(rt).sub(userRewardPerTokenPaidForToken[rt][account]))
208
+ .div(1e18)
209
+ .add(rewardsForToken[rt][account]);
210
+ }
211
+
212
+ function stake(uint256 amount) public updateRewards(msg.sender) {
213
+ require(amount > 0, "Cannot stake 0");
214
+ recordSmartContract();
215
+ super._mint(msg.sender, amount); // ERC20 is used as a staking receipt
216
+ stakedBalanceOf[msg.sender] = stakedBalanceOf[msg.sender].add(amount);
217
+ IERC20(lpToken).safeTransferFrom(msg.sender, address(this), amount);
218
+ emit Staked(msg.sender, amount);
219
+ }
220
+
221
+ function withdraw(uint256 amount) public updateRewards(msg.sender) {
222
+ require(amount > 0, "Cannot withdraw 0");
223
+ super._burn(msg.sender, amount);
224
+ stakedBalanceOf[msg.sender] = stakedBalanceOf[msg.sender].sub(amount);
225
+ IERC20(lpToken).safeTransfer(msg.sender, amount);
226
+ emit Withdrawn(msg.sender, amount);
227
+ }
228
+
229
+ function exit() external {
230
+ withdraw(Math.min(stakedBalanceOf[msg.sender], balanceOf(msg.sender)));
231
+ getAllRewards();
232
+ }
233
+
234
+ /// A push mechanism for accounts that have not claimed their rewards for a long time.
235
+ /// The implementation is semantically analogous to getReward(), but uses a push pattern
236
+ /// instead of pull pattern.
237
+ function pushAllRewards(address recipient) public updateRewards(recipient) onlyGovernance {
238
+ bool rewardPayout = (!smartContractStakers[recipient] || !IController(controller()).greyList(recipient));
239
+ for(uint256 i = 0 ; i < rewardTokens.length; i++ ){
240
+ uint256 reward = earned(rewardTokens[i], recipient);
241
+ if (reward > 0) {
242
+ rewardsForToken[rewardTokens[i]][recipient] = 0;
243
+ // If it is a normal user and not smart contract,
244
+ // then the requirement will pass
245
+ // If it is a smart contract, then
246
+ // make sure that it is not on our greyList.
247
+ if (rewardPayout) {
248
+ IERC20(rewardTokens[i]).safeTransfer(recipient, reward);
249
+ emit RewardPaid(recipient, rewardTokens[i], reward);
250
+ } else {
251
+ emit RewardDenied(recipient, rewardTokens[i], reward);
252
+ }
253
+ }
254
+ }
255
+ }
256
+
257
+ function getAllRewards() public updateRewards(msg.sender) {
258
+ recordSmartContract();
259
+ bool rewardPayout = (!smartContractStakers[msg.sender] || !IController(controller()).greyList(msg.sender));
260
+ for(uint256 i = 0 ; i < rewardTokens.length; i++ ){
261
+ _getRewardAction(rewardTokens[i], rewardPayout);
262
+ }
263
+ }
264
+
265
+ function getReward(address rt) public updateReward(msg.sender, rt) {
266
+ recordSmartContract();
267
+ _getRewardAction(
268
+ rt,
269
+ // don't payout if it is a grey listed smart contract
270
+ (!smartContractStakers[msg.sender] || !IController(controller()).greyList(msg.sender))
271
+ );
272
+ }
273
+
274
+ function getReward() public {
275
+ getReward(rewardTokens[0]);
276
+ }
277
+
278
+ function _getRewardAction(address rt, bool rewardPayout) internal {
279
+ uint256 reward = earned(rt, msg.sender);
280
+ if (reward > 0 && IERC20(rt).balanceOf(address(this)) >= reward ) {
281
+ rewardsForToken[rt][msg.sender] = 0;
282
+ // If it is a normal user and not smart contract,
283
+ // then the requirement will pass
284
+ // If it is a smart contract, then
285
+ // make sure that it is not on our greyList.
286
+ if (rewardPayout) {
287
+ IERC20(rt).safeTransfer(msg.sender, reward);
288
+ emit RewardPaid(msg.sender, rt, reward);
289
+ } else {
290
+ emit RewardDenied(msg.sender, rt, reward);
291
+ }
292
+ }
293
+ }
294
+
295
+ function addRewardToken(address rt) public onlyGovernanceOrRewardDistribution {
296
+ require(getRewardTokenIndex(rt) == type(uint256).max, "Reward token already exists");
297
+ rewardTokens.push(rt);
298
+ }
299
+
300
+ function removeRewardToken(address rt) public onlyGovernanceOrRewardDistribution {
301
+ uint256 i = getRewardTokenIndex(rt);
302
+ require(i != type(uint256).max, "Reward token does not exists");
303
+ require(periodFinishForToken[rewardTokens[i]] < block.timestamp, "Can only remove when the reward period has passed");
304
+ require(rewardTokens.length > 1, "Cannot remove the last reward token");
305
+ uint256 lastIndex = rewardTokens.length - 1;
306
+
307
+ // swap
308
+ rewardTokens[i] = rewardTokens[lastIndex];
309
+
310
+ // delete last element
311
+ rewardTokens.pop();
312
+ }
313
+
314
+ // If the return value is MAX_UINT256, it means that
315
+ // the specified reward token is not in the list
316
+ function getRewardTokenIndex(address rt) public view returns(uint256) {
317
+ for(uint i = 0 ; i < rewardTokens.length ; i++){
318
+ if(rewardTokens[i] == rt)
319
+ return i;
320
+ }
321
+ return type(uint256).max;
322
+ }
323
+
324
+ function notifyTargetRewardAmount(address _rewardToken, uint256 reward)
325
+ public override
326
+ onlyRewardDistribution
327
+ updateRewards(address(0))
328
+ {
329
+ // overflow fix according to https://sips.synthetix.io/sips/sip-77
330
+ require(reward < type(uint256).max / 1e18, "the notified reward cannot invoke multiplication overflow");
331
+
332
+ uint256 i = getRewardTokenIndex(_rewardToken);
333
+ require(i != type(uint256).max, "rewardTokenIndex not found");
334
+
335
+ if (block.timestamp >= periodFinishForToken[_rewardToken]) {
336
+ rewardRateForToken[_rewardToken] = reward.div(duration);
337
+ } else {
338
+ uint256 remaining = periodFinishForToken[_rewardToken].sub(block.timestamp);
339
+ uint256 leftover = remaining.mul(rewardRateForToken[_rewardToken]);
340
+ rewardRateForToken[_rewardToken] = reward.add(leftover).div(duration);
341
+ }
342
+ lastUpdateTimeForToken[_rewardToken] = block.timestamp;
343
+ periodFinishForToken[_rewardToken] = block.timestamp.add(duration);
344
+ emit RewardAdded(_rewardToken, reward);
345
+ }
346
+
347
+ function notifyRewardAmount(uint256 reward)
348
+ external override
349
+ onlyRewardDistribution
350
+ updateRewards(address(0))
351
+ {
352
+ notifyTargetRewardAmount(rewardTokens[0], reward);
353
+ }
354
+
355
+ function rewardTokensLength() public view returns(uint256){
356
+ return rewardTokens.length;
357
+ }
358
+
359
+ // Harvest Smart Contract recording
360
+ function recordSmartContract() internal {
361
+ if( tx.origin != msg.sender ) {
362
+ smartContractStakers[msg.sender] = true;
363
+ emit SmartContractRecorded(msg.sender, tx.origin);
364
+ }
365
+ }
366
+
367
+ }
@@ -0,0 +1,38 @@
1
+ // SPDX-License-Identifier: Unlicense
2
+ pragma solidity 0.8.26;
3
+
4
+ import "@openzeppelin/contracts/utils/Address.sol";
5
+ import "@openzeppelin/contracts/utils/math/SafeMath.sol";
6
+ import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
7
+ import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
8
+
9
+ import "./inheritance/Governable.sol";
10
+ import "./interface/IProfitSharingReceiver.sol";
11
+
12
+
13
+ /**
14
+ * A simple contract for receiving tokens for profit sharing. This contract is designed to pool rewards that will be
15
+ * sent by governance to Ethereum mainnet for FARM buybacks
16
+ */
17
+ contract ProfitSharingReceiver is Governable {
18
+ using SafeERC20 for IERC20;
19
+
20
+ event WithdrawToken(address indexed token, address indexed receiver, uint amount);
21
+
22
+ constructor(
23
+ address _store
24
+ )
25
+ Governable(_store) {}
26
+
27
+ function withdrawTokens(address[] calldata _tokens) external onlyGovernance {
28
+ address _governance = governance();
29
+ for (uint i = 0; i < _tokens.length; ++i) {
30
+ uint amount = IERC20(_tokens[i]).balanceOf(address(this));
31
+ if (amount > 0) {
32
+ IERC20(_tokens[i]).safeTransfer(_governance, amount);
33
+ emit WithdrawToken(_tokens[i], _governance, amount);
34
+ }
35
+ }
36
+ }
37
+
38
+ }
@@ -0,0 +1,54 @@
1
+ // SPDX-License-Identifier: Unlicense
2
+ pragma solidity 0.8.26;
3
+
4
+ import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
5
+ import "./interface/IVault.sol";
6
+
7
+ contract Reader {
8
+
9
+ function getAllInformation(address who, address[] memory vaults, address[] memory pools)
10
+ public view returns (uint256[] memory, uint256[] memory, uint256[] memory) {
11
+ return (unstakedBalances(who, vaults), stakedBalances(who, pools), vaultSharePrices(vaults));
12
+ }
13
+
14
+ function unstakedBalances(address who, address[] memory vaults) public view returns (uint256[] memory) {
15
+ uint256[] memory result = new uint256[](vaults.length);
16
+ for (uint256 i = 0; i < vaults.length; i++) {
17
+ result[i] = IERC20Upgradeable(vaults[i]).balanceOf(who);
18
+ }
19
+ return result;
20
+ }
21
+
22
+ function stakedBalances(address who, address[] memory pools) public view returns (uint256[] memory) {
23
+ uint256[] memory result = new uint256[](pools.length);
24
+ for (uint256 i = 0; i < pools.length; i++) {
25
+ result[i] = IERC20Upgradeable(pools[i]).balanceOf(who);
26
+ }
27
+ return result;
28
+ }
29
+
30
+ function underlyingBalances(address who, address[] memory vaults) public view returns (uint256[] memory) {
31
+ uint256[] memory result = new uint256[](vaults.length);
32
+ for (uint256 i = 0; i < vaults.length; i++) {
33
+ result[i] = IERC20Upgradeable(IVault(vaults[i]).underlying()).balanceOf(who);
34
+ }
35
+ return result;
36
+ }
37
+
38
+ function vaultSharePrices(address[] memory vaults) public view returns (uint256[] memory) {
39
+ uint256[] memory result = new uint256[](vaults.length);
40
+ for (uint256 i = 0; i < vaults.length; i++) {
41
+ result[i] = IVault(vaults[i]).getPricePerFullShare();
42
+ }
43
+ return result;
44
+ }
45
+
46
+ function underlyingBalanceWithInvestmentForHolder(address who, address[] memory vaults)
47
+ public view returns (uint256[] memory) {
48
+ uint256[] memory result = new uint256[](vaults.length);
49
+ for (uint256 i = 0; i < vaults.length; i++) {
50
+ result[i] = IVault(vaults[i]).underlyingBalanceWithInvestmentForHolder(who);
51
+ }
52
+ return result;
53
+ }
54
+ }
@@ -0,0 +1,109 @@
1
+ // SPDX-License-Identifier: Unlicense
2
+ pragma solidity 0.8.26;
3
+
4
+ import "@openzeppelin/contracts/utils/math/SafeMath.sol";
5
+ import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
6
+ import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
7
+
8
+ import "./inheritance/Governable.sol";
9
+ import "./interface/IController.sol";
10
+ import "./interface/IRewardForwarder.sol";
11
+ import "./interface/IProfitSharingReceiver.sol";
12
+ import "./interface/IStrategy.sol";
13
+ import "./interface/IUniversalLiquidator.sol";
14
+ import "./inheritance/Controllable.sol";
15
+
16
+ /**
17
+ * @dev This contract receives rewards from strategies and is responsible for routing the reward's liquidation into
18
+ * specific buyback tokens and profit tokens for the DAO.
19
+ */
20
+ contract RewardForwarder is Controllable {
21
+ using SafeERC20 for IERC20;
22
+ using SafeMath for uint256;
23
+
24
+ address public constant iFARM = address(0x9dCA587dc65AC0a043828B0acd946d71eb8D46c1);
25
+
26
+ constructor(
27
+ address _storage
28
+ ) Controllable(_storage) {}
29
+
30
+ function notifyFee(
31
+ address _token,
32
+ uint256 _profitSharingFee,
33
+ uint256 _strategistFee,
34
+ uint256 _platformFee
35
+ ) external {
36
+ _notifyFee(
37
+ _token,
38
+ _profitSharingFee,
39
+ _strategistFee,
40
+ _platformFee
41
+ );
42
+ }
43
+
44
+ function _notifyFee(
45
+ address _token,
46
+ uint256 _profitSharingFee,
47
+ uint256 _strategistFee,
48
+ uint256 _platformFee
49
+ ) internal {
50
+ address _controller = controller();
51
+ address liquidator = IController(_controller).universalLiquidator();
52
+
53
+ uint totalTransferAmount = _profitSharingFee.add(_strategistFee).add(_platformFee);
54
+ require(totalTransferAmount > 0, "totalTransferAmount should not be 0");
55
+ IERC20(_token).safeTransferFrom(msg.sender, address(this), totalTransferAmount);
56
+
57
+ address _targetToken = IController(_controller).targetToken();
58
+
59
+ if (_token != _targetToken) {
60
+ IERC20(_token).safeApprove(liquidator, 0);
61
+ IERC20(_token).safeApprove(liquidator, _platformFee);
62
+
63
+ uint amountOutMin = 1;
64
+
65
+ if (_platformFee > 0) {
66
+ IUniversalLiquidator(liquidator).swap(
67
+ _token,
68
+ _targetToken,
69
+ _platformFee,
70
+ amountOutMin,
71
+ IController(_controller).protocolFeeReceiver()
72
+ );
73
+ }
74
+ } else {
75
+ IERC20(_targetToken).safeTransfer(IController(_controller).protocolFeeReceiver(), _platformFee);
76
+ }
77
+
78
+ if (_token != iFARM) {
79
+ IERC20(_token).safeApprove(liquidator, 0);
80
+ IERC20(_token).safeApprove(liquidator, _profitSharingFee.add(_strategistFee));
81
+
82
+ uint amountOutMin = 1;
83
+
84
+ if (_profitSharingFee > 0) {
85
+ IUniversalLiquidator(liquidator).swap(
86
+ _token,
87
+ iFARM,
88
+ _profitSharingFee,
89
+ amountOutMin,
90
+ IController(_controller).profitSharingReceiver()
91
+ );
92
+ }
93
+ if (_strategistFee > 0) {
94
+ IUniversalLiquidator(liquidator).swap(
95
+ _token,
96
+ iFARM,
97
+ _strategistFee,
98
+ amountOutMin,
99
+ IStrategy(msg.sender).strategist()
100
+ );
101
+ }
102
+ } else {
103
+ if (_strategistFee > 0) {
104
+ IERC20(iFARM).safeTransfer(IStrategy(msg.sender).strategist(), _strategistFee);
105
+ }
106
+ IERC20(iFARM).safeTransfer(IController(_controller).profitSharingReceiver(), _profitSharingFee);
107
+ }
108
+ }
109
+ }
@@ -0,0 +1,34 @@
1
+ // SPDX-License-Identifier: Unlicense
2
+ pragma solidity 0.8.26;
3
+
4
+ import "./interface/IUpgradeSource.sol";
5
+ import "./upgradability/BaseUpgradeabilityProxy.sol";
6
+
7
+ contract VaultProxy is BaseUpgradeabilityProxy {
8
+
9
+ constructor(address _implementation) {
10
+ _setImplementation(_implementation);
11
+ }
12
+
13
+ /**
14
+ * The main logic. If the timer has elapsed and there is a schedule upgrade,
15
+ * the governance can upgrade the vault
16
+ */
17
+ function upgrade() external {
18
+ (bool should, address newImplementation) = IUpgradeSource(address(this)).shouldUpgrade();
19
+ require(should, "Upgrade not scheduled");
20
+ _upgradeTo(newImplementation);
21
+
22
+ // the finalization needs to be executed on itself to update the storage of this proxy
23
+ // it also needs to be invoked by the governance, not by address(this), so delegatecall is needed
24
+ (bool success,) = address(this).delegatecall(
25
+ abi.encodeWithSignature("finalizeUpgrade()")
26
+ );
27
+
28
+ require(success, "Issue when finalizing the upgrade");
29
+ }
30
+
31
+ function implementation() external view returns (address) {
32
+ return _implementation();
33
+ }
34
+ }