@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.
- package/README.md +127 -5
- package/contracts/base/Controller.sol +358 -0
- package/contracts/base/Drip.sol +86 -0
- package/contracts/base/PotPool.sol +367 -0
- package/contracts/base/ProfitSharingReceiver.sol +38 -0
- package/contracts/base/Reader.sol +54 -0
- package/contracts/base/RewardForwarder.sol +109 -0
- package/contracts/base/VaultProxy.sol +34 -0
- package/contracts/base/VaultStorage.sol +205 -0
- package/contracts/base/VaultV1.sol +371 -0
- package/contracts/base/VaultV1GMX.sol +465 -0
- package/contracts/base/VaultV2.sol +111 -0
- package/contracts/base/VaultV2GMX.sol +111 -0
- package/contracts/base/factory/MegaFactory.sol +120 -0
- package/contracts/base/factory/interface/IPoolFactory.sol +6 -0
- package/contracts/base/factory/interface/IStrategyFactory.sol +6 -0
- package/contracts/base/factory/interface/IVaultFactory.sol +7 -0
- package/contracts/base/factory/pool/PotPoolFactory.sol +41 -0
- package/contracts/base/factory/strategy/UpgradableStrategyFactory.sol +19 -0
- package/contracts/base/factory/vault/RegularVaultFactory.sol +34 -0
- package/contracts/base/incentives/GlobalIncentivesExecutor.sol +85 -0
- package/contracts/base/incentives/GlobalIncentivesHelper.sol +174 -0
- package/contracts/base/incentives/NotifyHelperGeneric.sol +61 -0
- package/contracts/base/incentives/NotifyHelperStateful.sol +290 -0
- package/contracts/base/incentives/ViewerNotifyHelperStateful.sol +25 -0
- package/contracts/base/inheritance/Controllable.sol +25 -0
- package/contracts/base/inheritance/ControllableInit.sol +30 -0
- package/contracts/base/inheritance/Governable.sol +28 -0
- package/contracts/base/inheritance/GovernableInit.sol +50 -0
- package/contracts/base/inheritance/IUpgradeSource.sol +7 -0
- package/contracts/base/inheritance/OwnableWhitelist.sol +17 -0
- package/contracts/base/inheritance/Storage.sol +35 -0
- package/contracts/base/interface/IBalDex.sol +7 -0
- package/contracts/base/interface/IController.sol +132 -0
- package/contracts/base/interface/IDex.sol +9 -0
- package/contracts/base/interface/IERC4626.sol +261 -0
- package/contracts/base/interface/IGMXStrategy.sol +37 -0
- package/contracts/base/interface/IGlobalIncentivesHelper.sol +6 -0
- package/contracts/base/interface/IPotPool.sol +70 -0
- package/contracts/base/interface/IProfitSharingReceiver.sol +9 -0
- package/contracts/base/interface/IRewardForwarder.sol +57 -0
- package/contracts/base/interface/IStrategy.sol +37 -0
- package/contracts/base/interface/IUniversalLiquidator.sol +21 -0
- package/contracts/base/interface/IUniversalLiquidatorRegistry.sol +20 -0
- package/contracts/base/interface/IUpgradeSource.sol +9 -0
- package/contracts/base/interface/IVault.sol +58 -0
- package/contracts/base/interface/IVaultGMX.sol +71 -0
- package/contracts/base/interface/aura/IAuraBaseRewardPool.sol +25 -0
- package/contracts/base/interface/aura/IAuraBooster.sol +17 -0
- package/contracts/base/interface/aura/IAuraDepositor.sol +7 -0
- package/contracts/base/interface/balancer/Gauge.sol +22 -0
- package/contracts/base/interface/balancer/IBVault.sol +580 -0
- package/contracts/base/interface/balancer/IBalancerMinter.sol +114 -0
- package/contracts/base/interface/balancer/IGyroPool.sol +7 -0
- package/contracts/base/interface/balancer/linearPool/ILinearPool.sol +184 -0
- package/contracts/base/interface/balancer/linearPool/ILinearPoolFactory.sol +16 -0
- package/contracts/base/interface/balancer/linearPool/ILinearPoolRebalancer.sol +8 -0
- package/contracts/base/interface/balancer/linearPool/IPoolSwapStructs.sol +56 -0
- package/contracts/base/interface/compound/CTokenInterface.sol +29 -0
- package/contracts/base/interface/compound/IComptroller.sol +9 -0
- package/contracts/base/interface/dolomite/IDepositWithdraw.sol +13 -0
- package/contracts/base/interface/dolomite/IDolomiteMargin.sol +15 -0
- package/contracts/base/interface/dolomite/IRewardsDistributor.sol +11 -0
- package/contracts/base/interface/gamma/IClearing.sol +7 -0
- package/contracts/base/interface/gamma/IHypervisor.sol +9 -0
- package/contracts/base/interface/gamma/IUniProxy.sol +14 -0
- package/contracts/base/interface/gmx/EventUtils.sol +253 -0
- package/contracts/base/interface/gmx/ICallbackReceiver.sol +119 -0
- package/contracts/base/interface/gmx/IDataStore.sol +7 -0
- package/contracts/base/interface/gmx/IExchangeRouter.sol +38 -0
- package/contracts/base/interface/gmx/IGMXViewer.sol +7 -0
- package/contracts/base/interface/gmx/IHandler.sol +12 -0
- package/contracts/base/interface/gmx/IMarket.sol +7 -0
- package/contracts/base/interface/gmx/IOracle.sol +6 -0
- package/contracts/base/interface/gmx/IPriceFeed.sol +12 -0
- package/contracts/base/interface/gmx/IReader.sol +49 -0
- package/contracts/base/interface/gmx/IRoleStore.sol +6 -0
- package/contracts/base/interface/ipor/Errors.sol +20 -0
- package/contracts/base/interface/ipor/FuseStorageLib.sol +71 -0
- package/contracts/base/interface/ipor/FusesLib.sol +149 -0
- package/contracts/base/interface/ipor/IFuseCommon.sol +9 -0
- package/contracts/base/interface/ipor/IFuseInstantWithdraw.sol +14 -0
- package/contracts/base/interface/ipor/IMarketBalanceFuse.sol +10 -0
- package/contracts/base/interface/ipor/IPriceOracleMiddleware.sol +42 -0
- package/contracts/base/interface/ipor/IporMath.sol +110 -0
- package/contracts/base/interface/ipor/PlasmaVaultConfigLib.sol +106 -0
- package/contracts/base/interface/ipor/PlasmaVaultLib.sol +293 -0
- package/contracts/base/interface/ipor/PlasmaVaultStorageLib.sol +352 -0
- package/contracts/base/interface/merkl/IDistributor.sol +6 -0
- package/contracts/base/interface/notional/INProxy.sol +44 -0
- package/contracts/base/interface/notional/IPrimeToken.sol +6 -0
- package/contracts/base/interface/venus/IRewardsDistributor.sol +6 -0
- package/contracts/base/interface/weth/IWETH.sol +39 -0
- package/contracts/base/ipor/Erc4626BalanceFuse.sol +54 -0
- package/contracts/base/ipor/Erc4626SupplyFuse.sol +134 -0
- package/contracts/base/noop/NoopStrategyUpgradeable.sol +90 -0
- package/contracts/base/upgradability/BaseUpgradeabilityProxy.sol +60 -0
- package/contracts/base/upgradability/BaseUpgradeableStrategy.sol +144 -0
- package/contracts/base/upgradability/BaseUpgradeableStrategyStorage.sol +284 -0
- package/contracts/base/upgradability/IUpgradable.sol +7 -0
- package/contracts/base/upgradability/ReentrancyGuardUpgradeable.sol +51 -0
- package/contracts/base/upgradability/StrategyProxy.sol +34 -0
- package/contracts/strategies/aura/AuraStrategy.sol +403 -0
- package/contracts/strategies/aura/AuraStrategyMainnet_MORE_GYD.sol +32 -0
- package/contracts/strategies/aura/AuraStrategyMainnet_sUSDe_GYD.sol +31 -0
- package/contracts/strategies/aura/AuraStrategyMainnet_waFRAX_sFRAX.sol +31 -0
- package/contracts/strategies/aura/AuraStrategyMainnet_waGHO_GYD.sol +31 -0
- package/contracts/strategies/aura/AuraStrategyMainnet_waUSDC_GHO.sol +32 -0
- package/contracts/strategies/aura/AuraStrategyMainnet_waUSDC_GYD.sol +31 -0
- package/contracts/strategies/aura/AuraStrategyMainnet_waUSDT_GYD.sol +31 -0
- package/contracts/strategies/aura/AuraStrategyMainnet_wstETH_GYD.sol +31 -0
- package/contracts/strategies/camelot/CamelotV3Strategy.sol +304 -0
- package/contracts/strategies/camelot/CamelotV3StrategyMainnet_ARB_USDC.sol +28 -0
- package/contracts/strategies/camelot/CamelotV3StrategyMainnet_ETH_USDC.sol +28 -0
- package/contracts/strategies/camelot/CamelotV3StrategyMainnet_ETH_USDT.sol +28 -0
- package/contracts/strategies/camelot/CamelotV3StrategyMainnet_GMX_ETH.sol +28 -0
- package/contracts/strategies/camelot/CamelotV3StrategyMainnet_GRAIL_ETH.sol +28 -0
- package/contracts/strategies/camelot/CamelotV3StrategyMainnet_USDC_USDT.sol +28 -0
- package/contracts/strategies/camelot/CamelotV3StrategyMainnet_WBTC_ETH.sol +28 -0
- package/contracts/strategies/dolomite/DolomiteLendStrategy.sol +273 -0
- package/contracts/strategies/dolomite/DolomiteLendStrategyMainnet_DAI.sol +26 -0
- package/contracts/strategies/dolomite/DolomiteLendStrategyMainnet_GMX.sol +26 -0
- package/contracts/strategies/dolomite/DolomiteLendStrategyMainnet_USDC.sol +26 -0
- package/contracts/strategies/dolomite/DolomiteLendStrategyMainnet_USDCe.sol +26 -0
- package/contracts/strategies/dolomite/DolomiteLendStrategyMainnet_USDT.sol +26 -0
- package/contracts/strategies/dolomite/DolomiteLendStrategyMainnet_WBTC.sol +26 -0
- package/contracts/strategies/dolomite/DolomiteLendStrategyMainnet_WETH.sol +26 -0
- package/contracts/strategies/fluid/FluidLendStrategy.sol +241 -0
- package/contracts/strategies/fluid/FluidLendStrategyMainnet_ETH.sol +25 -0
- package/contracts/strategies/fluid/FluidLendStrategyMainnet_USDC.sol +25 -0
- package/contracts/strategies/fluid/FluidLendStrategyMainnet_USDT.sol +25 -0
- package/contracts/strategies/gmx/GMXStrategy.sol +472 -0
- package/contracts/strategies/gmx/GMXStrategyMainnet_WBTC.sol +25 -0
- package/contracts/strategies/gmx/GMXViewer.sol +110 -0
- package/contracts/strategies/notional/NotionalStrategy.sol +223 -0
- package/contracts/strategies/notional/NotionalStrategyMainnet_nETH.sol +27 -0
- package/contracts/strategies/notional/NotionalStrategyMainnet_nUSDC.sol +27 -0
- package/contracts/strategies/notional/NotionalStrategyMainnet_nUSDT.sol +27 -0
- package/contracts/strategies/notional/NotionalStrategyMainnet_nwstETH.sol +27 -0
- package/contracts/strategies/venus/VenusFoldStrategy.sol +591 -0
- package/contracts/strategies/venus/VenusFoldStrategyMainnet_ARB.sol +32 -0
- package/contracts/strategies/venus/VenusFoldStrategyMainnet_ETH_core.sol +32 -0
- package/contracts/strategies/venus/VenusFoldStrategyMainnet_ETH_lsd.sol +32 -0
- package/contracts/strategies/venus/VenusFoldStrategyMainnet_USDC.sol +32 -0
- package/contracts/strategies/venus/VenusFoldStrategyMainnet_USDT.sol +32 -0
- package/contracts/strategies/venus/VenusFoldStrategyMainnet_WBTC.sol +32 -0
- package/hardhat.config.js +60 -0
- package/index.js +42 -0
- package/package.json +38 -6
- package/scripts/01-deploy-vault-regular-with-upgradable-strategy.js +41 -0
- package/scripts/02-deploy-vault-regular.js +35 -0
- package/scripts/03-deploy-upgradable-strategy.js +40 -0
- package/scripts/04-deploy-new-implementation.js +24 -0
- package/scripts/05-deploy-GMXViewer.js +17 -0
- package/scripts/06-deploy-GMXVault.js +49 -0
- package/scripts/07-deploy-ipor-fuses.js +29 -0
- package/scripts/08-deploy-drip.js +20 -0
- package/scripts/README.md +55 -0
- package/scripts/utils.js +22 -0
- package/test/aura/more-gyd.js +140 -0
- package/test/aura/susde-gyd.js +140 -0
- package/test/aura/wafrax-sfrax.js +140 -0
- package/test/aura/wagho-gyd.js +140 -0
- package/test/aura/wausdc-gho.js +141 -0
- package/test/aura/wausdc-gyd.js +140 -0
- package/test/aura/wausdt-gyd.js +140 -0
- package/test/aura/wsteth-gyd.js +138 -0
- package/test/camelot/arb-usdc.js +125 -0
- package/test/camelot/eth-usdc.js +125 -0
- package/test/camelot/eth-usdt.js +125 -0
- package/test/camelot/gmx-eth.js +125 -0
- package/test/camelot/grail-eth.js +125 -0
- package/test/camelot/usdc-usdt.js +125 -0
- package/test/camelot/wbtc-eth.js +125 -0
- package/test/dolomite/dai.js +127 -0
- package/test/dolomite/gmx.js +134 -0
- package/test/dolomite/usdc.js +127 -0
- package/test/dolomite/usdce.js +127 -0
- package/test/dolomite/usdt.js +127 -0
- package/test/dolomite/wbtc.js +127 -0
- package/test/dolomite/weth.js +127 -0
- package/test/fluid/eth.js +127 -0
- package/test/fluid/usdc.js +134 -0
- package/test/fluid/usdt.js +134 -0
- package/test/gmx/wbtc.js +184 -0
- package/test/notional/neth.js +133 -0
- package/test/notional/nusdc.js +133 -0
- package/test/notional/nusdt.js +133 -0
- package/test/notional/nwsteth.js +133 -0
- package/test/test-config.js +28 -0
- package/test/utilities/Utils.js +96 -0
- package/test/utilities/hh-utils.js +248 -0
- package/test/utilities/make-vault.js +16 -0
- package/test/venus/arb.js +135 -0
- package/test/venus/eth-core.js +133 -0
- package/test/venus/eth-lsd.js +133 -0
- package/test/venus/usdc.js +133 -0
- package/test/venus/usdt.js +133 -0
- 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
|
+
}
|