-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathVestingParams.sol
More file actions
172 lines (145 loc) · 6.51 KB
/
VestingParams.sol
File metadata and controls
172 lines (145 loc) · 6.51 KB
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
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {IVestingParams} from "./interfaces/IVestingParams.sol";
import {VestingType, Beneficiary, Schedule, Period} from "../utils/Common.sol";
/**
* @title Vesting params
* @author Pavel Naydanov
* @notice The contract describes the parameters of the launched vestings.
* Includes: total amount of the vestings, the addresses of the beneficiaries, allocations, the unlocking schedule
* The start time is common for all types of vesting. Start time and addresses of the beneficiaries are set during contract deployment.
*/
contract VestingParams is IVestingParams {
uint256 public constant MONTH = 30 days;
// Team
uint256 public constant TEAM_TOTAL_AMOUNT = 100_000_000e18;
uint256 public constant TEAM_NUMBER_OF_PERIODS = 27; // 25 periods + 1 period TGE + 1 period cliff
uint256 public constant TEAM_TGE_PORTION = 0; // 0%
uint256 public constant TEAM_CLIFF_PERIOD = 13 * MONTH; // 13 month
uint256 public constant TEAM_VESTING_PORTION = 400; // 4%
// Liquidity
uint256 public constant LIQUIDITY_TOTAL_AMOUNT = 287_500_000e18;
uint256 public constant LIQUIDITY_NUMBER_OF_PERIODS = 22; // // 20 periods + 1 period TGE + 1 period cliff
uint256 public constant LIQUIDITY_TGE_PORTION = 2000; // 20%
uint256 public constant LIQUIDITY_CLIFF_PERIOD = 4 * MONTH; // 4 month
uint256 public constant LIQUIDITY_VESTING_PORTION = 400; // 4%
/// @notice Start time of vestings
uint64 private _startTime;
/// @notice List of beneficiaries for vesting type
mapping(VestingType vestingType => Beneficiary[] beneficiaries) private _beneficiaries;
constructor(uint64 startTime, Beneficiary[] memory teamBeneficiaries, Beneficiary[] memory liquidityBeneficiaries) {
if (startTime < block.timestamp) {
revert InvalidStartTime();
}
_startTime = startTime;
_validateAndStoreBeneficiaries(VestingType.TEAM, teamBeneficiaries, TEAM_TOTAL_AMOUNT);
_validateAndStoreBeneficiaries(VestingType.LIQUIDITY, liquidityBeneficiaries, LIQUIDITY_TOTAL_AMOUNT);
}
/**
* @notice Get schedule by vesting type
* @param vestingType Type of vesting (Team, Liquidity, etc.)
* @dev Portions 100% equal 10_000. It's _BASIS_POINTS, which declared in Vesting contract
* @return schedule Schedule structure
*/
function getSchedule(VestingType vestingType) public view returns (Schedule memory schedule) {
(, uint256 numberOfPeriods, uint256 tgePortion, uint256 cliffPeriod, uint256 vestingPortion) =
getVestingConstant(vestingType);
Period[] memory periods = new Period[](numberOfPeriods);
// TGE
periods[0] = Period({endTime: _startTime, portion: tgePortion});
// Cliff period
periods[1] = Period({endTime: _startTime + cliffPeriod, portion: 0});
// Vesting period
uint256 vestingStartTime = _startTime + cliffPeriod;
for (uint256 i = 2; i < numberOfPeriods; i++) {
periods[i] = Period({endTime: vestingStartTime + (i - 1) * MONTH, portion: vestingPortion});
}
schedule = Schedule({startTime: _startTime, periods: periods});
}
/**
* @notice Get beneficiaries by vesting type
* @param vestingType Type of vesting (Team, Liquidity, etc.)
* @return List of the beneficiaries
*/
function getBeneficiaries(VestingType vestingType) public view returns (Beneficiary[] memory) {
return _beneficiaries[vestingType];
}
/**
* @notice Get vesting constant by vesting type
* @param vestingType Type of vesting (Team, Liquidity, etc.)
* @return totalAmount Total amount of the vesting type
* @return numberOfPeriods Number of vesting periods (includes tge and cliff periods)
* @return tgePortions Unlocked tge portion based on BASIS_POINTS from vesting contract
* @return cliffPeriod Duration time of the cliff period when unlocked amount is zero
* @return vestingPortion Unlocked vesting period portion based on BASIS_POINTS from vesting contract
*/
function getVestingConstant(VestingType vestingType)
public
pure
returns (
uint256 totalAmount,
uint256 numberOfPeriods,
uint256 tgePortions,
uint256 cliffPeriod,
uint256 vestingPortion
)
{
if (vestingType == VestingType.TEAM) {
totalAmount = TEAM_TOTAL_AMOUNT;
numberOfPeriods = TEAM_NUMBER_OF_PERIODS;
tgePortions = TEAM_TGE_PORTION;
cliffPeriod = TEAM_CLIFF_PERIOD;
vestingPortion = TEAM_VESTING_PORTION;
}
if (vestingType == VestingType.LIQUIDITY) {
totalAmount = LIQUIDITY_TOTAL_AMOUNT;
numberOfPeriods = LIQUIDITY_NUMBER_OF_PERIODS;
tgePortions = LIQUIDITY_TGE_PORTION;
cliffPeriod = LIQUIDITY_CLIFF_PERIOD;
vestingPortion = LIQUIDITY_VESTING_PORTION;
}
}
/**
* @notice Get vesting params by vesting type
* @param vestingType Type of vesting (Team, Liquidity, etc.)
* @return Schedule of the vesting
* @return List of the beneficiaries
* @return totalAmount Total amount of the vesting type
*/
function getVestingParams(VestingType vestingType)
external
view
returns (Schedule memory, Beneficiary[] memory, uint256 totalAmount)
{
(totalAmount,,,,) = getVestingConstant(vestingType);
return (getSchedule(vestingType), getBeneficiaries(vestingType), totalAmount);
}
/// @notice Return start time for all vesting types
function getStartTime() external view returns (uint64) {
return _startTime;
}
function _validateAndStoreBeneficiaries(
VestingType vestingType,
Beneficiary[] memory beneficiaries,
uint256 expectedTotalAmount
) internal virtual {
if (beneficiaries.length == 0) {
revert ZeroBeneficiaries();
}
uint256 totalAmount;
for (uint256 i = 0; i < beneficiaries.length; i++) {
Beneficiary memory beneficiary = beneficiaries[i];
if (beneficiary.account == address(0)) {
revert ZeroAddress();
}
if (beneficiary.amount == 0) {
revert ZeroAmount();
}
totalAmount += beneficiary.amount;
_beneficiaries[vestingType].push(beneficiary);
}
if (totalAmount != expectedTotalAmount) {
revert IncorrectBeneficiaryAmounts();
}
}
}