token_test.gno

5.52 Kb ยท 190 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	)
102
103	token, admin := NewToken("Test", "TEST", 6)
104
105	// owner has 100 tokens, spender has 50 allowance
106	initialBalance := int64(100)
107	initialAllowance := int64(50)
108
109	urequire.NoError(t, admin.Mint(owner, initialBalance))
110	urequire.NoError(t, admin.Approve(owner, spender, initialAllowance))
111
112	// transfer to an invalid address to force a transfer failure
113	transferAmount := int64(30)
114	err := admin.TransferFrom(owner, spender, invalidRecipient, transferAmount)
115	uassert.Error(t, err, "transfer should fail due to invalid address")
116
117	ownerBalance := token.BalanceOf(owner)
118	uassert.Equal(t, ownerBalance, initialBalance, "owner balance should remain unchanged")
119
120	// check if allowance was incorrectly reduced
121	remainingAllowance := token.Allowance(owner, spender)
122	uassert.Equal(t, remainingAllowance, initialAllowance,
123		"allowance should not be reduced when transfer fails")
124}
125
126func TestMintUntilOverflow(t *testing.T) {
127	alice := testutils.TestAddress("alice")
128	bob := testutils.TestAddress("bob")
129	tok, adm := NewToken("Dummy", "DUMMY", 6)
130
131	tests := []struct {
132		name           string
133		addr           address
134		amount         int64
135		expectedError  error
136		expectedSupply int64
137		description    string
138	}{
139		{
140			name:           "mint negative value",
141			addr:           alice,
142			amount:         -1,
143			expectedError:  ErrInvalidAmount,
144			expectedSupply: 0,
145			description:    "minting a negative number should fail with ErrInvalidAmount",
146		},
147		{
148			name:           "mint MaxInt64",
149			addr:           alice,
150			amount:         math.MaxInt64 - 1000,
151			expectedError:  nil,
152			expectedSupply: math.MaxInt64 - 1000,
153			description:    "minting almost MaxInt64 should succeed",
154		},
155		{
156			name:           "mint small value",
157			addr:           bob,
158			amount:         1000,
159			expectedError:  nil,
160			expectedSupply: math.MaxInt64,
161			description:    "minting a small value when close to MaxInt64 should succeed",
162		},
163		{
164			name:           "mint value that would exceed MaxInt64",
165			addr:           bob,
166			amount:         1,
167			expectedError:  ErrMintOverflow,
168			expectedSupply: math.MaxInt64,
169			description:    "minting any value when at MaxInt64 should fail with ErrMintOverflow",
170		},
171	}
172
173	for _, tt := range tests {
174		t.Run(tt.name, func(t *testing.T) {
175			err := adm.Mint(tt.addr, tt.amount)
176
177			if tt.expectedError != nil {
178				uassert.Error(t, err, tt.description)
179				if err == nil || err.Error() != tt.expectedError.Error() {
180					t.Errorf("expected error %v, got %v", tt.expectedError, err)
181				}
182			} else {
183				uassert.NoError(t, err, tt.description)
184			}
185
186			totalSupply := tok.TotalSupply()
187			uassert.Equal(t, totalSupply, tt.expectedSupply, "totalSupply should match expected value")
188		})
189	}
190}