Skip to content

Commit 43b7d6a

Browse files
authored
New adapter that solely handles splitting streaming fees. (#61)
New manager extension that solely handles splitting streaming fees.
1 parent c7a0929 commit 43b7d6a

File tree

5 files changed

+596
-2
lines changed

5 files changed

+596
-2
lines changed
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
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+
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@setprotocol/index-coop-contracts",
3-
"version": "0.0.21",
3+
"version": "0.0.22",
44
"description": "",
55
"main": "dist",
66
"types": "dist/types",

0 commit comments

Comments
 (0)