-
Notifications
You must be signed in to change notification settings - Fork 47
/
Copy pathVestingRegistry3.sol
228 lines (201 loc) · 7.36 KB
/
VestingRegistry3.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
pragma solidity ^0.5.17;
import "../../openzeppelin/Ownable.sol";
import "../../interfaces/IERC20.sol";
import "../Staking/interfaces/IStaking.sol";
import "../IFeeSharingCollector.sol";
import "./IVestingFactory.sol";
import "./IVesting.sol";
import "./ITeamVesting.sol";
import "../../openzeppelin/SafeMath.sol";
contract VestingRegistry3 is Ownable {
using SafeMath for uint256;
IVestingFactory public vestingFactory;
///@notice the SOV token contract
address public SOV;
///@notice the staking contract address
address public staking;
//@notice fee sharing proxy
address public feeSharingCollector;
//@notice the vesting owner (e.g. governance timelock address)
address public vestingOwner;
//TODO add to the documentation: address can have only one vesting of each type
//user => vesting type => vesting contract
mapping(address => mapping(uint256 => address)) public vestingContracts;
//user => flag whether user has admin role
mapping(address => bool) public admins;
enum VestingType {
TeamVesting, //MultisigVesting
Vesting //TokenHolderVesting
}
event SOVTransferred(address indexed receiver, uint256 amount);
event VestingCreated(
address indexed tokenOwner,
address vesting,
uint256 cliff,
uint256 duration,
uint256 amount
);
event TeamVestingCreated(
address indexed tokenOwner,
address vesting,
uint256 cliff,
uint256 duration,
uint256 amount
);
event TokensStaked(address indexed vesting, uint256 amount);
event AdminAdded(address admin);
event AdminRemoved(address admin);
constructor(
address _vestingFactory,
address _SOV,
address _staking,
address _feeSharingCollector,
address _vestingOwner
) public {
require(_SOV != address(0), "SOV address invalid");
require(_staking != address(0), "staking address invalid");
require(_feeSharingCollector != address(0), "feeSharingCollector address invalid");
require(_vestingOwner != address(0), "vestingOwner address invalid");
_setVestingFactory(_vestingFactory);
SOV = _SOV;
staking = _staking;
feeSharingCollector = _feeSharingCollector;
vestingOwner = _vestingOwner;
}
/**
* @dev Throws if called by any account other than the owner or admin.
*/
modifier onlyAuthorized() {
require(isOwner() || admins[msg.sender], "unauthorized");
_;
}
function addAdmin(address _admin) public onlyOwner {
admins[_admin] = true;
emit AdminAdded(_admin);
}
function removeAdmin(address _admin) public onlyOwner {
admins[_admin] = false;
emit AdminRemoved(_admin);
}
/**
* @notice sets vesting factory address
* @param _vestingFactory the address of vesting factory contract
*/
function setVestingFactory(address _vestingFactory) public onlyOwner {
_setVestingFactory(_vestingFactory);
}
function _setVestingFactory(address _vestingFactory) internal {
require(_vestingFactory != address(0), "vestingFactory address invalid");
vestingFactory = IVestingFactory(_vestingFactory);
}
/**
* @notice transfers SOV tokens to given address
* @param _receiver the address of the SOV receiver
* @param _amount the amount to be transferred
*/
function transferSOV(address _receiver, uint256 _amount) public onlyOwner {
require(_receiver != address(0), "receiver address invalid");
require(_amount != 0, "amount invalid");
IERC20(SOV).transfer(_receiver, _amount);
emit SOVTransferred(_receiver, _amount);
}
/**
* @notice creates Vesting contract
* @param _tokenOwner the owner of the tokens
* @param _amount the amount to be staked
* @param _cliff the cliff in seconds
* @param _duration the total duration in seconds
*/
function createVesting(
address _tokenOwner,
uint256 _amount,
uint256 _cliff,
uint256 _duration
) public onlyAuthorized {
address vesting = _getOrCreateVesting(_tokenOwner, _cliff, _duration);
emit VestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);
}
/**
* @notice creates Team Vesting contract
* @param _tokenOwner the owner of the tokens
* @param _amount the amount to be staked
* @param _cliff the cliff in seconds
* @param _duration the total duration in seconds
*/
function createTeamVesting(
address _tokenOwner,
uint256 _amount,
uint256 _cliff,
uint256 _duration
) public onlyAuthorized {
address vesting = _getOrCreateTeamVesting(_tokenOwner, _cliff, _duration);
emit TeamVestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);
}
/**
* @notice stakes tokens according to the vesting schedule
* @param _vesting the address of Vesting contract
* @param _amount the amount of tokens to stake
*/
function stakeTokens(address _vesting, uint256 _amount) public onlyAuthorized {
require(_vesting != address(0), "vesting address invalid");
require(_amount > 0, "amount invalid");
IERC20(SOV).approve(_vesting, _amount);
IVesting(_vesting).stakeTokens(_amount);
emit TokensStaked(_vesting, _amount);
}
/**
* @notice returns vesting contract address for the given token owner
* @param _tokenOwner the owner of the tokens
*/
function getVesting(address _tokenOwner) public view returns (address) {
return vestingContracts[_tokenOwner][uint256(VestingType.Vesting)];
}
/**
* @notice returns team vesting contract address for the given token owner
* @param _tokenOwner the owner of the tokens
*/
function getTeamVesting(address _tokenOwner) public view returns (address) {
return vestingContracts[_tokenOwner][uint256(VestingType.TeamVesting)];
}
function _getOrCreateVesting(
address _tokenOwner,
uint256 _cliff,
uint256 _duration
) internal returns (address) {
uint256 type_ = uint256(VestingType.Vesting);
if (vestingContracts[_tokenOwner][type_] == address(0)) {
//TODO Owner of OwnerVesting contracts - the same address as tokenOwner
address vesting = vestingFactory.deployVesting(
SOV,
staking,
_tokenOwner,
_cliff,
_duration,
feeSharingCollector,
_tokenOwner
);
vestingContracts[_tokenOwner][type_] = vesting;
}
return vestingContracts[_tokenOwner][type_];
}
function _getOrCreateTeamVesting(
address _tokenOwner,
uint256 _cliff,
uint256 _duration
) internal returns (address) {
uint256 type_ = uint256(VestingType.TeamVesting);
if (vestingContracts[_tokenOwner][type_] == address(0)) {
address vesting = vestingFactory.deployTeamVesting(
SOV,
staking,
_tokenOwner,
_cliff,
_duration,
feeSharingCollector,
vestingOwner
);
vestingContracts[_tokenOwner][type_] = vesting;
}
return vestingContracts[_tokenOwner][type_];
}
}