@@ -15,6 +15,59 @@ import {PRECISION} from "../utils/Globals.sol";
1515 * designed to seamlessly manage vestings and associated schedules for
1616 * multiple beneficiaries and ERC20 tokens. This module stands out for its
1717 * flexibility, offering support for both linear and exponential vesting calculations out of the box.
18+ *
19+ * Linear and Exponential Vesting:
20+ *
21+ * Linear vesting has a constant release rate over time (exponent = 1), resulting in a linear graph.
22+ * Exponential vesting allows for a more flexible release rate, defined by the exponent.
23+ * Higher exponents result in a steeper release curve.
24+ *
25+ * Vesting formula:
26+ *
27+ * vestedAmount = elapsedPeriodsPercentage ** exponent * (totalVestingAmount_)).
28+ *
29+ * Key concepts:
30+ *
31+ * Vesting contract contains two main components: Schedule struct and Vesting struct.
32+ * Each vesting contains scheduleId, which is associated with a schedule struct.
33+ *
34+ * You can create as much Schedules as needed with different parameters with an associated scheduleId.
35+ * Then a schedule can be assigned to vestings. So it's possible to create multiple vestings with the same schedule.
36+ *
37+ * Schedule defines the base structure for the vesting and how the vested amount will be calculated,
38+ * with the following parameters such as the duration, cliff, period, and exponent.
39+ *
40+ * Schedule parameters description:
41+ * - secondsInPeriod: The duration of each vesting period in seconds. (i.e. 86,400 sec for 1 day)
42+ * - durationInPeriods: The total number of periods for the vesting. (i.e. 20 for 20 days)
43+ * - cliffInPeriods: The number of periods before the vesting starts. (i.e. 3 for 3 days).
44+ * - exponent: The exponent for the vesting calculation. (i.e. 1 for linear vesting, 5 for exponential)
45+ *
46+ * Example of schedule:
47+ * Let's define a schedule with the following parameters:
48+ * - secondsInPeriod = 86,400 (1 day)
49+ * - durationInPeriods = 20 (20 days)
50+ * - cliffInPeriods = 3 (3 days)
51+ * - exponent = 1 (linear vesting)
52+ *
53+ * Using the provided schedule, you can create a vesting that will release vested amount linearly over 20 days with a 3-day cliff.
54+ * Let's say you have 1000 tokens to vest; then the vested amount will be released as follows:
55+ * - 1 day: 0 tokens
56+ * - 2 days: 0 tokens
57+ * - 3 days: 0 tokens
58+ * - 4 days: 200 tokens
59+ * - 5 days: 250 tokens
60+ * ...
61+ * - 20 days: 1000 tokens
62+ *
63+ * P.S.
64+ * For defining linear vesting, the exponent should be set to 1,
65+ * or there is an option to create a linear schedule just by defining the baseSchedule struct
66+ * and the exponent will be automatically set to 1.
67+ *
68+ * For the creation of exponential vesting, the exponent should be set to a value greater than 1.
69+ *
70+ * It's not possible to create a schedule with an exponent equal to 0.
1871 */
1972abstract contract Vesting is Initializable {
2073 using MathUpgradeable for uint256 ;
@@ -164,9 +217,8 @@ abstract contract Vesting is Initializable {
164217 */
165218 function getVestedAmount (uint256 vestingId_ ) public view virtual returns (uint256 ) {
166219 VestingData storage _vesting = _vestings[vestingId_];
167- Schedule storage _schedule = _schedules[_vesting.scheduleId];
168220
169- return _getVestedAmount (_vesting, _schedule , block .timestamp );
221+ return _getVestedAmount (_vesting, _vesting.scheduleId , block .timestamp );
170222 }
171223
172224 /**
@@ -176,9 +228,8 @@ abstract contract Vesting is Initializable {
176228 */
177229 function getWithdrawableAmount (uint256 vestingId_ ) public view virtual returns (uint256 ) {
178230 VestingData storage _vesting = _vestings[vestingId_];
179- Schedule storage _schedule = _schedules[_vesting.scheduleId];
180231
181- return _getWithdrawableAmount (_vesting, _schedule , block .timestamp );
232+ return _getWithdrawableAmount (_vesting, _vesting.scheduleId , block .timestamp );
182233 }
183234
184235 /**
@@ -254,18 +305,18 @@ abstract contract Vesting is Initializable {
254305 /**
255306 * @notice Retrieves the vested amount for a vesting ID.
256307 * @param vesting Vesting data for the vesting contract.
257- * @param schedule Schedule data for the vesting contract .
308+ * @param scheduleId_ Id for the associated schedule .
258309 * @param timestampUpTo_ The timestamp up to which the calculation is performed.
259310 * @return The amount of tokens vested.
260311 */
261312 function _getVestedAmount (
262313 VestingData storage vesting ,
263- Schedule storage schedule ,
314+ uint256 scheduleId_ ,
264315 uint256 timestampUpTo_
265316 ) internal view virtual returns (uint256 ) {
266317 return
267318 _vestingCalculation (
268- schedule ,
319+ scheduleId_ ,
269320 vesting.vestingAmount,
270321 vesting.vestingStartTime,
271322 timestampUpTo_
@@ -275,18 +326,18 @@ abstract contract Vesting is Initializable {
275326 /**
276327 * @notice Retrieves the withdrawable amount for a vesting ID.
277328 * @param vesting Vesting data for the vesting contract.
278- * @param schedule Schedule data for the vesting contract .
329+ * @param scheduleId_ Id for the associated schedule .
279330 * @param timestampUpTo_ The timestamp up to which the calculation is performed.
280331 * @return The amount of tokens withdrawable.
281332 */
282333 function _getWithdrawableAmount (
283334 VestingData storage vesting ,
284- Schedule storage schedule ,
335+ uint256 scheduleId_ ,
285336 uint256 timestampUpTo_
286337 ) internal view virtual returns (uint256 ) {
287338 return
288339 _vestingCalculation (
289- schedule ,
340+ scheduleId_ ,
290341 vesting.vestingAmount,
291342 vesting.vestingStartTime,
292343 timestampUpTo_
@@ -295,19 +346,20 @@ abstract contract Vesting is Initializable {
295346
296347 /**
297348 * @notice Performs the vesting calculation.
298- * @param schedule_ Schedule data for the vesting contract .
349+ * @param scheduleId_ Id for the associated schedule .
299350 * @param totalVestingAmount_ The total amount of tokens to be vested.
300351 * @param vestingStartTime_ The starting time of the vesting.
301352 * @param timestampUpTo_ The timestamp up to which the calculation is performed.
302353 * @return vestedAmount_ The amount of tokens vested.
303354 */
304355 function _vestingCalculation (
305- Schedule memory schedule_ ,
356+ uint256 scheduleId_ ,
306357 uint256 totalVestingAmount_ ,
307358 uint256 vestingStartTime_ ,
308359 uint256 timestampUpTo_
309360 ) internal view virtual returns (uint256 vestedAmount_ ) {
310- BaseSchedule memory baseData_ = schedule_.scheduleData;
361+ Schedule storage _schedule = _schedules[scheduleId_];
362+ BaseSchedule storage _baseData = _schedule.scheduleData;
311363
312364 if (vestingStartTime_ > timestampUpTo_) {
313365 return vestedAmount_;
@@ -316,24 +368,24 @@ abstract contract Vesting is Initializable {
316368 uint256 elapsedPeriods_ = _calculateElapsedPeriods (
317369 vestingStartTime_,
318370 timestampUpTo_,
319- baseData_ .secondsInPeriod
371+ _baseData .secondsInPeriod
320372 );
321373
322- if (elapsedPeriods_ <= baseData_ .cliffInPeriods) {
374+ if (elapsedPeriods_ <= _baseData .cliffInPeriods) {
323375 return 0 ;
324376 }
325377
326- if (elapsedPeriods_ >= baseData_ .durationInPeriods) {
378+ if (elapsedPeriods_ >= _baseData .durationInPeriods) {
327379 return totalVestingAmount_;
328380 }
329381
330382 uint256 elapsedPeriodsPercentage_ = (elapsedPeriods_ * PRECISION) /
331- baseData_ .durationInPeriods;
383+ _baseData .durationInPeriods;
332384
333385 vestedAmount_ =
334- (_raiseToPower (elapsedPeriodsPercentage_, schedule_ .exponent) *
386+ (_raiseToPower (elapsedPeriodsPercentage_, _schedule .exponent) *
335387 (totalVestingAmount_)) /
336- _raiseToPower (PRECISION, schedule_ .exponent);
388+ _raiseToPower (PRECISION, _schedule .exponent);
337389
338390 return vestedAmount_.min (totalVestingAmount_);
339391 }
0 commit comments