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

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}