@gooddollar/goodprotocol 1.0.8 → 1.0.11

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.
Files changed (123) hide show
  1. package/artifacts/contracts/DAOStackInterfaces.sol/Avatar.dbg.json +1 -1
  2. package/artifacts/contracts/DAOStackInterfaces.sol/Controller.dbg.json +1 -1
  3. package/artifacts/contracts/DAOStackInterfaces.sol/GlobalConstraintInterface.dbg.json +1 -1
  4. package/artifacts/contracts/DAOStackInterfaces.sol/IntVoteInterface.dbg.json +1 -1
  5. package/artifacts/contracts/DAOStackInterfaces.sol/ReputationInterface.dbg.json +1 -1
  6. package/artifacts/contracts/DAOStackInterfaces.sol/SchemeRegistrar.dbg.json +1 -1
  7. package/artifacts/contracts/Interfaces.sol/AggregatorV3Interface.dbg.json +1 -1
  8. package/artifacts/contracts/Interfaces.sol/ERC20.dbg.json +1 -1
  9. package/artifacts/contracts/Interfaces.sol/IAaveIncentivesController.dbg.json +1 -1
  10. package/artifacts/contracts/Interfaces.sol/IAdminWallet.dbg.json +1 -1
  11. package/artifacts/contracts/Interfaces.sol/IDonationStaking.dbg.json +1 -1
  12. package/artifacts/contracts/Interfaces.sol/IERC2917.dbg.json +1 -1
  13. package/artifacts/contracts/Interfaces.sol/IFirstClaimPool.dbg.json +1 -1
  14. package/artifacts/contracts/Interfaces.sol/IGoodDollar.dbg.json +1 -1
  15. package/artifacts/contracts/Interfaces.sol/IGoodStaking.dbg.json +1 -1
  16. package/artifacts/contracts/Interfaces.sol/IHasRouter.dbg.json +1 -1
  17. package/artifacts/contracts/Interfaces.sol/IIdentity.dbg.json +1 -1
  18. package/artifacts/contracts/Interfaces.sol/ILendingPool.dbg.json +1 -1
  19. package/artifacts/contracts/Interfaces.sol/INameService.dbg.json +1 -1
  20. package/artifacts/contracts/Interfaces.sol/IUBIScheme.dbg.json +1 -1
  21. package/artifacts/contracts/Interfaces.sol/ProxyAdmin.dbg.json +1 -1
  22. package/artifacts/contracts/Interfaces.sol/Reserve.dbg.json +1 -1
  23. package/artifacts/contracts/Interfaces.sol/Staking.dbg.json +1 -1
  24. package/artifacts/contracts/Interfaces.sol/Uniswap.dbg.json +1 -1
  25. package/artifacts/contracts/Interfaces.sol/UniswapFactory.dbg.json +1 -1
  26. package/artifacts/contracts/Interfaces.sol/UniswapPair.dbg.json +1 -1
  27. package/artifacts/contracts/Interfaces.sol/cERC20.dbg.json +1 -1
  28. package/artifacts/contracts/governance/ClaimersDistribution.sol/ClaimersDistribution.dbg.json +1 -1
  29. package/artifacts/contracts/governance/CompoundVotingMachine.sol/CompoundVotingMachine.dbg.json +1 -1
  30. package/artifacts/contracts/governance/GReputation.sol/GReputation.dbg.json +1 -1
  31. package/artifacts/contracts/governance/GovarnanceStaking.sol/GovernanceStaking.dbg.json +1 -1
  32. package/artifacts/contracts/governance/MultiBaseGovernanceShareField.sol/MultiBaseGovernanceShareField.dbg.json +1 -1
  33. package/artifacts/contracts/governance/Reputation.sol/Reputation.dbg.json +1 -1
  34. package/artifacts/contracts/governance/StakersDistribution.sol/StakersDistribution.dbg.json +1 -1
  35. package/artifacts/contracts/governance/StakersDistribution.sol/StakersDistribution.json +2 -2
  36. package/artifacts/contracts/mocks/AaveMock.sol/AaveMock.dbg.json +1 -1
  37. package/artifacts/contracts/mocks/DAIMock.sol/DAIMock.dbg.json +1 -1
  38. package/artifacts/contracts/mocks/DecimalsMock.sol/DecimalsMock.dbg.json +1 -1
  39. package/artifacts/contracts/mocks/GoodCompoundStakingTest.sol/GoodCompoundStakingTest.dbg.json +1 -1
  40. package/artifacts/contracts/mocks/GoodCompoundStakingTest.sol/GoodCompoundStakingTest.json +6 -6
  41. package/artifacts/contracts/mocks/GoodFundManagerTest.sol/GoodFundManagerTest.dbg.json +1 -1
  42. package/artifacts/contracts/mocks/IncentiveControllerMock.sol/IncentiveControllerMock.dbg.json +1 -1
  43. package/artifacts/contracts/mocks/LendingPoolMock.sol/LendingPoolMock.dbg.json +1 -1
  44. package/artifacts/contracts/mocks/OverMintTester.sol/OverMintTester.dbg.json +1 -1
  45. package/artifacts/contracts/mocks/OverMintTesterRegularStake.sol/OverMintTesterRegularStake.dbg.json +1 -1
  46. package/artifacts/contracts/mocks/OverMintTesterRegularStake.sol/OverMintTesterRegularStake.json +2 -2
  47. package/artifacts/contracts/mocks/SixteenDecimalsTokenMock.sol/SixteenDecimalsTokenMock.dbg.json +1 -1
  48. package/artifacts/contracts/mocks/SwapHelperTest.sol/SwapHelperTest.dbg.json +1 -1
  49. package/artifacts/contracts/mocks/TwentyDecimalsTokenMock.sol/TwentyDecimalsTokenMock.dbg.json +1 -1
  50. package/artifacts/contracts/mocks/UpgradableMocks.sol/UpgradableMock.dbg.json +1 -1
  51. package/artifacts/contracts/mocks/UpgradableMocks.sol/UpgradableMock2.dbg.json +1 -1
  52. package/artifacts/contracts/mocks/UsdcMock.sol/USDCMock.dbg.json +1 -1
  53. package/artifacts/contracts/mocks/cBATMock.sol/cBATMock.dbg.json +1 -1
  54. package/artifacts/contracts/mocks/cDAILowWorthMock.sol/cDAILowWorthMock.dbg.json +1 -1
  55. package/artifacts/contracts/mocks/cDAIMock.sol/cDAIMock.dbg.json +1 -1
  56. package/artifacts/contracts/mocks/cDAINonMintableMock.sol/cDAINonMintableMock.dbg.json +1 -1
  57. package/artifacts/contracts/mocks/cDecimalsMock.sol/cDecimalsMock.dbg.json +1 -1
  58. package/artifacts/contracts/mocks/cSDTMock.sol/cSDTMock.dbg.json +1 -1
  59. package/artifacts/contracts/mocks/cUSDCMock.sol/cUSDCMock.dbg.json +1 -1
  60. package/artifacts/contracts/reserve/ExchangeHelper.sol/ExchangeHelper.dbg.json +1 -1
  61. package/artifacts/contracts/reserve/GoodMarketMaker.sol/GoodMarketMaker.dbg.json +1 -1
  62. package/artifacts/contracts/reserve/GoodReserveCDai.sol/ContributionCalc.dbg.json +1 -1
  63. package/artifacts/contracts/reserve/GoodReserveCDai.sol/GoodReserveCDai.dbg.json +1 -1
  64. package/artifacts/contracts/staking/BaseShareField.sol/BaseShareField.dbg.json +1 -1
  65. package/artifacts/contracts/staking/BaseShareFieldV2.sol/BaseShareFieldV2.dbg.json +4 -0
  66. package/artifacts/contracts/staking/BaseShareFieldV2.sol/BaseShareFieldV2.json +200 -0
  67. package/artifacts/contracts/staking/DonationsStaking.sol/DonationsStaking.dbg.json +1 -1
  68. package/artifacts/contracts/staking/DonationsStaking.sol/DonationsStaking.json +2 -2
  69. package/artifacts/contracts/staking/GoodFundManager.sol/GoodFundManager.dbg.json +1 -1
  70. package/artifacts/contracts/staking/SimpleStaking.sol/SimpleStaking.dbg.json +1 -1
  71. package/artifacts/contracts/staking/SimpleStakingV2.sol/SimpleStakingV2.dbg.json +4 -0
  72. package/artifacts/contracts/staking/SimpleStakingV2.sol/SimpleStakingV2.json +958 -0
  73. package/artifacts/contracts/staking/UniswapV2SwapHelper.sol/UniswapV2SwapHelper.dbg.json +1 -1
  74. package/artifacts/contracts/staking/aave/AaveStakingFactory.sol/AaveStakingFactory.dbg.json +1 -1
  75. package/artifacts/contracts/staking/aave/AaveStakingFactory.sol/AaveStakingFactory.json +65 -12
  76. package/artifacts/contracts/staking/aave/GoodAaveStaking.sol/GoodAaveStaking.dbg.json +1 -1
  77. package/artifacts/contracts/staking/aave/GoodAaveStaking.sol/GoodAaveStaking.json +4 -4
  78. package/artifacts/contracts/staking/aave/GoodAaveStakingV2.sol/GoodAaveStakingV2.dbg.json +4 -0
  79. package/artifacts/contracts/staking/aave/GoodAaveStakingV2.sol/GoodAaveStakingV2.json +1149 -0
  80. package/artifacts/contracts/staking/compound/CompoundStakingFactory.sol/CompoundStakingFactory.dbg.json +1 -1
  81. package/artifacts/contracts/staking/compound/CompoundStakingFactory.sol/CompoundStakingFactory.json +57 -14
  82. package/artifacts/contracts/staking/compound/GoodCompoundStaking.sol/GoodCompoundStaking.dbg.json +1 -1
  83. package/artifacts/contracts/staking/compound/GoodCompoundStaking.sol/GoodCompoundStaking.json +6 -6
  84. package/artifacts/contracts/staking/compound/GoodCompoundStakingV2.sol/GoodCompoundStakingV2.dbg.json +4 -0
  85. package/artifacts/contracts/staking/compound/GoodCompoundStakingV2.sol/GoodCompoundStakingV2.json +1092 -0
  86. package/artifacts/contracts/ubi/UBIScheme.sol/UBIScheme.dbg.json +1 -1
  87. package/artifacts/contracts/unaudited-foundation/FuseFaucet.sol/FuseFaucet.dbg.json +1 -1
  88. package/artifacts/contracts/unaudited-foundation/InvitesV1.sol/InvitesV1.dbg.json +1 -1
  89. package/artifacts/contracts/utils/BancorFormula.sol/BancorFormula.dbg.json +1 -1
  90. package/artifacts/contracts/utils/DAOContract.sol/DAOContract.dbg.json +1 -1
  91. package/artifacts/contracts/utils/DAOUpgradeableContract.sol/DAOUpgradeableContract.dbg.json +1 -1
  92. package/artifacts/contracts/utils/DSMath.sol/DSMath.dbg.json +1 -1
  93. package/artifacts/contracts/utils/DataTypes.sol/DataTypes.dbg.json +1 -1
  94. package/artifacts/contracts/utils/NameService.sol/NameService.dbg.json +1 -1
  95. package/artifacts/contracts/utils/ProtocolUpgrade.sol/OldMarketMaker.dbg.json +1 -1
  96. package/artifacts/contracts/utils/ProtocolUpgrade.sol/ProtocolUpgrade.dbg.json +1 -1
  97. package/artifacts/contracts/utils/ProtocolUpgradeFuse.sol/ProtocolUpgradeFuse.dbg.json +1 -1
  98. package/artifacts/contracts/utils/ReputationTestHelper.sol/ReputationTestHelper.dbg.json +1 -1
  99. package/contracts/staking/BaseShareFieldV2.sol +343 -0
  100. package/contracts/staking/SimpleStaking.sol +0 -7
  101. package/contracts/staking/SimpleStakingV2.sol +488 -0
  102. package/contracts/staking/aave/AaveStakingFactory.sol +45 -19
  103. package/contracts/staking/aave/GoodAaveStaking.sol +1 -1
  104. package/contracts/staking/aave/GoodAaveStakingV2.sol +263 -0
  105. package/contracts/staking/compound/CompoundStakingFactory.sol +41 -18
  106. package/contracts/staking/compound/GoodCompoundStaking.sol +1 -1
  107. package/contracts/staking/compound/GoodCompoundStakingV2.sol +315 -0
  108. package/package.json +1 -1
  109. package/releases/deployment.json +55 -47
  110. package/scripts/deployFullDAO.ts +1 -1
  111. package/scripts/upgradeToV2/upgradeToV2.ts +7 -3
  112. package/test/governance/StakersDistribution.test.ts +43 -14
  113. package/test/helpers.ts +6 -1
  114. package/test/staking/CompoundStakingFactory.test.ts +24 -21
  115. package/test/staking/DifferentStakingTokens.test.ts +3 -1
  116. package/test/staking/DonationsStaking.test.ts +3 -1
  117. package/test/staking/GoodAaveStakingFactory.test.ts +26 -23
  118. package/test/staking/SimpleDAIStaking.test.ts +3 -11
  119. package/test/staking/StakingRewards.test.ts +20 -14
  120. package/test/staking/SwapHelper.test.ts +4 -1
  121. package/test/staking/UsdcAaveStaking.test.ts +22 -3
  122. package/test/ubi/UBIScheme.e2e.test.ts +1 -1
  123. package/test/utils/ProtocolUpgrade.test.ts +1 -1
@@ -0,0 +1,263 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity >=0.8.0;
4
+ import "../SimpleStakingV2.sol";
5
+ import "../../Interfaces.sol";
6
+ import "../../utils/DataTypes.sol";
7
+ import "../UniswapV2SwapHelper.sol";
8
+
9
+ /**
10
+ * @title Staking contract that donates earned interest to the DAO
11
+ * allowing stakers to deposit Token
12
+ * or withdraw their stake in Token
13
+ * the contracts buy cToken and can transfer the daily interest to the DAO
14
+ */
15
+ contract GoodAaveStakingV2 is SimpleStakingV2 {
16
+ using UniswapV2SwapHelper for IHasRouter;
17
+
18
+ // Address of the TOKEN/USD oracle from chainlink
19
+ address public tokenUsdOracle;
20
+
21
+ //LendingPool of aave
22
+ ILendingPool public lendingPool;
23
+
24
+ //Address of the AaveIncentivesController
25
+ IAaveIncentivesController public incentiveController;
26
+
27
+ //address of the AAVE/USD oracle
28
+ address public aaveUSDOracle;
29
+ // Gas cost to collect interest from this staking contract
30
+ uint32 public collectInterestGasCost;
31
+ // Gas cost to claim stkAave rewards
32
+ uint32 public stkAaveClaimGasCost;
33
+
34
+ address[] public tokenToDaiSwapPath;
35
+
36
+ /**
37
+ * @param _token Token to swap DEFI token
38
+ * @param _lendingPool LendingPool address
39
+ * @param _ns Address of the NameService
40
+ * @param _tokenName Name of the staking token which will be provided to staker for their staking share
41
+ * @param _tokenSymbol Symbol of the staking token which will be provided to staker for their staking share
42
+ * @param _tokenSymbol Determines blocks to pass for 1x Multiplier
43
+ * @param _tokenUsdOracle address of the TOKEN/USD oracle
44
+ * @param _incentiveController Aave incentive controller which provides AAVE rewards
45
+ * @param _aaveUSDOracle address of the AAVE/USD oracle
46
+ */
47
+ function init(
48
+ address _token,
49
+ address _lendingPool,
50
+ INameService _ns,
51
+ string memory _tokenName,
52
+ string memory _tokenSymbol,
53
+ uint64 _maxRewardThreshold,
54
+ address _tokenUsdOracle,
55
+ IAaveIncentivesController _incentiveController,
56
+ address _aaveUSDOracle,
57
+ address[] memory _tokenToDaiSwapPath
58
+ ) public {
59
+ lendingPool = ILendingPool(_lendingPool);
60
+ DataTypes.ReserveData memory reserve = lendingPool.getReserveData(_token);
61
+ initialize(
62
+ _token,
63
+ reserve.aTokenAddress,
64
+ _ns,
65
+ _tokenName,
66
+ _tokenSymbol,
67
+ _maxRewardThreshold
68
+ );
69
+ require(
70
+ _tokenToDaiSwapPath[0] == _token &&
71
+ _tokenToDaiSwapPath[_tokenToDaiSwapPath.length - 1] ==
72
+ nameService.getAddress("DAI"),
73
+ "invalid _tokenToDaiSwapPath"
74
+ );
75
+ tokenToDaiSwapPath = _tokenToDaiSwapPath;
76
+
77
+ //above initialize going to revert on second call, so this is safe
78
+ tokenUsdOracle = _tokenUsdOracle;
79
+ incentiveController = _incentiveController;
80
+ aaveUSDOracle = _aaveUSDOracle;
81
+ collectInterestGasCost = 250000;
82
+ stkAaveClaimGasCost = 50000;
83
+ _approveTokens();
84
+ }
85
+
86
+ /**
87
+ * @dev stake some Token
88
+ * @param _amount of Token to stake
89
+ */
90
+ function mintInterestToken(uint256 _amount) internal override {
91
+ lendingPool.deposit(address(token), _amount, address(this), 0);
92
+ }
93
+
94
+ /**
95
+ * @dev redeem Token from aave
96
+ * @param _amount of token to redeem in Token
97
+ */
98
+ function redeem(uint256 _amount) internal override {
99
+ uint256 withdrawnAmount = lendingPool.withdraw(
100
+ address(token),
101
+ _amount,
102
+ address(this)
103
+ );
104
+ require(withdrawnAmount > 0, "Withdrawn amount should be bigger than zero");
105
+ }
106
+
107
+ /**
108
+ * @dev Function to redeem aToken for DAI, so reserve knows how to handle it. (reserve can handle dai or cdai)
109
+ * also transfers stkaave to reserve
110
+ * @dev _amount of token in iToken
111
+ * @dev _recipient recipient of the DAI
112
+ * @return actualTokenGains amount of token redeemed for dai,
113
+ actualRewardTokenGains amount of reward token earned,
114
+ daiAmount total dai received
115
+ */
116
+ function redeemUnderlyingToDAI(uint256 _amount, address _recipient)
117
+ internal
118
+ override
119
+ returns (
120
+ uint256 actualTokenGains,
121
+ uint256 actualRewardTokenGains,
122
+ uint256 daiAmount
123
+ )
124
+ {
125
+ //out of requested interests to withdraw how much is it safe to swap
126
+ actualTokenGains = IHasRouter(this).maxSafeTokenAmount(
127
+ address(token),
128
+ tokenToDaiSwapPath[1],
129
+ _amount,
130
+ maxLiquidityPercentageSwap
131
+ );
132
+
133
+ lendingPool.withdraw(address(token), actualTokenGains, address(this));
134
+ actualTokenGains = token.balanceOf(address(this));
135
+
136
+ address[] memory tokenAddress = new address[](1);
137
+ tokenAddress[0] = address(iToken);
138
+
139
+ actualRewardTokenGains = incentiveController.claimRewards(
140
+ tokenAddress,
141
+ type(uint256).max,
142
+ avatar
143
+ );
144
+
145
+ if (actualTokenGains > 0) {
146
+ daiAmount = IHasRouter(this).swap(
147
+ tokenToDaiSwapPath,
148
+ actualTokenGains,
149
+ 0,
150
+ _recipient
151
+ );
152
+ }
153
+ }
154
+
155
+ /**
156
+ * @dev returns decimals of token.
157
+ */
158
+ function tokenDecimal() internal view override returns (uint256) {
159
+ ERC20 token = ERC20(address(token));
160
+ return uint256(token.decimals());
161
+ }
162
+
163
+ /**
164
+ * @dev returns decimals of interest token.
165
+ */
166
+ function iTokenDecimal() internal view override returns (uint256) {
167
+ ERC20 aToken = ERC20(address(iToken));
168
+ return uint256(aToken.decimals());
169
+ }
170
+
171
+ /**
172
+ * @dev Function that calculates current interest gains of this staking contract
173
+ * @param _returnTokenBalanceInUSD determine return token balance of staking contract in USD
174
+ * @param _returnTokenGainsInUSD determine return token gains of staking contract in USD
175
+ * @return iTokenGains gains in iToken, tokenGains gains in token, tokenBalance current balance , balanceInUSD, tokenGainsInUSD
176
+ */
177
+ function currentGains(
178
+ bool _returnTokenBalanceInUSD,
179
+ bool _returnTokenGainsInUSD
180
+ )
181
+ public
182
+ view
183
+ override
184
+ returns (
185
+ uint256 iTokenGains,
186
+ uint256 tokenGains,
187
+ uint256 tokenBalance,
188
+ uint256 balanceInUSD,
189
+ uint256 tokenGainsInUSD
190
+ )
191
+ {
192
+ ERC20 aToken = ERC20(address(iToken));
193
+ tokenBalance = aToken.balanceOf(address(this));
194
+ balanceInUSD = _returnTokenBalanceInUSD
195
+ ? getTokenValueInUSD(tokenUsdOracle, tokenBalance, token.decimals())
196
+ : 0;
197
+ address[] memory tokenAddress = new address[](1);
198
+ tokenAddress[0] = address(token);
199
+ if (tokenBalance <= totalProductivity) {
200
+ return (0, 0, tokenBalance, balanceInUSD, 0);
201
+ }
202
+ iTokenGains = tokenGains = tokenBalance - totalProductivity;
203
+
204
+ tokenGainsInUSD = _returnTokenGainsInUSD
205
+ ? getTokenValueInUSD(tokenUsdOracle, tokenGains, token.decimals())
206
+ : 0;
207
+ }
208
+
209
+ /**
210
+ * @dev Function to get interest transfer cost for this particular staking contract
211
+ */
212
+ function getGasCostForInterestTransfer()
213
+ external
214
+ view
215
+ override
216
+ returns (uint32)
217
+ {
218
+ address[] memory tokenAddress = new address[](1);
219
+ tokenAddress[0] = address(iToken);
220
+ uint256 stkAaaveBalance = incentiveController.getRewardsBalance(
221
+ tokenAddress,
222
+ address(this)
223
+ );
224
+ if (stkAaaveBalance > 0)
225
+ return collectInterestGasCost + stkAaveClaimGasCost;
226
+
227
+ return collectInterestGasCost;
228
+ }
229
+
230
+ /**
231
+ * @dev Set Gas cost to interest collection for this contract
232
+ * @param _collectInterestGasCost Gas cost to collect interest
233
+ * @param _rewardTokenCollectCost gas cost to collect reward tokens
234
+ */
235
+ function setcollectInterestGasCostParams(
236
+ uint32 _collectInterestGasCost,
237
+ uint32 _rewardTokenCollectCost
238
+ ) external {
239
+ _onlyAvatar();
240
+ collectInterestGasCost = _collectInterestGasCost;
241
+ stkAaveClaimGasCost = _rewardTokenCollectCost;
242
+ }
243
+
244
+ /**
245
+ * @dev Calculates worth of given amount of iToken in Token
246
+ * @param _amount Amount of token to calculate worth in Token
247
+ * @return Worth of given amount of token in Token
248
+ */
249
+ function iTokenWorthInToken(uint256 _amount)
250
+ internal
251
+ view
252
+ override
253
+ returns (uint256)
254
+ {
255
+ return _amount; // since aToken is peg to Token 1:1 return exact amount
256
+ }
257
+
258
+ function _approveTokens() internal {
259
+ address uniswapRouter = nameService.getAddress("UNISWAP_ROUTER");
260
+ token.approve(uniswapRouter, type(uint256).max);
261
+ token.approve(address(lendingPool), type(uint256).max); // approve the transfers to defi protocol as much as possible in order to save gas
262
+ }
263
+ }
@@ -2,7 +2,7 @@
2
2
 
3
3
  pragma solidity >=0.8.0;
4
4
  import "@openzeppelin/contracts-upgradeable/proxy/ClonesUpgradeable.sol";
5
- import "./GoodCompoundStaking.sol";
5
+ import "./GoodCompoundStakingV2.sol";
6
6
  import "../../Interfaces.sol";
7
7
 
8
8
  /**
@@ -14,23 +14,44 @@ import "../../Interfaces.sol";
14
14
  contract CompoundStakingFactory {
15
15
  using ClonesUpgradeable for address;
16
16
 
17
- address impl = address(new GoodCompoundStaking());
17
+ address public impl = address(new GoodCompoundStakingV2());
18
18
 
19
- event Deployed(address proxy, address cToken);
19
+ event Deployed(address proxy, address cToken, address impl);
20
20
 
21
- function clone(cERC20 cToken, bytes32 paramsHash)
22
- public
23
- returns (GoodCompoundStaking)
24
- {
25
- address deployed = address(impl).cloneDeterministic(
21
+ function clone(
22
+ address _impl,
23
+ cERC20 cToken,
24
+ bytes32 paramsHash
25
+ ) internal returns (GoodCompoundStakingV2) {
26
+ address deployed = address(_impl).cloneDeterministic(
26
27
  keccak256(abi.encodePacked(address(cToken), paramsHash))
27
28
  );
28
- emit Deployed(deployed, address(cToken));
29
- return GoodCompoundStaking(deployed);
29
+ emit Deployed(deployed, address(cToken), _impl);
30
+ return GoodCompoundStakingV2(deployed);
31
+ }
32
+
33
+ function cloneAndInit(
34
+ cERC20 _cToken,
35
+ INameService _ns,
36
+ uint64 _maxRewardThreshold,
37
+ address _tokenUsdOracle,
38
+ address _compUsdOracle,
39
+ address[] memory _tokenToDaiSwapPath
40
+ ) public {
41
+ cloneAndInit(
42
+ impl,
43
+ _cToken,
44
+ _ns,
45
+ _maxRewardThreshold,
46
+ _tokenUsdOracle,
47
+ _compUsdOracle,
48
+ _tokenToDaiSwapPath
49
+ );
30
50
  }
31
51
 
32
52
  /**
33
53
  @dev Function to clone Staking contract and initialize new one with new ctoken
54
+ @param _impl address of contract to clone
34
55
  @param cToken Staking cToken to use in staking contract
35
56
  @param _ns NameService that holds whole necessary addresses
36
57
  @param _maxRewardThreshold Block numbers that need to pass in order to user would get their rewards with 1x multiplier instead of 0.5x
@@ -38,6 +59,7 @@ contract CompoundStakingFactory {
38
59
  @param _compUsdOracle address of the AAVE/USD oracle
39
60
  */
40
61
  function cloneAndInit(
62
+ address _impl,
41
63
  cERC20 cToken,
42
64
  INameService _ns,
43
65
  uint64 _maxRewardThreshold,
@@ -45,7 +67,8 @@ contract CompoundStakingFactory {
45
67
  address _compUsdOracle,
46
68
  address[] memory _tokenToDaiSwapPath
47
69
  ) public {
48
- GoodCompoundStaking deployed = clone(
70
+ GoodCompoundStakingV2 deployed = clone(
71
+ _impl,
49
72
  cToken,
50
73
  keccak256(
51
74
  abi.encodePacked(
@@ -60,7 +83,7 @@ contract CompoundStakingFactory {
60
83
  cToken.underlying(),
61
84
  address(cToken),
62
85
  _ns,
63
- string(abi.encodePacked("GoodCompoundStaking ", cToken.name())),
86
+ string(abi.encodePacked("GoodCompoundStakingV2 ", cToken.name())),
64
87
  string(abi.encodePacked("g", cToken.symbol())),
65
88
  _maxRewardThreshold,
66
89
  _tokenUsdOracle,
@@ -69,13 +92,13 @@ contract CompoundStakingFactory {
69
92
  );
70
93
  }
71
94
 
72
- function predictAddress(cERC20 cToken, bytes32 paramsHash)
73
- public
74
- view
75
- returns (address)
76
- {
95
+ function predictAddress(
96
+ address _impl,
97
+ cERC20 cToken,
98
+ bytes32 paramsHash
99
+ ) public view returns (address) {
77
100
  return
78
- address(impl).predictDeterministicAddress(
101
+ address(_impl).predictDeterministicAddress(
79
102
  keccak256(abi.encodePacked(address(cToken), paramsHash))
80
103
  );
81
104
  }
@@ -315,7 +315,7 @@ contract GoodCompoundStaking is SimpleStaking {
315
315
  compCollectGasCost = _rewardTokenCollectCost;
316
316
  }
317
317
 
318
- function _approveTokens() internal override {
318
+ function _approveTokens() internal {
319
319
  address uniswapRouter = address(uniswapContract);
320
320
  comp.approve(uniswapRouter, type(uint256).max);
321
321
  token.approve(uniswapRouter, type(uint256).max);
@@ -0,0 +1,315 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity >=0.8.0;
4
+ import "../SimpleStakingV2.sol";
5
+ import "../../Interfaces.sol";
6
+ import "../UniswapV2SwapHelper.sol";
7
+
8
+ /**
9
+ * @title Staking contract that donates earned interest to the DAO
10
+ * allowing stakers to deposit Token
11
+ * or withdraw their stake in Token
12
+ * the contracts buy cToken and can transfer the daily interest to the DAO
13
+ */
14
+ contract GoodCompoundStakingV2 is SimpleStakingV2 {
15
+ using UniswapV2SwapHelper for IHasRouter;
16
+
17
+ // Address of the TOKEN/USD oracle from chainlink
18
+ address tokenUsdOracle;
19
+ //Address of the COMP/USD oracle from chianlink
20
+ address compUsdOracle;
21
+
22
+ // Gas cost to collect interest from this staking contract
23
+ uint32 collectInterestGasCost;
24
+ // Gas cost to collect COMP rewards
25
+ uint32 compCollectGasCost;
26
+
27
+ address[] tokenToDaiSwapPath;
28
+
29
+ ERC20 comp;
30
+
31
+ Uniswap uniswapContract;
32
+
33
+ function getSettings()
34
+ external
35
+ view
36
+ returns (uint32 _collectInterestGasCost, uint32 _compCollectGasCost)
37
+ {
38
+ return (collectInterestGasCost, compCollectGasCost);
39
+ }
40
+
41
+ /**
42
+ * @param _token Token to swap DEFI token
43
+ * @param _iToken DEFI token address
44
+ * @param _ns Address of the NameService
45
+ * @param _tokenName Name of the staking token which will be provided to staker for their staking share
46
+ * @param _tokenSymbol Symbol of the staking token which will be provided to staker for their staking share
47
+ * @param _maxRewardThreshold Determines blocks to pass for 1x Multiplier
48
+ * @param _tokenUsdOracle address of the TOKEN/USD oracle
49
+ * @param _compUsdOracle address of the COMP/USD oracle
50
+ * @param _tokenToDaiSwapPath the uniswap path to swap token to DAI, should be empty if token is DAI
51
+ */
52
+ function init(
53
+ address _token,
54
+ address _iToken,
55
+ INameService _ns,
56
+ string memory _tokenName,
57
+ string memory _tokenSymbol,
58
+ uint64 _maxRewardThreshold,
59
+ address _tokenUsdOracle,
60
+ address _compUsdOracle,
61
+ address[] memory _tokenToDaiSwapPath
62
+ ) public {
63
+ initialize(
64
+ _token,
65
+ _iToken,
66
+ _ns,
67
+ _tokenName,
68
+ _tokenSymbol,
69
+ _maxRewardThreshold
70
+ );
71
+
72
+ address dai = nameService.getAddress("DAI");
73
+ require(
74
+ _token == dai ||
75
+ (_tokenToDaiSwapPath[0] == _token &&
76
+ _tokenToDaiSwapPath[_tokenToDaiSwapPath.length - 1] == dai),
77
+ "path"
78
+ );
79
+
80
+ //above initialize going to revert on second call, so this is safe
81
+ compUsdOracle = _compUsdOracle;
82
+ tokenUsdOracle = _tokenUsdOracle;
83
+ tokenToDaiSwapPath = _tokenToDaiSwapPath;
84
+ comp = ERC20(nameService.getAddress("COMP"));
85
+ uniswapContract = Uniswap(nameService.getAddress("UNISWAP_ROUTER"));
86
+ collectInterestGasCost = 250000;
87
+ compCollectGasCost = 150000;
88
+ comp.approve(address(uniswapContract), type(uint256).max);
89
+ token.approve(address(uniswapContract), type(uint256).max);
90
+ token.approve(address(iToken), type(uint256).max); // approve the transfers to defi protocol as much as possible in order to save gas
91
+ }
92
+
93
+ /**
94
+ * @dev stake some Token
95
+ * @param _amount of Token to stake
96
+ */
97
+ function mintInterestToken(uint256 _amount) internal override {
98
+ require(cERC20(address(iToken)).mint(_amount) == 0, "minting");
99
+ }
100
+
101
+ /**
102
+ * @dev redeem Token from compound
103
+ * @param _amount of token to redeem in Token
104
+ */
105
+ function redeem(uint256 _amount) internal override {
106
+ require(cERC20(address(iToken)).redeemUnderlying(_amount) == 0, "redeem");
107
+ }
108
+
109
+ /**
110
+ * @dev Function to redeem cToken + reward COMP for DAI, so reserve knows how to handle it. (reserve can handle dai or cdai)
111
+ * @dev _amount of token in iToken
112
+ * @dev _recipient recipient of the DAI
113
+ * @return actualTokenGains amount of token redeemed for dai,
114
+ actualRewardTokenGains amount of reward token redeemed for dai,
115
+ daiAmount total dai received
116
+ */
117
+ function redeemUnderlyingToDAI(uint256 _amount, address _recipient)
118
+ internal
119
+ override
120
+ returns (
121
+ uint256 actualTokenGains,
122
+ uint256 actualRewardTokenGains,
123
+ uint256 daiAmount
124
+ )
125
+ {
126
+ uint256 compBalance = comp.balanceOf(address(this));
127
+
128
+ uint256 redeemedDAI;
129
+
130
+ if (compBalance > 0) {
131
+ address[] memory compToDaiSwapPath = new address[](3);
132
+ compToDaiSwapPath[0] = address(comp);
133
+ compToDaiSwapPath[1] = uniswapContract.WETH();
134
+ compToDaiSwapPath[2] = nameService.getAddress("DAI");
135
+ actualRewardTokenGains = IHasRouter(this).maxSafeTokenAmount(
136
+ address(comp),
137
+ uniswapContract.WETH(),
138
+ compBalance,
139
+ maxLiquidityPercentageSwap
140
+ );
141
+
142
+ redeemedDAI = IHasRouter(this).swap(
143
+ compToDaiSwapPath,
144
+ actualRewardTokenGains,
145
+ 0,
146
+ _recipient
147
+ );
148
+ }
149
+ //in case of cdai there's no need to swap to DAI, we send cdai to reserve directly
150
+ actualTokenGains = iTokenWorthInToken(_amount);
151
+ if (address(iToken) == nameService.getAddress("CDAI")) {
152
+ require(iToken.transfer(_recipient, _amount), "collect");
153
+ return (
154
+ actualTokenGains,
155
+ actualRewardTokenGains,
156
+ actualTokenGains + redeemedDAI
157
+ ); // If iToken is cDAI then just return cDAI
158
+ }
159
+
160
+ //out of requested interests to withdraw how much is it safe to swap
161
+ uint256 safeAmount = IHasRouter(this).maxSafeTokenAmount(
162
+ address(token),
163
+ tokenToDaiSwapPath[1],
164
+ actualTokenGains,
165
+ maxLiquidityPercentageSwap
166
+ );
167
+
168
+ if (actualTokenGains > safeAmount) {
169
+ actualTokenGains = safeAmount;
170
+ //recalculate how much iToken to redeem
171
+ _amount = tokenWorthIniToken(actualTokenGains);
172
+ }
173
+
174
+ require(cERC20(address(iToken)).redeem(_amount) == 0, "iredeem");
175
+
176
+ actualTokenGains = token.balanceOf(address(this));
177
+
178
+ if (actualTokenGains > 0) {
179
+ redeemedDAI += IHasRouter(this).swap(
180
+ tokenToDaiSwapPath,
181
+ actualTokenGains,
182
+ 0,
183
+ _recipient
184
+ );
185
+ }
186
+
187
+ return (actualTokenGains, actualRewardTokenGains, redeemedDAI);
188
+ }
189
+
190
+ /**
191
+ * @dev returns decimals of token.
192
+ */
193
+ function tokenDecimal() internal view override returns (uint256) {
194
+ return uint256(ERC20(address(token)).decimals());
195
+ }
196
+
197
+ /**
198
+ * @dev returns decimals of interest token.
199
+ */
200
+ function iTokenDecimal() internal view override returns (uint256) {
201
+ return uint256(ERC20(address(iToken)).decimals());
202
+ }
203
+
204
+ /**
205
+ * @dev Function that calculates current interest gains of this staking contract
206
+ * @param _returnTokenBalanceInUSD determine return token balance of staking contract in USD
207
+ * @param _returnTokenGainsInUSD determine return token gains of staking contract in USD
208
+ * @return iTokenGains gains in itoken, tokenGains gains in token, tokenBalance total locked Tokens, balanceInUsd locked tokens worth in USD, tokenGainsInUSD token Gains in USD
209
+ */
210
+ function currentGains(
211
+ bool _returnTokenBalanceInUSD,
212
+ bool _returnTokenGainsInUSD
213
+ )
214
+ public
215
+ view
216
+ override
217
+ returns (
218
+ uint256 iTokenGains,
219
+ uint256 tokenGains,
220
+ uint256 tokenBalance,
221
+ uint256 balanceInUSD,
222
+ uint256 tokenGainsInUSD
223
+ )
224
+ {
225
+ tokenBalance = iTokenWorthInToken(iToken.balanceOf(address(this)));
226
+ balanceInUSD = _returnTokenBalanceInUSD
227
+ ? getTokenValueInUSD(tokenUsdOracle, tokenBalance, token.decimals())
228
+ : 0;
229
+ uint256 compValueInUSD = _returnTokenGainsInUSD
230
+ ? getTokenValueInUSD(
231
+ compUsdOracle,
232
+ comp.balanceOf(address(this)),
233
+ 18 // COMP is in 18 decimal
234
+ )
235
+ : 0;
236
+ if (tokenBalance <= totalProductivity) {
237
+ return (0, 0, tokenBalance, balanceInUSD, compValueInUSD);
238
+ }
239
+
240
+ tokenGains = tokenBalance - totalProductivity;
241
+ tokenGainsInUSD = _returnTokenGainsInUSD
242
+ ? getTokenValueInUSD(tokenUsdOracle, tokenGains, token.decimals()) +
243
+ compValueInUSD
244
+ : 0;
245
+
246
+ iTokenGains = tokenWorthIniToken(tokenGains);
247
+ }
248
+
249
+ /**
250
+ * @dev Function to get interest transfer cost for this particular staking contract
251
+ */
252
+ function getGasCostForInterestTransfer()
253
+ external
254
+ view
255
+ override
256
+ returns (uint32)
257
+ {
258
+ uint256 compBalance = comp.balanceOf(address(this));
259
+ if (compBalance > 0) return collectInterestGasCost + 200000; // need to make more check for this value
260
+
261
+ return collectInterestGasCost;
262
+ }
263
+
264
+ /**
265
+ * @dev Calculates worth of given amount of iToken in Token
266
+ * @param _amount Amount of token to calculate worth in Token
267
+ * @return Worth of given amount of token in Token
268
+ */
269
+ function iTokenWorthInToken(uint256 _amount)
270
+ internal
271
+ view
272
+ override
273
+ returns (uint256)
274
+ {
275
+ uint256 er = cERC20(address(iToken)).exchangeRateStored();
276
+ (uint256 decimalDifference, bool caseType) = tokenDecimalPrecision();
277
+ uint256 mantissa = 18 + tokenDecimal() - iTokenDecimal();
278
+ uint256 tokenWorth = caseType == true
279
+ ? (_amount * (10**decimalDifference) * er) / 10**mantissa
280
+ : ((_amount / (10**decimalDifference)) * er) / 10**mantissa; // calculation based on https://compound.finance/docs#protocol-math
281
+ return tokenWorth;
282
+ }
283
+
284
+ /**
285
+ * @dev Calculates worth of given amount of token in iToken
286
+ * @param _amount Amount of iToken to calculate worth in token
287
+ * @return tokenWorth Worth of given amount of token in iToken
288
+ */
289
+ function tokenWorthIniToken(uint256 _amount)
290
+ public
291
+ view
292
+ returns (uint256 tokenWorth)
293
+ {
294
+ uint256 er = cERC20(address(iToken)).exchangeRateStored();
295
+ (uint256 decimalDifference, bool caseType) = tokenDecimalPrecision();
296
+ uint256 mantissa = 18 + tokenDecimal() - iTokenDecimal();
297
+ tokenWorth = caseType == true
298
+ ? ((_amount / (10**decimalDifference)) * 10**mantissa) / er
299
+ : ((_amount * (10**decimalDifference)) * 10**mantissa) / er; // calculation based on https://compound.finance/docs#protocol-math
300
+ }
301
+
302
+ /**
303
+ * @dev Set Gas cost to interest collection for this contract
304
+ * @param _collectInterestGasCost Gas cost to collect interest
305
+ * @param _rewardTokenCollectCost gas cost to collect reward tokens
306
+ */
307
+ function setcollectInterestGasCostParams(
308
+ uint32 _collectInterestGasCost,
309
+ uint32 _rewardTokenCollectCost
310
+ ) external {
311
+ _onlyAvatar();
312
+ collectInterestGasCost = _collectInterestGasCost;
313
+ compCollectGasCost = _rewardTokenCollectCost;
314
+ }
315
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gooddollar/goodprotocol",
3
- "version": "1.0.8",
3
+ "version": "1.0.11",
4
4
  "description": "GoodDollar Protocol",
5
5
  "scripts": {
6
6
  "build": "scripts/build.sh deploy",