Cliff Vesting
A pure vesting calculator, demoing the p/moul/x/daily/cliffvesting library.
A 12-month grant with a 3-month cliff
1200 tokens, Start = 0, Cliff = 3, End = 12.
| month | vested | unvested | % |
|---|---|---|---|
| 0 | 0 | 1200 | 0% |
| 1 | 0 | 1200 | 0% |
| 2 | 0 | 1200 | 0% ← nothing yet |
| 3 | 300 | 900 | 25% ← cliff |
| 4 | 400 | 800 | 33% |
| 5 | 500 | 700 | 41% |
| 6 | 600 | 600 | 50% |
| 7 | 700 | 500 | 58% |
| 8 | 800 | 400 | 66% |
| 9 | 900 | 300 | 75% |
| 10 | 1000 | 200 | 83% |
| 11 | 1100 | 100 | 91% |
| 12 | 1200 | 0 | 100% ← fully vested |
The cliff is a step, not a ramp: at month 3 a quarter of the term has elapsed, so 300 tokens unlock at once. After that it accrues linearly.
Claiming
The library tracks no balances, so the caller supplies what has already been claimed:
| at month | already claimed | claimable |
|---|---|---|
| 6 | 0 | 600 |
| 6 | 300 | 300 |
| 6 | 600 | 0 |
| 12 | 600 | 600 |
Integer rounding
All arithmetic is integer, no float ever reaches consensus state. Rounding is down, so nobody is ever paid more than they earned, and the final instalment collects the remainder.
1000 over 3 periods:
| t | vested |
|---|---|
| 0 | 0 |
| 1 | 333 |
| 2 | 666 |
| 3 | 1000 |
333 + 333 + 334, and the end is exactly 1000, never 999.
Bug 1: a rate truncated to zero
When the total is smaller than the duration, computing a per-tick rate first truncates it to zero and nothing ever vests. Multiplying before dividing keeps it honest. 7 tokens over 1000 ticks:
| t | vested |
|---|---|
| 100 | 0 |
| 150 | 1 |
| 500 | 3 |
| 1000 | 7 |
Bug 2: a product that leaves int64
Multiplying first is only safe if the product fits. Over a term measured in seconds, total * elapsed passes 2^63 for any grant above about 146,036 whole coins, and a wrapped int64 is still a valid int64: v0 of this library returned a negative vested amount and nothing signalled it. v1 routes the product through a 128-bit intermediate.
A real two-year schedule, 1789225200 to 1852383600, at the halfway mark:
| grant | vested at halfway | expected |
|---|---|---|
| 100000000000 | 50000000000 | 50000000000 |
| 146037000000 | 73018500000 | 73018500000 |
| 318720000000000 | 159360000000000 | 159360000000000 |