Search Apps Documentation Source Content File Folder Download Copy Actions Download

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}