1
+ /*
2
+ Copyright 2021 IndexCooperative
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */
16
+
17
+ pragma solidity 0.6.10 ;
18
+
19
+ import { Address } from "@openzeppelin/contracts/utils/Address.sol " ;
20
+ import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol " ;
21
+
22
+ import { BaseAdapter } from "../lib/BaseAdapter.sol " ;
23
+ import { IBaseManager } from "../interfaces/IBaseManager.sol " ;
24
+ import { ISetToken } from "../interfaces/ISetToken.sol " ;
25
+ import { IStreamingFeeModule } from "../interfaces/IStreamingFeeModule.sol " ;
26
+ import { PreciseUnitMath } from "../lib/PreciseUnitMath.sol " ;
27
+ import { TimeLockUpgrade } from "../lib/TimeLockUpgrade.sol " ;
28
+
29
+
30
+ /**
31
+ * @title StreamingFeeSplitExtension
32
+ * @author Set Protocol
33
+ *
34
+ * Smart contract manager extension that allows for splitting and setting streaming fees. Fee splits are updated by operator.
35
+ * Any fee updates are timelocked.
36
+ */
37
+ contract StreamingFeeSplitExtension is BaseAdapter , TimeLockUpgrade {
38
+ using Address for address ;
39
+ using PreciseUnitMath for uint256 ;
40
+ using SafeMath for uint256 ;
41
+
42
+ /* ============ Events ============ */
43
+
44
+ event FeesAccrued (address indexed _operator , address indexed _methodologist , uint256 _operatorTake , uint256 _methodologistTake );
45
+
46
+ /* ============ State Variables ============ */
47
+
48
+ ISetToken public setToken;
49
+ IStreamingFeeModule public streamingFeeModule;
50
+
51
+ // Percent of fees in precise units (10^16 = 1%) sent to operator, rest to methodologist
52
+ uint256 public operatorFeeSplit;
53
+
54
+ /* ============ Constructor ============ */
55
+
56
+ constructor (
57
+ IBaseManager _manager ,
58
+ IStreamingFeeModule _streamingFeeModule ,
59
+ uint256 _operatorFeeSplit
60
+ )
61
+ public
62
+ BaseAdapter (_manager)
63
+ {
64
+ streamingFeeModule = _streamingFeeModule;
65
+ operatorFeeSplit = _operatorFeeSplit;
66
+ setToken = manager.setToken ();
67
+ }
68
+
69
+ /* ============ External Functions ============ */
70
+
71
+ /**
72
+ * ANYONE CALLABLE: Accrues fees from streaming fee module. Gets resulting balance after fee accrual, calculates fees for
73
+ * operator and methodologist, and sends to each.
74
+ */
75
+ function accrueFeesAndDistribute () public {
76
+ streamingFeeModule.accrueFee (setToken);
77
+
78
+ uint256 totalFees = setToken.balanceOf (address (manager));
79
+
80
+ address operator = manager.operator ();
81
+ address methodologist = manager.methodologist ();
82
+
83
+ uint256 operatorTake = totalFees.preciseMul (operatorFeeSplit);
84
+ uint256 methodologistTake = totalFees.sub (operatorTake);
85
+
86
+ if (operatorTake > 0 ) {
87
+ invokeManagerTransfer (address (setToken), operator, operatorTake);
88
+ }
89
+
90
+ if (methodologistTake > 0 ) {
91
+ invokeManagerTransfer (address (setToken), methodologist, methodologistTake);
92
+ }
93
+
94
+ emit FeesAccrued (operator, methodologist, operatorTake, methodologistTake);
95
+ }
96
+
97
+ /**
98
+ * ONLY OPERATOR: Updates streaming fee on StreamingFeeModule. NOTE: This will accrue streaming fees to the manager contract
99
+ * but not distribute to the operator and methodologist.
100
+ */
101
+ function updateStreamingFee (uint256 _newFee ) external onlyOperator timeLockUpgrade {
102
+ bytes memory callData = abi.encodeWithSelector (
103
+ IStreamingFeeModule.updateStreamingFee.selector ,
104
+ manager.setToken (),
105
+ _newFee
106
+ );
107
+
108
+ invokeManager (address (streamingFeeModule), callData);
109
+ }
110
+
111
+ /**
112
+ * ONLY OPERATOR: Updates fee recipient on streaming fee module.
113
+ */
114
+ function updateFeeRecipient (address _newFeeRecipient ) external onlyOperator {
115
+ bytes memory callData = abi.encodeWithSelector (
116
+ IStreamingFeeModule.updateFeeRecipient.selector ,
117
+ manager.setToken (),
118
+ _newFeeRecipient
119
+ );
120
+
121
+ invokeManager (address (streamingFeeModule), callData);
122
+ }
123
+
124
+ /**
125
+ * ONLY OPERATOR: Updates fee split between operator and methodologist. Split defined in precise units (1% = 10^16). Fees will be
126
+ * accrued and distributed before the new split goes into effect.
127
+ */
128
+ function updateFeeSplit (uint256 _newFeeSplit ) external onlyOperator {
129
+ require (_newFeeSplit <= PreciseUnitMath.preciseUnit (), "Fee must be less than 100% " );
130
+ accrueFeesAndDistribute ();
131
+ operatorFeeSplit = _newFeeSplit;
132
+ }
133
+ }
0 commit comments