Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

render_example_test.gno

2.73 Kb · 81 lines
 1package cliffvestingdemo
 2
 3// ExampleRender pins the realm's Render output as a testable example.
 4func ExampleRender() {
 5	print(Render(""))
 6	// Output:
 7	// # Cliff Vesting
 8	//
 9	// A pure vesting calculator, demoing the [`p/moul/x/daily/cliffvesting`](/p/moul/x/daily/cliffvesting/v1) library.
10	//
11	// ## A 12-month grant with a 3-month cliff
12	//
13	// `1200` tokens, `Start = 0`, `Cliff = 3`, `End = 12`.
14	//
15	// | month | vested | unvested | % |
16	// |---|---|---|---|
17	// | 0 | 0 | 1200 | 0% |
18	// | 1 | 0 | 1200 | 0% |
19	// | 2 | 0 | 1200 | 0% ← nothing yet |
20	// | 3 | 300 | 900 | 25% ← **cliff** |
21	// | 4 | 400 | 800 | 33% |
22	// | 5 | 500 | 700 | 41% |
23	// | 6 | 600 | 600 | 50% |
24	// | 7 | 700 | 500 | 58% |
25	// | 8 | 800 | 400 | 66% |
26	// | 9 | 900 | 300 | 75% |
27	// | 10 | 1000 | 200 | 83% |
28	// | 11 | 1100 | 100 | 91% |
29	// | 12 | 1200 | 0 | 100% ← fully vested |
30	//
31	// 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.
32	//
33	// ## Claiming
34	//
35	// The library tracks no balances, so the caller supplies what has already been claimed:
36	//
37	// | at month | already claimed | claimable |
38	// |---|---|---|
39	// | 6 | 0 | 600 |
40	// | 6 | 300 | 300 |
41	// | 6 | 600 | 0 |
42	// | 12 | 600 | 600 |
43	//
44	// ## Integer rounding
45	//
46	// 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.
47	//
48	// `1000` over `3` periods:
49	//
50	// | t | vested |
51	// |---|---|
52	// | 0 | 0 |
53	// | 1 | 333 |
54	// | 2 | 666 |
55	// | 3 | 1000 |
56	//
57	// `333 + 333 + 334`, and the end is exactly `1000`, never `999`.
58	//
59	// ## Bug 1: a rate truncated to zero
60	//
61	// 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:
62	//
63	// | t | vested |
64	// |---|---|
65	// | 100 | 0 |
66	// | 150 | 1 |
67	// | 500 | 3 |
68	// | 1000 | 7 |
69	//
70	// ## Bug 2: a product that leaves int64
71	//
72	// 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.
73	//
74	// A real two-year schedule, `1789225200` to `1852383600`, at the halfway mark:
75	//
76	// | grant | vested at halfway | expected |
77	// |---|---|---|
78	// | 100000000000 | 50000000000 | 50000000000 |
79	// | 146037000000 | 73018500000 | 73018500000 |
80	// | 318720000000000 | 159360000000000 | 159360000000000 |
81}