Skip to content

Commit 04d5b37

Browse files
committed
add EmergencyFeeHandler
1 parent 2e823e2 commit 04d5b37

File tree

3 files changed

+593
-0
lines changed

3 files changed

+593
-0
lines changed
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
pragma solidity 0.6.6;
2+
3+
import "../IKyberFeeHandler.sol";
4+
import "../utils/PermissionGroupsNoModifiers.sol";
5+
import "../utils/zeppelin/ReentrancyGuard.sol";
6+
import "../utils/zeppelin/SafeMath.sol";
7+
import "../utils/Utils5.sol";
8+
9+
contract EmergencyKyberFeeHandler is IKyberFeeHandler, PermissionGroupsNoModifiers, ReentrancyGuard, Utils5 {
10+
using SafeMath for uint256;
11+
12+
uint16 public immutable rewardBps;
13+
uint16 public immutable rebateBps;
14+
address public kyberNetwork;
15+
16+
mapping(address => uint256) public feePerPlatformWallet;
17+
uint256 public totalPlatformFeeWei; // total balance in the contract that is for platform fee
18+
mapping(address => uint256) public rebatePerWallet;
19+
uint256 public totalRewardWei;
20+
21+
event HandleFeeFailed(address[] rebateWallets, uint256[] rebateBpsPerWallet, uint256 feeBRRWei);
22+
23+
event HandleFee(
24+
address indexed platformWallet,
25+
uint256 platformFeeWei,
26+
address[] rebateWallets,
27+
uint256[] rebateBpsPerWallet,
28+
uint256 feeBRRWei
29+
);
30+
31+
event BRRFeeDistribution (
32+
uint256 rewardWei,
33+
uint256 rebateWei,
34+
uint256 burnAmountWei
35+
);
36+
37+
event EtherWithdraw(uint256 amount, address sendTo);
38+
39+
event KyberNetworkUpdated(address kyberNetwork);
40+
41+
constructor(
42+
address admin,
43+
address _kyberNetwork,
44+
uint256 _rewardBps,
45+
uint256 _rebateBps,
46+
uint256 _burnBps
47+
) public PermissionGroupsNoModifiers(admin) {
48+
require(_burnBps.add(_rewardBps).add(_rebateBps) == BPS, "Bad BRR values");
49+
rewardBps = uint16(_rewardBps);
50+
rebateBps = uint16(_rebateBps);
51+
kyberNetwork = _kyberNetwork;
52+
}
53+
54+
modifier onlyKyberNetwork {
55+
require(msg.sender == address(kyberNetwork), "only kyberNetwork");
56+
_;
57+
}
58+
59+
/// @dev handleFees function is called per trade on KyberNetwork. unless the trade is not involving any fees.
60+
/// @param rebateWallets a list of rebate wallets that will get rebate for this trade.
61+
/// @param rebateBpsPerWallet percentage of rebate for each wallet, out of total rebate.
62+
/// @param platformWallet Wallet address that will receive the platfrom fee.
63+
/// @param platformFeeWei Fee amount in wei the platfrom wallet is entitled to.
64+
function handleFees(
65+
address[] calldata rebateWallets,
66+
uint256[] calldata rebateBpsPerWallet,
67+
address platformWallet,
68+
uint256 platformFeeWei
69+
) external payable override onlyKyberNetwork {
70+
uint256 feeBRRWei = msg.value.sub(platformFeeWei);
71+
72+
// handle platform fee
73+
feePerPlatformWallet[platformWallet] = feePerPlatformWallet[platformWallet].add(
74+
platformFeeWei
75+
);
76+
totalPlatformFeeWei = totalPlatformFeeWei.add(platformFeeWei);
77+
emit HandleFee(platformWallet, platformFeeWei, rebateWallets, rebateBpsPerWallet, feeBRRWei);
78+
79+
if (feeBRRWei == 0) {
80+
return;
81+
}
82+
83+
(bool success, ) = address(this).call(
84+
abi.encodeWithSignature(
85+
"calculateAndRecordFeeData(address[],uint256[],uint256)",
86+
rebateWallets,
87+
rebateBpsPerWallet,
88+
feeBRRWei
89+
)
90+
);
91+
if (!success) {
92+
emit HandleFeeFailed(rebateWallets, rebateBpsPerWallet, feeBRRWei);
93+
}
94+
}
95+
96+
function calculateAndRecordFeeData(
97+
address[] calldata rebateWallets,
98+
uint256[] calldata rebateBpsPerWallet,
99+
uint256 feeBRRWei
100+
) external virtual {
101+
require(msg.sender == address(this), "only Feehandler contract can call this function");
102+
uint256 rebateWei = feeBRRWei.mul(rebateBps).div(BPS);
103+
uint256 rewardWei = feeBRRWei.mul(rewardBps).div(BPS);
104+
105+
rebateWei = updateRebateValues(rebateWei, rebateWallets, rebateBpsPerWallet);
106+
107+
totalRewardWei = totalRewardWei.add(rewardWei);
108+
109+
uint burnAmountWei = feeBRRWei.sub(rewardWei).sub(rebateWei);
110+
111+
emit BRRFeeDistribution(
112+
rewardWei,
113+
rebateWei,
114+
burnAmountWei
115+
);
116+
}
117+
118+
/// @dev claim accumulated fee per platform wallet. Called by any address
119+
/// @param platformWallet the wallet to claim fee for. Total accumulated fee sent to this wallet.
120+
/// @return amountWei amount of fee claimed
121+
function claimPlatformFee(address platformWallet)
122+
external
123+
override
124+
nonReentrant
125+
returns (uint256 amountWei)
126+
{
127+
require(feePerPlatformWallet[platformWallet] > 1, "no fee to claim");
128+
// Get total amount of fees accumulated
129+
amountWei = feePerPlatformWallet[platformWallet].sub(1);
130+
131+
// redundant check, but can't happen
132+
assert(totalPlatformFeeWei >= amountWei);
133+
totalPlatformFeeWei = totalPlatformFeeWei.sub(amountWei);
134+
135+
feePerPlatformWallet[platformWallet] = 1; // avoid zero to non zero storage cost
136+
137+
(bool success, ) = platformWallet.call{value: amountWei}("");
138+
require(success, "platform fee transfer failed");
139+
140+
emit PlatformFeePaid(platformWallet, amountWei);
141+
return amountWei;
142+
}
143+
144+
function withdraw(address payable sendTo, uint256 amount) external nonReentrant {
145+
onlyAdmin();
146+
147+
uint256 balance = address(this).balance;
148+
// check if the remain balance is enough for withdraw and paying platform fee
149+
require(amount <= balance.sub(totalPlatformFeeWei), "amount > available funds");
150+
151+
(bool success, ) = sendTo.call{value: amount}("");
152+
require(success);
153+
emit EtherWithdraw(amount, sendTo);
154+
}
155+
156+
/// @dev claimReserveRebate is implemented for IKyberFeeHandler
157+
function claimReserveRebate(address) external override returns (uint256) {
158+
revert("not implemented");
159+
}
160+
161+
/// @dev claimStakerReward is implemented for IKyberFeeHandler
162+
function claimStakerReward(address, uint256, uint256) external override returns (uint256) {
163+
revert("not implemented");
164+
}
165+
166+
/// @dev set new kyberNetwork address by daoOperator
167+
/// @param _kyberNetwork new kyberNetwork contract
168+
function setNetworkContract(address _kyberNetwork) external {
169+
onlyAdmin();
170+
require(_kyberNetwork != address(0), "kyberNetwork 0");
171+
if (_kyberNetwork != kyberNetwork) {
172+
kyberNetwork = _kyberNetwork;
173+
emit KyberNetworkUpdated(kyberNetwork);
174+
}
175+
}
176+
177+
function updateRebateValues(
178+
uint256 rebateWei,
179+
address[] memory rebateWallets,
180+
uint256[] memory rebateBpsPerWallet
181+
) internal returns (uint256 totalRebatePaidWei) {
182+
uint256 totalRebateBps;
183+
uint256 walletRebateWei;
184+
185+
for (uint256 i = 0; i < rebateWallets.length; i++) {
186+
require(rebateWallets[i] != address(0), "rebate wallet address 0");
187+
188+
walletRebateWei = rebateWei.mul(rebateBpsPerWallet[i]).div(BPS);
189+
rebatePerWallet[rebateWallets[i]] = rebatePerWallet[rebateWallets[i]].add(
190+
walletRebateWei
191+
);
192+
193+
// a few wei could be left out due to rounding down. so count only paid wei
194+
totalRebatePaidWei = totalRebatePaidWei.add(walletRebateWei);
195+
totalRebateBps = totalRebateBps.add(rebateBpsPerWallet[i]);
196+
}
197+
198+
require(totalRebateBps <= BPS, "rebates more then 100%");
199+
}
200+
201+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
pragma solidity 0.6.6;
2+
3+
import "../EmergencyFeeHandler.sol";
4+
5+
6+
contract MockEmergencyFeeHandler is EmergencyKyberFeeHandler {
7+
constructor(
8+
address admin,
9+
address _kyberNetwork,
10+
uint256 _rewardBps,
11+
uint256 _rebateBps,
12+
uint256 _burnBps
13+
) public EmergencyKyberFeeHandler(admin, _kyberNetwork, _rewardBps, _rebateBps, _burnBps) {}
14+
15+
function calculateAndRecordFeeData(
16+
address[] calldata,
17+
uint256[] calldata,
18+
uint256
19+
) external override {
20+
revert();
21+
}
22+
}

0 commit comments

Comments
 (0)