Skip to content

Commit de10452

Browse files
Proof of concept. Multiple fee handlers working with DAO And staking contracts.
Claim staker reward from multiple fee handlers. Co-authored-by: Ilan Doron <[email protected]>
1 parent 785f779 commit de10452

File tree

4 files changed

+1469
-1
lines changed

4 files changed

+1469
-1
lines changed
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
pragma solidity 0.6.6;
2+
3+
import "../../utils/Utils5.sol";
4+
import "../../utils/zeppelin/ReentrancyGuard.sol";
5+
import "../../utils/zeppelin/SafeERC20.sol";
6+
import "../../utils/zeppelin/SafeMath.sol";
7+
import "../../IKyberDao.sol";
8+
import "../../IKyberFeeHandler.sol";
9+
import "../DaoOperator.sol";
10+
11+
interface IFeeHandler is IKyberFeeHandler {
12+
function feePerPlatformWallet(address) external view returns (uint256);
13+
function rebatePerWallet(address) external view returns (uint256);
14+
}
15+
16+
17+
contract KyberFeeHandlerWrapper is DaoOperator {
18+
using SafeMath for uint256;
19+
using SafeERC20 for IERC20;
20+
21+
struct KyberFeeHandlerData {
22+
IFeeHandler kyberFeeHandler;
23+
uint256 startEpoch;
24+
}
25+
26+
IKyberDao public immutable kyberDao;
27+
IERC20[] internal supportedTokens;
28+
mapping(IERC20 => KyberFeeHandlerData[]) internal kyberFeeHandlersPerToken;
29+
address public daoSetter;
30+
31+
event FeeHandlerAdded(IERC20 token, IFeeHandler kyberFeeHandler);
32+
33+
constructor(
34+
IKyberDao _kyberDao,
35+
address _daoOperator
36+
) public DaoOperator(_daoOperator) {
37+
require(_kyberDao != IKyberDao(0), "kyberDao 0");
38+
kyberDao = _kyberDao;
39+
}
40+
41+
function addFeeHandler(IERC20 _token, IFeeHandler _kyberFeeHandler) external onlyDaoOperator {
42+
addTokenToSupportedTokensArray(_token);
43+
addFeeHandlerToKyberFeeHandlerArray(kyberFeeHandlersPerToken[_token], _kyberFeeHandler);
44+
emit FeeHandlerAdded(_token, _kyberFeeHandler);
45+
}
46+
47+
/// @dev claim from multiple feeHandlers
48+
/// @param staker staker address
49+
/// @param epoch epoch for which the staker is claiming the reward
50+
/// @param startTokenIndex index of supportedTokens to start iterating from (inclusive)
51+
/// @param endTokenIndex index of supportedTokens to end iterating to (exclusive)
52+
/// @param startKyberFeeHandlerIndex index of feeHandlerArray to start iterating from (inclusive)
53+
/// @param endKyberFeeHandlerIndex index of feeHandlerArray to end iterating to (exclusive)
54+
/// @return amounts staker reward wei / twei amount claimed from each feeHandler
55+
function claimStakerReward(
56+
address staker,
57+
uint256 epoch,
58+
uint256 startTokenIndex,
59+
uint256 endTokenIndex,
60+
uint256 startKyberFeeHandlerIndex,
61+
uint256 endKyberFeeHandlerIndex
62+
) external returns(uint256[] memory amounts) {
63+
if (
64+
startTokenIndex > endTokenIndex ||
65+
startKyberFeeHandlerIndex > endKyberFeeHandlerIndex ||
66+
supportedTokens.length == 0
67+
) {
68+
// no need to do anything
69+
return amounts;
70+
}
71+
72+
uint256 endTokenId = (endTokenIndex >= supportedTokens.length) ?
73+
supportedTokens.length : endTokenIndex;
74+
75+
for (uint256 i = startTokenIndex; i < endTokenId; i++) {
76+
KyberFeeHandlerData[] memory kyberFeeHandlerArray = kyberFeeHandlersPerToken[supportedTokens[i]];
77+
uint256 endKyberFeeHandlerId = (endKyberFeeHandlerIndex >= kyberFeeHandlerArray.length) ?
78+
kyberFeeHandlerArray.length - 1: endKyberFeeHandlerIndex - 1;
79+
require(endKyberFeeHandlerId >= startKyberFeeHandlerIndex, "bad array indices");
80+
amounts = new uint256[](endKyberFeeHandlerId - startKyberFeeHandlerIndex + 1);
81+
82+
// iteration starts from endIndex, differs from claiming reserve rebates and platform wallets
83+
for (uint256 j = endKyberFeeHandlerId; j >= startKyberFeeHandlerIndex; j--) {
84+
KyberFeeHandlerData memory kyberFeeHandlerData = kyberFeeHandlerArray[j];
85+
if (kyberFeeHandlerData.startEpoch < epoch) {
86+
amounts[j] = kyberFeeHandlerData.kyberFeeHandler.claimStakerReward(staker, epoch);
87+
break;
88+
} else if (kyberFeeHandlerData.startEpoch == epoch) {
89+
amounts[j] = kyberFeeHandlerData.kyberFeeHandler.claimStakerReward(staker, epoch);
90+
}
91+
92+
if (j == 0) {
93+
break;
94+
}
95+
}
96+
}
97+
}
98+
99+
/// @dev claim reabate per reserve wallet. called by any address
100+
/// @param rebateWallet the wallet to claim rebates for. Total accumulated rebate sent to this wallet
101+
/// @param startTokenIndex index of supportedTokens to start iterating from (inclusive)
102+
/// @param endTokenIndex index of supportedTokens to end iterating to (exclusive)
103+
/// @param startKyberFeeHandlerIndex index of feeHandlerArray to start iterating from (inclusive)
104+
/// @param endKyberFeeHandlerIndex index of feeHandlerArray to end iterating to (exclusive)
105+
/// @return amounts reserve rebate wei / twei amount claimed from each feeHandler
106+
function claimReserveRebate(
107+
address rebateWallet,
108+
uint256 startTokenIndex,
109+
uint256 endTokenIndex,
110+
uint256 startKyberFeeHandlerIndex,
111+
uint256 endKyberFeeHandlerIndex
112+
) external returns (uint256[] memory amounts)
113+
{
114+
if (
115+
startTokenIndex > endTokenIndex ||
116+
startKyberFeeHandlerIndex > endKyberFeeHandlerIndex ||
117+
supportedTokens.length == 0
118+
) {
119+
// no need to do anything
120+
return amounts;
121+
}
122+
123+
uint256 endTokenId = (endTokenIndex >= supportedTokens.length) ?
124+
supportedTokens.length : endTokenIndex;
125+
126+
for (uint256 i = startTokenIndex; i < endTokenId; i++) {
127+
KyberFeeHandlerData[] memory kyberFeeHandlerArray = kyberFeeHandlersPerToken[supportedTokens[i]];
128+
uint256 endKyberFeeHandlerId = (endKyberFeeHandlerIndex >= kyberFeeHandlerArray.length) ?
129+
kyberFeeHandlerArray.length : endKyberFeeHandlerIndex;
130+
require(endKyberFeeHandlerId >= startKyberFeeHandlerIndex, "bad array indices");
131+
amounts = new uint256[](endKyberFeeHandlerId - startKyberFeeHandlerIndex + 1);
132+
133+
for (uint256 j = startKyberFeeHandlerIndex; j < endKyberFeeHandlerId; j++) {
134+
IFeeHandler feeHandler = kyberFeeHandlerArray[j].kyberFeeHandler;
135+
if (feeHandler.rebatePerWallet(rebateWallet) > 1) {
136+
amounts[j] = feeHandler.claimReserveRebate(rebateWallet);
137+
}
138+
}
139+
}
140+
}
141+
142+
/// @dev claim accumulated fee per platform wallet. Called by any address
143+
/// @param platformWallet the wallet to claim fee for. Total accumulated fee sent to this wallet
144+
/// @param startTokenIndex index of supportedTokens to start iterating from (inclusive)
145+
/// @param endTokenIndex index of supportedTokens to end iterating to (exclusive)
146+
/// @param startKyberFeeHandlerIndex index of feeHandlerArray to start iterating from (inclusive)
147+
/// @param endKyberFeeHandlerIndex index of feeHandlerArray to end iterating to (exclusive)
148+
/// @return amounts platform fee wei / twei amount claimed from each feeHandler
149+
function claimPlatformFee(
150+
address platformWallet,
151+
uint256 startTokenIndex,
152+
uint256 endTokenIndex,
153+
uint256 startKyberFeeHandlerIndex,
154+
uint256 endKyberFeeHandlerIndex
155+
) external returns (uint256[] memory amounts)
156+
{
157+
if (
158+
startTokenIndex > endTokenIndex ||
159+
startKyberFeeHandlerIndex > endKyberFeeHandlerIndex ||
160+
supportedTokens.length == 0
161+
) {
162+
// no need to do anything
163+
return amounts;
164+
}
165+
166+
uint256 endTokenId = (endTokenIndex >= supportedTokens.length) ?
167+
supportedTokens.length : endTokenIndex;
168+
169+
for (uint256 i = startTokenIndex; i < endTokenId; i++) {
170+
KyberFeeHandlerData[] memory kyberFeeHandlerArray = kyberFeeHandlersPerToken[supportedTokens[i]];
171+
uint256 endKyberFeeHandlerId = (endKyberFeeHandlerIndex >= kyberFeeHandlerArray.length) ?
172+
kyberFeeHandlerArray.length : endKyberFeeHandlerIndex;
173+
require(endKyberFeeHandlerId >= startKyberFeeHandlerIndex, "bad array indices");
174+
amounts = new uint256[](endKyberFeeHandlerId - startKyberFeeHandlerIndex + 1);
175+
176+
for (uint256 j = startKyberFeeHandlerIndex; j < endKyberFeeHandlerId; j++) {
177+
IFeeHandler feeHandler = kyberFeeHandlerArray[j].kyberFeeHandler;
178+
if (feeHandler.feePerPlatformWallet(platformWallet) > 1) {
179+
amounts[j] = feeHandler.claimPlatformFee(platformWallet);
180+
}
181+
}
182+
}
183+
}
184+
185+
function getKyberFeeHandlersPerToken(IERC20 token) external view returns (
186+
IFeeHandler[] memory kyberFeeHandlers,
187+
uint256[] memory epochs
188+
)
189+
{
190+
KyberFeeHandlerData[] storage kyberFeeHandlerData = kyberFeeHandlersPerToken[token];
191+
kyberFeeHandlers = new IFeeHandler[](kyberFeeHandlerData.length);
192+
epochs = new uint256[](kyberFeeHandlerData.length);
193+
for (uint i = 0; i < kyberFeeHandlerData.length; i++) {
194+
kyberFeeHandlers[i] = kyberFeeHandlerData[i].kyberFeeHandler;
195+
epochs[i] = kyberFeeHandlerData[i].startEpoch;
196+
}
197+
}
198+
199+
function getSupportedTokens() external view returns (IERC20[] memory) {
200+
return supportedTokens;
201+
}
202+
203+
function addTokenToSupportedTokensArray(IERC20 _token) internal {
204+
uint256 i;
205+
for (i = 0; i < supportedTokens.length; i++) {
206+
if (_token == supportedTokens[i]) {
207+
// already added, return
208+
return;
209+
}
210+
}
211+
supportedTokens.push(_token);
212+
}
213+
214+
function addFeeHandlerToKyberFeeHandlerArray(
215+
KyberFeeHandlerData[] storage kyberFeeHandlerArray,
216+
IFeeHandler _kyberFeeHandler
217+
) internal {
218+
uint256 i;
219+
for (i = 0; i < kyberFeeHandlerArray.length; i++) {
220+
if (_kyberFeeHandler == kyberFeeHandlerArray[i].kyberFeeHandler) {
221+
// already added, return
222+
return;
223+
}
224+
}
225+
kyberFeeHandlerArray.push(KyberFeeHandlerData({
226+
kyberFeeHandler: _kyberFeeHandler,
227+
startEpoch: kyberDao.getCurrentEpochNumber()
228+
})
229+
);
230+
}
231+
}

0 commit comments

Comments
 (0)