vestoken_test.gno
3.37 Kb · 119 lines
1package vestoken
2
3import (
4 "strings"
5 "testing"
6
7 "gno.land/p/nt/testutils/v0"
8 "gno.land/p/nt/uassert/v0"
9)
10
11// Fixed test addresses. testutils.TestAddress derives real, valid-length
12// addresses; literal strings would fail address.IsValid() and trip the realm's
13// zero-address guard.
14var (
15 alice = testutils.TestAddress("alice")
16 bob = testutils.TestAddress("bob")
17)
18
19// reset clears package state between tests so cases stay independent.
20func reset() {
21 balances = map[address]uint64{}
22 grants = map[address]*grant{}
23 totalSupply = 0
24}
25
26// TestVestingUnlocksLinearly opens a grant, claims nothing before any
27// blocks pass, half at the midpoint, and the rest once fully vested.
28func TestVestingUnlocksLinearly(cur realm, t *testing.T) {
29 reset()
30
31 testing.SetRealm(testing.NewUserRealm(alice))
32 MintVested(cross(cur), alice, 1000, 100)
33
34 if got := TotalSupply(); got != 1000 {
35 t.Fatalf("total supply = %d, want 1000", got)
36 }
37
38 testing.SetRealm(testing.NewUserRealm(alice))
39 if got := Claim(cross(cur)); got != 0 {
40 t.Fatalf("claim at start = %d, want 0", got)
41 }
42
43 testing.SkipHeights(50)
44 testing.SetRealm(testing.NewUserRealm(alice))
45 if got := Claim(cross(cur)); got != 500 {
46 t.Fatalf("claim at midpoint = %d, want 500", got)
47 }
48 if got := BalanceOf(alice); got != 500 {
49 t.Errorf("alice liquid balance = %d, want 500", got)
50 }
51
52 testing.SkipHeights(50)
53 testing.SetRealm(testing.NewUserRealm(alice))
54 if got := Claim(cross(cur)); got != 500 {
55 t.Fatalf("claim at end = %d, want 500", got)
56 }
57 if got := BalanceOf(alice); got != 1000 {
58 t.Errorf("alice liquid balance = %d, want 1000", got)
59 }
60
61 total, claimed, claimable := GrantOf(alice)
62 if total != 0 || claimed != 0 || claimable != 0 {
63 t.Errorf("grant should be gone after full claim, got total=%d claimed=%d claimable=%d", total, claimed, claimable)
64 }
65}
66
67// TestActiveGrantBlocksNewGrant asserts a beneficiary can't be granted twice
68// while a previous grant is still unclaimed.
69func TestActiveGrantBlocksNewGrant(cur realm, t *testing.T) {
70 reset()
71
72 testing.SetRealm(testing.NewUserRealm(alice))
73 MintVested(cross(cur), alice, 100, 10)
74
75 // Aborts from a cross(cur) call cannot be caught by a plain recover();
76 // assert on the abort message instead.
77 uassert.AbortsWithMessage(t, cur, "vestoken: beneficiary already has an unclaimed grant", func() {
78 MintVested(cross(cur), alice, 50, 10)
79 })
80}
81
82// TestTransferClaimedBalance checks claimed tokens behave like a normal
83// transferable ERC-20 balance.
84func TestTransferClaimedBalance(cur realm, t *testing.T) {
85 reset()
86
87 testing.SetRealm(testing.NewUserRealm(alice))
88 MintVested(cross(cur), alice, 200, 10)
89
90 testing.SkipHeights(10)
91 testing.SetRealm(testing.NewUserRealm(alice))
92 Claim(cross(cur))
93
94 testing.SetRealm(testing.NewUserRealm(alice))
95 Transfer(cross(cur), bob, 80)
96
97 if got := BalanceOf(alice); got != 120 {
98 t.Errorf("alice balance = %d, want 120", got)
99 }
100 if got := BalanceOf(bob); got != 80 {
101 t.Errorf("bob balance = %d, want 80", got)
102 }
103}
104
105// TestRenderContainsMetadata checks the Markdown view exposes name/symbol
106// and the active grant.
107func TestRenderContainsMetadata(cur realm, t *testing.T) {
108 reset()
109
110 testing.SetRealm(testing.NewUserRealm(alice))
111 MintVested(cross(cur), alice, 42, 10)
112
113 out := Render("")
114 for _, want := range []string{"VestToken", "VEST", "Total supply", "42"} {
115 if !strings.Contains(out, want) {
116 t.Errorf("render output missing %q\n%s", want, out)
117 }
118 }
119}