@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,133 @@
1
+ // Utilities
2
+ const Utils = require("../utilities/Utils.js");
3
+ const { impersonates, setupCoreProtocol, depositVault } = require("../utilities/hh-utils.js");
4
+ const addresses = require("../test-config.js");
5
+
6
+ const BigNumber = require("bignumber.js");
7
+ const IERC20 = artifacts.require("@openzeppelin/contracts/token/ERC20/IERC20.sol:IERC20");
8
+
9
+ const Strategy = artifacts.require("NotionalStrategyMainnet_nUSDT");
10
+
11
+ //This test was developed at blockNumber 252737900
12
+
13
+ // Vanilla Mocha test. Increased compatibility with tools that integrate Mocha.
14
+ describe("Mainnet Notional nUSDT", function() {
15
+ let accounts;
16
+
17
+ // external contracts
18
+ let underlying;
19
+
20
+ // external setup
21
+ let underlyingWhale = "0xbdE30e219d605E202237564c6D93FA5171788bdc";
22
+ let note = "0x019bE259BC299F3F653688c7655C87F998Bc7bC1";
23
+ let weth = "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1";
24
+ let arb = "0x912CE59144191C1204E64559FE8253a0e49E6548";
25
+
26
+ // parties in the protocol
27
+ let governance;
28
+ let farmer1;
29
+
30
+ // numbers used in tests
31
+ let farmerBalance;
32
+
33
+ // Core protocol contracts
34
+ let controller;
35
+ let vault;
36
+ let strategy;
37
+
38
+ async function setupExternalContracts() {
39
+ underlying = await IERC20.at("0x9c0Fbb8caDE7B178b135fD2F1da125a37B27f442");
40
+ console.log("Fetching Underlying at: ", underlying.address);
41
+ }
42
+
43
+ async function setupBalance(){
44
+ let etherGiver = accounts[9];
45
+ // Give whale some ether to make sure the following actions are good
46
+ await web3.eth.sendTransaction({ from: etherGiver, to: underlyingWhale, value: 10e18});
47
+ await web3.eth.sendTransaction({ from: etherGiver, to: addresses.ULOwner, value: 10e18});
48
+
49
+ farmerBalance = await underlying.balanceOf(underlyingWhale);
50
+ await underlying.transfer(farmer1, farmerBalance, { from: underlyingWhale });
51
+ }
52
+
53
+ before(async function() {
54
+ governance = addresses.Governance;
55
+ accounts = await web3.eth.getAccounts();
56
+
57
+ await web3.eth.sendTransaction({ from: accounts[8], to: governance, value: 10e18});
58
+ await web3.eth.sendTransaction({ from: accounts[8], to: addresses.ULOwner, value: 10e18});
59
+
60
+ farmer1 = accounts[1];
61
+
62
+ // impersonate accounts
63
+ await impersonates([governance, underlyingWhale, addresses.ULOwner]);
64
+
65
+ await setupExternalContracts();
66
+ [controller, vault, strategy] = await setupCoreProtocol({
67
+ "existingVaultAddress": null,
68
+ "strategyArtifact": Strategy,
69
+ "strategyArtifactIsUpgradable": true,
70
+ "underlying": underlying,
71
+ "governance": governance,
72
+ "liquidation": [
73
+ {"uniV3": [note, weth]},
74
+ {"camelot": [arb, weth]},
75
+ {"uniV3": [weth, note]}
76
+ ],
77
+ "uniV3Fee": [
78
+ [note, weth, 10000]
79
+ ],
80
+ "ULOwner": addresses.ULOwner
81
+ });
82
+
83
+ // whale send underlying to farmers
84
+ await setupBalance();
85
+ });
86
+
87
+ describe("Happy path", function() {
88
+ it("Farmer should earn money", async function() {
89
+ let farmerOldBalance = new BigNumber(await underlying.balanceOf(farmer1));
90
+ await depositVault(farmer1, underlying, vault, farmerBalance);
91
+ let fTokenBalance = new BigNumber(await vault.balanceOf(farmer1));
92
+
93
+ // Using half days is to simulate how we doHardwork in the real world
94
+ let hours = 10;
95
+ let blocksPerHour = 2400;
96
+ let oldSharePrice;
97
+ let newSharePrice;
98
+ for (let i = 0; i < hours; i++) {
99
+ console.log("loop ", i);
100
+
101
+ oldSharePrice = new BigNumber(await vault.getPricePerFullShare());
102
+ await controller.doHardWork(vault.address, { from: governance });
103
+ newSharePrice = new BigNumber(await vault.getPricePerFullShare());
104
+
105
+ console.log("old shareprice: ", oldSharePrice.toFixed());
106
+ console.log("new shareprice: ", newSharePrice.toFixed());
107
+ console.log("growth: ", newSharePrice.toFixed() / oldSharePrice.toFixed());
108
+
109
+ apr = (newSharePrice.toFixed()/oldSharePrice.toFixed()-1)*(24/(blocksPerHour/300))*365;
110
+ apy = ((newSharePrice.toFixed()/oldSharePrice.toFixed()-1)*(24/(blocksPerHour/300))+1)**365;
111
+
112
+ console.log("instant APR:", apr*100, "%");
113
+ console.log("instant APY:", (apy-1)*100, "%");
114
+ await vault.withdraw(fTokenBalance.div(10), { from: farmer1 });
115
+ await depositVault(farmer1, underlying, vault, new BigNumber(await underlying.balanceOf(farmer1)))
116
+ await Utils.advanceNBlock(blocksPerHour);
117
+ }
118
+ fTokenBalance = new BigNumber(await vault.balanceOf(farmer1));
119
+ await vault.withdraw(fTokenBalance, { from: farmer1 });
120
+ let farmerNewBalance = new BigNumber(await underlying.balanceOf(farmer1));
121
+ Utils.assertBNGt(farmerNewBalance, farmerOldBalance);
122
+
123
+ apr = (farmerNewBalance.toFixed()/farmerOldBalance.toFixed()-1)*(24/(blocksPerHour*hours/300))*365;
124
+ apy = ((farmerNewBalance.toFixed()/farmerOldBalance.toFixed()-1)*(24/(blocksPerHour*hours/300))+1)**365;
125
+
126
+ console.log("earned!");
127
+ console.log("Overall APR:", apr*100, "%");
128
+ console.log("Overall APY:", (apy-1)*100, "%");
129
+
130
+ await strategy.withdrawAllToVault({ from: governance }); // making sure can withdraw all for a next switch
131
+ });
132
+ });
133
+ });
@@ -0,0 +1,133 @@
1
+ // Utilities
2
+ const Utils = require("../utilities/Utils.js");
3
+ const { impersonates, setupCoreProtocol, depositVault } = require("../utilities/hh-utils.js");
4
+ const addresses = require("../test-config.js");
5
+
6
+ const BigNumber = require("bignumber.js");
7
+ const IERC20 = artifacts.require("@openzeppelin/contracts/token/ERC20/IERC20.sol:IERC20");
8
+
9
+ const Strategy = artifacts.require("NotionalStrategyMainnet_nwstETH");
10
+
11
+ //This test was developed at blockNumber 252737900
12
+
13
+ // Vanilla Mocha test. Increased compatibility with tools that integrate Mocha.
14
+ describe("Mainnet Notional nwstETH", function() {
15
+ let accounts;
16
+
17
+ // external contracts
18
+ let underlying;
19
+
20
+ // external setup
21
+ let underlyingWhale = "0x4Ee711b72b476f47A05AEc5a260BA42Bb564404D";
22
+ let note = "0x019bE259BC299F3F653688c7655C87F998Bc7bC1";
23
+ let weth = "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1";
24
+ let arb = "0x912CE59144191C1204E64559FE8253a0e49E6548";
25
+
26
+ // parties in the protocol
27
+ let governance;
28
+ let farmer1;
29
+
30
+ // numbers used in tests
31
+ let farmerBalance;
32
+
33
+ // Core protocol contracts
34
+ let controller;
35
+ let vault;
36
+ let strategy;
37
+
38
+ async function setupExternalContracts() {
39
+ underlying = await IERC20.at("0x06D45ef1f8b3C37b0de66f156B11F10b4837619A");
40
+ console.log("Fetching Underlying at: ", underlying.address);
41
+ }
42
+
43
+ async function setupBalance(){
44
+ let etherGiver = accounts[9];
45
+ // Give whale some ether to make sure the following actions are good
46
+ await web3.eth.sendTransaction({ from: etherGiver, to: underlyingWhale, value: 10e18});
47
+ await web3.eth.sendTransaction({ from: etherGiver, to: addresses.ULOwner, value: 10e18});
48
+
49
+ farmerBalance = await underlying.balanceOf(underlyingWhale);
50
+ await underlying.transfer(farmer1, farmerBalance, { from: underlyingWhale });
51
+ }
52
+
53
+ before(async function() {
54
+ governance = addresses.Governance;
55
+ accounts = await web3.eth.getAccounts();
56
+
57
+ await web3.eth.sendTransaction({ from: accounts[8], to: governance, value: 10e18});
58
+ await web3.eth.sendTransaction({ from: accounts[8], to: addresses.ULOwner, value: 10e18});
59
+
60
+ farmer1 = accounts[1];
61
+
62
+ // impersonate accounts
63
+ await impersonates([governance, underlyingWhale, addresses.ULOwner]);
64
+
65
+ await setupExternalContracts();
66
+ [controller, vault, strategy] = await setupCoreProtocol({
67
+ "existingVaultAddress": null,
68
+ "strategyArtifact": Strategy,
69
+ "strategyArtifactIsUpgradable": true,
70
+ "underlying": underlying,
71
+ "governance": governance,
72
+ "liquidation": [
73
+ {"uniV3": [note, weth]},
74
+ {"camelot": [arb, weth]},
75
+ {"uniV3": [weth, note]}
76
+ ],
77
+ "uniV3Fee": [
78
+ [note, weth, 10000]
79
+ ],
80
+ "ULOwner": addresses.ULOwner
81
+ });
82
+
83
+ // whale send underlying to farmers
84
+ await setupBalance();
85
+ });
86
+
87
+ describe("Happy path", function() {
88
+ it("Farmer should earn money", async function() {
89
+ let farmerOldBalance = new BigNumber(await underlying.balanceOf(farmer1));
90
+ await depositVault(farmer1, underlying, vault, farmerBalance);
91
+ let fTokenBalance = new BigNumber(await vault.balanceOf(farmer1));
92
+
93
+ // Using half days is to simulate how we doHardwork in the real world
94
+ let hours = 10;
95
+ let blocksPerHour = 2400;
96
+ let oldSharePrice;
97
+ let newSharePrice;
98
+ for (let i = 0; i < hours; i++) {
99
+ console.log("loop ", i);
100
+
101
+ oldSharePrice = new BigNumber(await vault.getPricePerFullShare());
102
+ await controller.doHardWork(vault.address, { from: governance });
103
+ newSharePrice = new BigNumber(await vault.getPricePerFullShare());
104
+
105
+ console.log("old shareprice: ", oldSharePrice.toFixed());
106
+ console.log("new shareprice: ", newSharePrice.toFixed());
107
+ console.log("growth: ", newSharePrice.toFixed() / oldSharePrice.toFixed());
108
+
109
+ apr = (newSharePrice.toFixed()/oldSharePrice.toFixed()-1)*(24/(blocksPerHour/300))*365;
110
+ apy = ((newSharePrice.toFixed()/oldSharePrice.toFixed()-1)*(24/(blocksPerHour/300))+1)**365;
111
+
112
+ console.log("instant APR:", apr*100, "%");
113
+ console.log("instant APY:", (apy-1)*100, "%");
114
+ await vault.withdraw(fTokenBalance.div(10), { from: farmer1 });
115
+ await depositVault(farmer1, underlying, vault, new BigNumber(await underlying.balanceOf(farmer1)))
116
+ await Utils.advanceNBlock(blocksPerHour);
117
+ }
118
+ fTokenBalance = new BigNumber(await vault.balanceOf(farmer1));
119
+ await vault.withdraw(fTokenBalance, { from: farmer1 });
120
+ let farmerNewBalance = new BigNumber(await underlying.balanceOf(farmer1));
121
+ Utils.assertBNGt(farmerNewBalance, farmerOldBalance);
122
+
123
+ apr = (farmerNewBalance.toFixed()/farmerOldBalance.toFixed()-1)*(24/(blocksPerHour*hours/300))*365;
124
+ apy = ((farmerNewBalance.toFixed()/farmerOldBalance.toFixed()-1)*(24/(blocksPerHour*hours/300))+1)**365;
125
+
126
+ console.log("earned!");
127
+ console.log("Overall APR:", apr*100, "%");
128
+ console.log("Overall APY:", (apy-1)*100, "%");
129
+
130
+ await strategy.withdrawAllToVault({ from: governance }); // making sure can withdraw all for a next switch
131
+ });
132
+ });
133
+ });
@@ -0,0 +1,28 @@
1
+ module.exports = {
2
+ "Storage": "0x88937abfc8C6A88cc70bfc686E4fBba80DE8d329",
3
+ "RewardForwarder": "0xC5a1873Bb6F83C677EB255194562500CcB7eE67F",
4
+ "UniversalLiquidator": "0x5f513cA572e7eD10487cEF2b0636C07eA9b82AD8",
5
+ "UniversalLiquidatorRegistry": "0xbcE9d31FfA2c96E11cEbEAa021136a83A3575D95",
6
+ "ULOwner": "0x6a74649aCFD7822ae8Fb78463a9f2192752E5Aa2",
7
+ "Controller": "0x68B2FC1566f411C1Af8fF5bFDA3dD4F3F3e59D03",
8
+ "Governance": "0xF066789028fE31D4f53B69B81b328B8218Cc0641",
9
+ "iFARM": "0x9dCA587dc65AC0a043828B0acd946d71eb8D46c1",
10
+ "WETH": "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
11
+ "VaultImplementationV2": "0x350856A672e7bF7D7327c8a5e72Ac49833DBfB75",
12
+ "CommunityMsig": "0xf3D1A027E858976634F81B7c41B09A05A46EdA21",
13
+ "ProfitShare": "0x5F11EfDF4422B548007Cae9919b0b38c35fa6BE7",
14
+ "Reader": "0xD5E42f45CC4ef59dE83999FAAd1bef25A7abf657",
15
+ "Incentives": {
16
+ "GlobalIncentivesExecutor": "0x9d052Ab5344F6D0a5dcf685D42906f48E6F2beaF",
17
+ "GlobalIncentivesHelper": "0x8F0d40c95047c6B09f08905C110d002E65e96C7d",
18
+ "NotifyHelperGeneric": "0xC0cE53f755feAe93Fd219b2Cd0F58a4Fd0d535Dd",
19
+ "NotifyHelperStateful": "0x99AFf7327CEb88fE408d1fB93dc3150fEa5f9A2A",
20
+ "ViewerNotifyHelperStateful": "0xb93280253E93d9CF01FbE500981792E1c577607d",
21
+ },
22
+ "Factory": {
23
+ "VaultFactory": "0x61d568C11321d12E05959203f00F19E4bd628122",
24
+ "PotPoolFactory": "0xB1E448117dF310b6090477291E57198A0b1816a8",
25
+ "MegaFactory": "0x344aECFdB8894E82178Bc45CE35ff7741b6aA527",
26
+ "UpgradableStrategyFactory": "0x9d8265676080489D68482B106620b0b7ED463EA0"
27
+ }
28
+ };
@@ -0,0 +1,96 @@
1
+ const BigNumber = require('bignumber.js');
2
+ const { time } = require("@openzeppelin/test-helpers");
3
+ BigNumber.config({DECIMAL_PLACES: 0});
4
+
5
+ let gasLogger = {};
6
+ let gasLoggerNum = {};
7
+
8
+ async function gasLog(logTo, targetPromise) {
9
+ let tx = await targetPromise;
10
+ gasUsed = tx.receipt.gasUsed;
11
+
12
+ if(gasLogger[logTo] == undefined) {
13
+ gasLogger[logTo] = gasUsed;
14
+ gasLoggerNum[logTo] = 1;
15
+ }
16
+ else {
17
+ gasLogger[logTo] = (gasLogger[logTo])/(gasLoggerNum[logTo]+1) + gasUsed/(gasLoggerNum[logTo]+1);
18
+ gasLoggerNum[logTo]++;
19
+ }
20
+ }
21
+
22
+ async function printGasLog() {
23
+ console.log(gasLogger);
24
+ }
25
+
26
+ async function advanceNBlock (n) {
27
+ let startingBlock = await time.latestBlock();
28
+ await time.increase(12 * Math.round(n));
29
+ let endBlock = startingBlock.addn(n);
30
+ await time.advanceBlockTo(endBlock);
31
+ }
32
+ async function waitHours (n) {
33
+ await time.increase(n * 3600 + 1);
34
+ let startingBlock = await time.latestBlock();
35
+ await time.advanceBlockTo(startingBlock.addn(1));
36
+ };
37
+
38
+ async function waitTime (n) {
39
+ await time.increase(n);
40
+ let startingBlock = await time.latestBlock();
41
+ await time.advanceBlockTo(startingBlock.addn(1));
42
+ };
43
+
44
+ function assertBNEq(a, b){
45
+ let _a = new BigNumber(a);
46
+ let _b = new BigNumber(b);
47
+ let msg = _a.toFixed() + " != " + _b.toFixed();
48
+ assert.equal(_a.eq(_b), true, msg);
49
+ }
50
+
51
+ function assertApproxBNEq(a, b, c){
52
+ let _a = new BigNumber(a).div(c);
53
+ let _b = new BigNumber(b).div(c);
54
+ let msg = _a.toFixed() + " != " + _b.toFixed();
55
+ assert.equal(_a.eq(_b), true, msg);
56
+ }
57
+
58
+ function assertBNGt(a, b){
59
+ let _a = new BigNumber(a);
60
+ let _b = new BigNumber(b);
61
+ let msg = _a.toFixed() + " is not greater than " + _b.toFixed();
62
+ assert.equal(_a.gt(_b), true, msg);
63
+ }
64
+
65
+ function assertBNGte(a, b){
66
+ let _a = new BigNumber(a);
67
+ let _b = new BigNumber(b);
68
+ let msg = _a.toFixed() + " is not greater than " + _b.toFixed();
69
+ assert.equal(_a.gte(_b), true, msg);
70
+ }
71
+
72
+ function assertNEqBN(a, b){
73
+ let _a = new BigNumber(a);
74
+ let _b = new BigNumber(b);
75
+ assert.equal(_a.eq(_b), false);
76
+ }
77
+
78
+ async function inBNfixed(a) {
79
+ return await (new BigNumber(a)).toFixed();
80
+ }
81
+
82
+ module.exports = {
83
+ gasLogger,
84
+ gasLoggerNum,
85
+ gasLog,
86
+ printGasLog,
87
+ advanceNBlock,
88
+ assertBNEq,
89
+ assertApproxBNEq,
90
+ assertBNGt,
91
+ assertNEqBN,
92
+ inBNfixed,
93
+ waitHours,
94
+ waitTime,
95
+ assertBNGte,
96
+ };
@@ -0,0 +1,248 @@
1
+ const makeVault = require("./make-vault.js");
2
+ const addresses = require("../test-config.js");
3
+ const IController = artifacts.require("IController");
4
+ const IRewardForwarder = artifacts.require("IRewardForwarder");
5
+ const Vault = artifacts.require("VaultV2");
6
+ const GMXVault = artifacts.require("VaultV2GMX");
7
+ const IUpgradeableStrategy = artifacts.require("IUpgradeableStrategy");
8
+ const ILiquidatorRegistry = artifacts.require("IUniversalLiquidatorRegistry");
9
+ const IDex = artifacts.require("IDex");
10
+ const IBalDex = artifacts.require("IBalDex");
11
+
12
+ const Utils = require("./Utils.js");
13
+
14
+ async function impersonates(targetAccounts){
15
+ console.log("Impersonating...");
16
+ for(i = 0; i < targetAccounts.length ; i++){
17
+ console.log(targetAccounts[i]);
18
+ await hre.network.provider.request({
19
+ method: "hardhat_impersonateAccount",
20
+ params: [
21
+ targetAccounts[i]
22
+ ]
23
+ });
24
+ }
25
+ }
26
+
27
+ async function setupCoreProtocol(config) {
28
+ // Set vault (or Deploy new vault), underlying, underlying Whale,
29
+ // amount the underlying whale should send to farmers
30
+ if(config.existingVaultAddress != null){
31
+ vault = await Vault.at(config.existingVaultAddress);
32
+ console.log("Fetching Vault at: ", vault.address);
33
+ } else {
34
+ let implAddress, useGMX
35
+ if (config.useGMXVault) {
36
+ vaultImpl = await GMXVault.new();
37
+ implAddress = vaultImpl.address;
38
+ useGMX = true;
39
+ } else {
40
+ implAddress = config.vaultImplementationOverride || addresses.VaultImplementationV2;
41
+ useGMX = false;
42
+ }
43
+ vault = await makeVault(implAddress, useGMX, addresses.Storage, config.underlying.address, 100, 100, {
44
+ from: config.governance,
45
+ });
46
+ console.log("New Vault Deployed: ", vault.address);
47
+ }
48
+
49
+ controller = await IController.at(addresses.Controller);
50
+ feeRewardForwarder = await IRewardForwarder.at(await controller.rewardForwarder());
51
+
52
+
53
+ if (config.feeRewardForwarder) {/*
54
+ const FeeRewardForwarder = artifacts.require("FeeRewardForwarder");
55
+ const feeRewardForwarder = await FeeRewardForwarder.new(
56
+ addresses.Storage,
57
+ addresses.FARM,
58
+ addresses.miFARM,
59
+ addresses.UniversalLiquidatorRegistry
60
+ );
61
+
62
+ config.feeRewardForwarder = feeRewardForwarder.address;*/
63
+ console.log("Setting up a custom fee reward forwarder...");
64
+ await controller.setRewardForwarder(
65
+ config.feeRewardForwarder,
66
+ { from: config.governance }
67
+ );
68
+
69
+ const NoMintRewardPool = artifacts.require("NoMintRewardPool");
70
+ const farmRewardPool = await NoMintRewardPool.at("0x8f5adC58b32D4e5Ca02EAC0E293D35855999436C");
71
+ await farmRewardPool.setRewardDistribution(config.feeRewardForwarder, {from: config.governance});
72
+
73
+ console.log("Done setting up fee reward forwarder!");
74
+ }
75
+
76
+ let rewardPool = null;
77
+
78
+ if (!config.rewardPoolConfig) {
79
+ config.rewardPoolConfig = {};
80
+ }
81
+ // if reward pool is required, then deploy it
82
+ if(config.rewardPool != null && config.existingRewardPoolAddress == null) {
83
+ const rewardTokens = config.rewardPoolConfig.rewardTokens || [addresses.FARM];
84
+ const rewardDistributions = [config.governance];
85
+ if (config.feeRewardForwarder) {
86
+ rewardDistributions.push(config.feeRewardForwarder);
87
+ }
88
+
89
+ if (config.rewardPoolConfig.type === 'PotPool') {
90
+ const PotPool = artifacts.require("PotPool");
91
+ console.log("reward pool needs to be deployed");
92
+ rewardPool = await PotPool.new(
93
+ rewardTokens,
94
+ vault.address,
95
+ 64800,
96
+ rewardDistributions,
97
+ addresses.Storage,
98
+ "fPool",
99
+ "fPool",
100
+ 18,
101
+ {from: config.governance }
102
+ );
103
+ console.log("New PotPool deployed: ", rewardPool.address);
104
+ } else {
105
+ const NoMintRewardPool = artifacts.require("NoMintRewardPool");
106
+ console.log("reward pool needs to be deployed");
107
+ rewardPool = await NoMintRewardPool.new(
108
+ rewardTokens[0],
109
+ vault.address,
110
+ 64800,
111
+ rewardDistributions,
112
+ addresses.Storage,
113
+ "0x0000000000000000000000000000000000000000",
114
+ "0x0000000000000000000000000000000000000000",
115
+ {from: config.governance }
116
+ );
117
+ console.log("New NoMintRewardPool deployed: ", rewardPool.address);
118
+ }
119
+ } else if(config.existingRewardPoolAddress != null) {
120
+ const PotPool = artifacts.require("PotPool");
121
+ rewardPool = await PotPool.at(config.existingRewardPoolAddress);
122
+ console.log("Fetching Reward Pool deployed: ", rewardPool.address);
123
+ }
124
+
125
+ let universalLiquidatorRegistry = await ILiquidatorRegistry.at(addresses.UniversalLiquidatorRegistry);
126
+
127
+ // set liquidation paths
128
+ if(config.liquidation) {
129
+ for (i=0;i<config.liquidation.length;i++) {
130
+ dex = Object.keys(config.liquidation[i])[0];
131
+ await universalLiquidatorRegistry.setPath(
132
+ web3.utils.keccak256(dex),
133
+ config.liquidation[i][dex],
134
+ {from: config.ULOwner}
135
+ );
136
+ }
137
+ }
138
+
139
+ if(config.uniV3Fee) {
140
+ const uniV3Dex = await IDex.at("0x357F2E6Cd64A1fD4525e4eC22d7635115C9Ca3cb");
141
+ for (i=0;i<config.uniV3Fee.length;i++) {
142
+ await uniV3Dex.setFee(config.uniV3Fee[i][0], config.uniV3Fee[i][1], config.uniV3Fee[i][2], {from: config.ULOwner})
143
+ }
144
+ }
145
+ if(config.pancakeV3Fee) {
146
+ const uniV3Dex = await IDex.at("0x7F60C26a34D2B9D99D8DeFD321C32fd717bEB8A5");
147
+ for (i=0;i<config.pancakeV3Fee.length;i++) {
148
+ await uniV3Dex.setFee(config.pancakeV3Fee[i][0], config.pancakeV3Fee[i][1], config.pancakeV3Fee[i][2], {from: config.ULOwner})
149
+ }
150
+ }
151
+ if(config.curveSetup) {
152
+ const curveDex = await IDex.at("0xdeb935422497c8bD46B84e066c742d3A21BEe06b");
153
+ for (i=0;i<config.curveSetup.length;i++) {
154
+ await curveDex.pairSetup(config.curveSetup[i][0], config.curveSetup[i][1], config.curveSetup[i][2], config.curveSetup[i][3], {from: config.ULOwner})
155
+ }
156
+ }
157
+ if(config.balancerPool) {
158
+ const dex = await IBalDex.at("0x48aC1856D6B96ae9F29107a3A0Be825BFEF58014");
159
+ for (i=0;i<config.balancerPool.length;i++) {
160
+ await dex.setPool(config.balancerPool[i][0], config.balancerPool[i][1], config.balancerPool[i][2], {from: config.ULOwner})
161
+ }
162
+ }
163
+
164
+ // default arguments are storage and vault addresses
165
+ config.strategyArgs = config.strategyArgs || [
166
+ addresses.Storage,
167
+ vault.address
168
+ ];
169
+
170
+ for(i = 0; i < config.strategyArgs.length ; i++){
171
+ if(config.strategyArgs[i] == "storageAddr") {
172
+ config.strategyArgs[i] = addresses.Storage;
173
+ } else if(config.strategyArgs[i] == "vaultAddr") {
174
+ config.strategyArgs[i] = vault.address;
175
+ } else if(config.strategyArgs[i] == "poolAddr" ){
176
+ config.strategyArgs[i] = rewardPool.address;
177
+ } else if(config.strategyArgs[i] == "universalLiquidatorRegistryAddr"){
178
+ config.strategyArgs[i] = universalLiquidatorRegistry.address;
179
+ }
180
+ }
181
+
182
+ let strategyImpl = null;
183
+
184
+ if (!config.strategyArtifactIsUpgradable) {
185
+ strategy = await config.strategyArtifact.new(
186
+ ...config.strategyArgs,
187
+ { from: config.governance }
188
+ );
189
+ } else {
190
+ strategyImpl = await config.strategyArtifact.new();
191
+ const StrategyProxy = artifacts.require("StrategyProxy");
192
+
193
+ const strategyProxy = await StrategyProxy.new(strategyImpl.address);
194
+ strategy = await config.strategyArtifact.at(strategyProxy.address);
195
+ await strategy.initializeStrategy(
196
+ ...config.strategyArgs,
197
+ { from: config.governance }
198
+ );
199
+ }
200
+
201
+ console.log("Strategy Deployed: ", strategy.address);
202
+
203
+ if (config.liquidationPath) {
204
+ const path = config.liquidationPath.path;
205
+ const router = addresses[config.liquidationPath.router];
206
+ await feeRewardForwarder.setConversionPath(
207
+ path[0],
208
+ path[path.length - 1],
209
+ path,
210
+ router,
211
+ {from: config.governance}
212
+ );
213
+ }
214
+
215
+ if (config.announceStrategy === true) {
216
+ // Announce switch, time pass, switch to strategy
217
+ await vault.announceStrategyUpdate(strategy.address, { from: config.governance });
218
+ console.log("Strategy switch announced. Waiting...");
219
+ await Utils.waitHours(13);
220
+ await vault.setStrategy(strategy.address, { from: config.governance });
221
+ await vault.setVaultFractionToInvest(100, 100, { from: config.governance });
222
+ console.log("Strategy switch completed.");
223
+ } else if (config.upgradeStrategy === true) {
224
+ // Announce upgrade, time pass, upgrade the strategy
225
+ const strategyAsUpgradable = await IUpgradeableStrategy.at(await vault.strategy());
226
+ await strategyAsUpgradable.scheduleUpgrade(strategyImpl.address, { from: config.governance });
227
+ console.log("Upgrade scheduled. Waiting...");
228
+ await Utils.waitHours(13);
229
+ await strategyAsUpgradable.upgrade({ from: config.governance });
230
+ await vault.setVaultFractionToInvest(100, 100, { from: config.governance });
231
+ strategy = await config.strategyArtifact.at(await vault.strategy());
232
+ console.log("Strategy upgrade completed.");
233
+ } else {
234
+ await vault.setStrategy(strategy.address, {from: config.governance});
235
+ }
236
+ return [controller, vault, strategy, rewardPool];
237
+ }
238
+
239
+ async function depositVault(_farmer, _underlying, _vault, _amount) {
240
+ await _underlying.approve(_vault.address, _amount, { from: _farmer });
241
+ await _vault.deposit(_amount, _farmer, { from: _farmer });
242
+ }
243
+
244
+ module.exports = {
245
+ impersonates,
246
+ setupCoreProtocol,
247
+ depositVault
248
+ };
@@ -0,0 +1,16 @@
1
+ const Vault = artifacts.require("VaultV2");
2
+ const GMXVault = artifacts.require("VaultV2GMX");
3
+ const VaultProxy = artifacts.require("VaultProxy");
4
+
5
+ module.exports = async function(implementationAddress, useGMX, ...args) {
6
+ const fromParameter = args[args.length - 1]; // corresponds to {from: governance}
7
+ const vaultAsProxy = await VaultProxy.new(implementationAddress, fromParameter);
8
+ let vault
9
+ if (useGMX) {
10
+ vault = await GMXVault.at(vaultAsProxy.address);
11
+ } else {
12
+ vault = await Vault.at(vaultAsProxy.address)
13
+ }
14
+ await vault.initializeVault(...args);
15
+ return vault;
16
+ };