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