token_test.gno
5.89 Kb ยท 200 lines
1package grc20
2
3import (
4 "math"
5 "testing"
6
7 "gno.land/p/nt/testutils"
8 "gno.land/p/nt/uassert"
9 "gno.land/p/nt/ufmt"
10 "gno.land/p/nt/urequire"
11)
12
13func TestTestImpl(t *testing.T) {
14 bank, _ := NewToken("Dummy", "DUMMY", 4)
15 urequire.False(t, bank == nil, "dummy should not be nil")
16}
17
18func TestToken(t *testing.T) {
19 var (
20 alice = testutils.TestAddress("alice")
21 bob = testutils.TestAddress("bob")
22 carl = testutils.TestAddress("carl")
23 )
24
25 bank, adm := NewToken("Dummy", "DUMMY", 6)
26
27 checkBalances := func(aliceEB, bobEB, carlEB int64) {
28 t.Helper()
29 exp := ufmt.Sprintf("alice=%d bob=%d carl=%d", aliceEB, bobEB, carlEB)
30 aliceGB := bank.BalanceOf(alice)
31 bobGB := bank.BalanceOf(bob)
32 carlGB := bank.BalanceOf(carl)
33 got := ufmt.Sprintf("alice=%d bob=%d carl=%d", aliceGB, bobGB, carlGB)
34 uassert.Equal(t, got, exp, "invalid balances")
35 }
36 checkAllowances := func(abEB, acEB, baEB, bcEB, caEB, cbEB int64) {
37 t.Helper()
38 exp := ufmt.Sprintf("ab=%d ac=%d ba=%d bc=%d ca=%d cb=%s", abEB, acEB, baEB, bcEB, caEB, cbEB)
39 abGB := bank.Allowance(alice, bob)
40 acGB := bank.Allowance(alice, carl)
41 baGB := bank.Allowance(bob, alice)
42 bcGB := bank.Allowance(bob, carl)
43 caGB := bank.Allowance(carl, alice)
44 cbGB := bank.Allowance(carl, bob)
45 got := ufmt.Sprintf("ab=%d ac=%d ba=%d bc=%d ca=%d cb=%s", abGB, acGB, baGB, bcGB, caGB, cbGB)
46 uassert.Equal(t, got, exp, "invalid allowances")
47 }
48
49 checkBalances(0, 0, 0)
50 checkAllowances(0, 0, 0, 0, 0, 0)
51
52 urequire.NoError(t, adm.Mint(alice, 1000))
53 urequire.NoError(t, adm.Mint(alice, 100))
54 checkBalances(1100, 0, 0)
55 checkAllowances(0, 0, 0, 0, 0, 0)
56
57 urequire.NoError(t, adm.Approve(alice, bob, 99999999))
58 checkBalances(1100, 0, 0)
59 checkAllowances(99999999, 0, 0, 0, 0, 0)
60
61 urequire.NoError(t, adm.Approve(alice, bob, 400))
62 checkBalances(1100, 0, 0)
63 checkAllowances(400, 0, 0, 0, 0, 0)
64
65 urequire.Error(t, adm.TransferFrom(alice, bob, carl, 100000000))
66 checkBalances(1100, 0, 0)
67 checkAllowances(400, 0, 0, 0, 0, 0)
68
69 urequire.NoError(t, adm.TransferFrom(alice, bob, carl, 100))
70 checkBalances(1000, 0, 100)
71 checkAllowances(300, 0, 0, 0, 0, 0)
72
73 urequire.Error(t, adm.SpendAllowance(alice, bob, 2000000))
74 checkBalances(1000, 0, 100)
75 checkAllowances(300, 0, 0, 0, 0, 0)
76
77 urequire.NoError(t, adm.SpendAllowance(alice, bob, 100))
78 checkBalances(1000, 0, 100)
79 checkAllowances(200, 0, 0, 0, 0, 0)
80}
81
82func TestMintOverflow(t *testing.T) {
83 alice := testutils.TestAddress("alice")
84 bob := testutils.TestAddress("bob")
85 tok, adm := NewToken("Dummy", "DUMMY", 6)
86
87 safeValue := int64(1 << 62)
88 urequire.NoError(t, adm.Mint(alice, safeValue))
89 urequire.Equal(t, tok.BalanceOf(alice), safeValue)
90
91 err := adm.Mint(bob, safeValue)
92 uassert.Error(t, err, "expected ErrMintOverflow")
93}
94
95func TestTransferFromAtomicity(t *testing.T) {
96 var (
97 owner = testutils.TestAddress("owner")
98 spender = testutils.TestAddress("spender")
99
100 invalidRecipient = address("")
101 recipient = testutils.TestAddress("to")
102 )
103
104 token, admin := NewToken("Test", "TEST", 6)
105
106 // owner has 100 tokens, spender has 50 allowance
107 initialBalance := int64(100)
108 initialAllowance := int64(50)
109
110 urequire.NoError(t, admin.Mint(owner, initialBalance))
111 urequire.NoError(t, admin.Approve(owner, spender, initialAllowance))
112
113 // transfer to an invalid address to force a transfer failure
114 transferAmount := int64(30)
115 err := admin.TransferFrom(owner, spender, invalidRecipient, transferAmount)
116 uassert.Error(t, err, "transfer should fail due to invalid address")
117
118 ownerBalance := token.BalanceOf(owner)
119 uassert.Equal(t, ownerBalance, initialBalance, "owner balance should remain unchanged")
120
121 // check if allowance was incorrectly reduced
122 remainingAllowance := token.Allowance(owner, spender)
123 uassert.Equal(t, remainingAllowance, initialAllowance,
124 "allowance should not be reduced when transfer fails")
125
126 // transfer all tokens
127 admin.Transfer(owner, recipient, 100)
128 remainingBalance := token.BalanceOf(owner)
129 uassert.Equal(t, remainingBalance, int64(0),
130 "balance should be zero")
131
132 err = admin.TransferFrom(owner, spender, recipient, transferAmount)
133 uassert.Error(t, err, "transfer should fail due to insufficient balance")
134}
135
136func TestMintUntilOverflow(t *testing.T) {
137 alice := testutils.TestAddress("alice")
138 bob := testutils.TestAddress("bob")
139 tok, adm := NewToken("Dummy", "DUMMY", 6)
140
141 tests := []struct {
142 name string
143 addr address
144 amount int64
145 expectedError error
146 expectedSupply int64
147 description string
148 }{
149 {
150 name: "mint negative value",
151 addr: alice,
152 amount: -1,
153 expectedError: ErrInvalidAmount,
154 expectedSupply: 0,
155 description: "minting a negative number should fail with ErrInvalidAmount",
156 },
157 {
158 name: "mint MaxInt64",
159 addr: alice,
160 amount: math.MaxInt64 - 1000,
161 expectedError: nil,
162 expectedSupply: math.MaxInt64 - 1000,
163 description: "minting almost MaxInt64 should succeed",
164 },
165 {
166 name: "mint small value",
167 addr: bob,
168 amount: 1000,
169 expectedError: nil,
170 expectedSupply: math.MaxInt64,
171 description: "minting a small value when close to MaxInt64 should succeed",
172 },
173 {
174 name: "mint value that would exceed MaxInt64",
175 addr: bob,
176 amount: 1,
177 expectedError: ErrMintOverflow,
178 expectedSupply: math.MaxInt64,
179 description: "minting any value when at MaxInt64 should fail with ErrMintOverflow",
180 },
181 }
182
183 for _, tt := range tests {
184 t.Run(tt.name, func(t *testing.T) {
185 err := adm.Mint(tt.addr, tt.amount)
186
187 if tt.expectedError != nil {
188 uassert.Error(t, err, tt.description)
189 if err == nil || err.Error() != tt.expectedError.Error() {
190 t.Errorf("expected error %v, got %v", tt.expectedError, err)
191 }
192 } else {
193 uassert.NoError(t, err, tt.description)
194 }
195
196 totalSupply := tok.TotalSupply()
197 uassert.Equal(t, totalSupply, tt.expectedSupply, "totalSupply should match expected value")
198 })
199 }
200}