github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/wallet/wallet_test.go (about) 1 package wallet 2 3 import ( 4 "encoding/json" 5 "path" 6 "path/filepath" 7 "testing" 8 9 "github.com/nspcc-dev/neo-go/pkg/encoding/address" 10 "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" 11 "github.com/nspcc-dev/neo-go/pkg/util" 12 "github.com/stretchr/testify/assert" 13 "github.com/stretchr/testify/require" 14 ) 15 16 const ( 17 walletTemplate = "testWallet" 18 ) 19 20 func TestNewWallet(t *testing.T) { 21 wallet := checkWalletConstructor(t) 22 require.NotNil(t, wallet) 23 } 24 25 func TestNewWalletFromFile_Negative_EmptyFile(t *testing.T) { 26 _ = checkWalletConstructor(t) 27 walletFromFile, err2 := NewWalletFromFile(walletTemplate) 28 require.Errorf(t, err2, "EOF") 29 require.Nil(t, walletFromFile) 30 } 31 32 func TestNewWalletFromFile_Negative_NoFile(t *testing.T) { 33 _, err := NewWalletFromFile(walletTemplate) 34 require.Errorf(t, err, "open testWallet: no such file or directory") 35 } 36 37 func TestCreateAccountAndClose(t *testing.T) { 38 wallet := checkWalletConstructor(t) 39 40 errAcc := wallet.CreateAccount("testName", "testPass") 41 require.NoError(t, errAcc) 42 accounts := wallet.Accounts 43 require.Len(t, accounts, 1) 44 require.True(t, wallet.Accounts[0].CanSign()) 45 wallet.Close() 46 require.False(t, wallet.Accounts[0].CanSign()) 47 } 48 49 func TestAddAccount(t *testing.T) { 50 wallets := []*Wallet{ 51 checkWalletConstructor(t), 52 NewInMemoryWallet(), 53 } 54 55 for _, w := range wallets { 56 w.AddAccount(&Account{ 57 privateKey: nil, 58 Address: "real", 59 EncryptedWIF: "", 60 Label: "", 61 Contract: nil, 62 Locked: false, 63 Default: false, 64 }) 65 accounts := w.Accounts 66 require.Len(t, accounts, 1) 67 68 require.Error(t, w.RemoveAccount("abc")) 69 require.Len(t, w.Accounts, 1) 70 require.NoError(t, w.RemoveAccount("real")) 71 require.Len(t, w.Accounts, 0) 72 } 73 } 74 75 func TestPath(t *testing.T) { 76 wallet := checkWalletConstructor(t) 77 78 path := wallet.Path() 79 require.NotEmpty(t, path) 80 } 81 82 func TestSave(t *testing.T) { 83 inMemWallet := NewInMemoryWallet() 84 85 tmpDir := t.TempDir() 86 file := filepath.Join(tmpDir, walletTemplate) 87 inMemWallet.SetPath(file) 88 89 wallets := []*Wallet{ 90 checkWalletConstructor(t), 91 inMemWallet, 92 } 93 94 for _, w := range wallets { 95 w.AddAccount(&Account{ 96 privateKey: nil, 97 Address: "", 98 EncryptedWIF: "", 99 Label: "", 100 Contract: nil, 101 Locked: false, 102 Default: false, 103 }) 104 105 errForSave := w.Save() 106 require.NoError(t, errForSave) 107 108 openedWallet, err := NewWalletFromFile(w.path) 109 require.NoError(t, err) 110 require.Equal(t, w.Accounts, openedWallet.Accounts) 111 112 t.Run("change and rewrite", func(t *testing.T) { 113 err := openedWallet.CreateAccount("test", "pass") 114 require.NoError(t, err) 115 116 w2, err := NewWalletFromFile(openedWallet.path) 117 require.NoError(t, err) 118 require.Equal(t, 2, len(w2.Accounts)) 119 require.NoError(t, w2.Accounts[1].Decrypt("pass", w2.Scrypt)) 120 _ = w2.Accounts[1].ScriptHash() // openedWallet has it for acc 1. 121 require.Equal(t, openedWallet.Accounts, w2.Accounts) 122 }) 123 } 124 } 125 126 func TestJSONMarshallUnmarshal(t *testing.T) { 127 wallet := checkWalletConstructor(t) 128 129 bytes, err := wallet.JSON() 130 require.NoError(t, err) 131 require.NotNil(t, bytes) 132 133 unmarshalledWallet := &Wallet{} 134 errUnmarshal := json.Unmarshal(bytes, unmarshalledWallet) 135 136 require.NoError(t, errUnmarshal) 137 require.Equal(t, wallet.Version, unmarshalledWallet.Version) 138 require.Equal(t, wallet.Accounts, unmarshalledWallet.Accounts) 139 require.Equal(t, wallet.Scrypt, unmarshalledWallet.Scrypt) 140 } 141 142 func checkWalletConstructor(t *testing.T) *Wallet { 143 tmpDir := t.TempDir() 144 file := filepath.Join(tmpDir, walletTemplate) 145 wallet, err := NewWallet(file) 146 require.NoError(t, err) 147 return wallet 148 } 149 150 func TestWallet_AddToken(t *testing.T) { 151 w := checkWalletConstructor(t) 152 tok := NewToken(util.Uint160{1, 2, 3}, "Rubl", "RUB", 2, manifest.NEP17StandardName) 153 require.Equal(t, 0, len(w.Extra.Tokens)) 154 w.AddToken(tok) 155 require.Equal(t, 1, len(w.Extra.Tokens)) 156 require.Error(t, w.RemoveToken(util.Uint160{4, 5, 6})) 157 require.Equal(t, 1, len(w.Extra.Tokens)) 158 require.NoError(t, w.RemoveToken(tok.Hash)) 159 require.Equal(t, 0, len(w.Extra.Tokens)) 160 } 161 162 func TestWallet_GetAccount(t *testing.T) { 163 wallet := checkWalletConstructor(t) 164 accounts := []*Account{ 165 { 166 Contract: &Contract{ 167 Script: []byte{0, 1, 2, 3}, 168 }, 169 }, 170 { 171 Contract: &Contract{ 172 Script: []byte{3, 2, 1, 0}, 173 }, 174 }, 175 } 176 177 for _, acc := range accounts { 178 acc.Address = address.Uint160ToString(acc.Contract.ScriptHash()) 179 wallet.AddAccount(acc) 180 } 181 182 for i, acc := range accounts { 183 h := acc.Contract.ScriptHash() 184 assert.Equal(t, acc, wallet.GetAccount(h), "can't get %d account", i) 185 } 186 } 187 188 func TestWalletGetChangeAddress(t *testing.T) { 189 w1, err := NewWalletFromFile("testdata/wallet1.json") 190 require.NoError(t, err) 191 sh := w1.GetChangeAddress() 192 // No default address, the first one is used. 193 require.Equal(t, "Nhfg3TbpwogLvDGVvAvqyThbsHgoSUKwtn", address.Uint160ToString(sh)) 194 w2, err := NewWalletFromFile("testdata/wallet2.json") 195 require.NoError(t, err) 196 sh = w2.GetChangeAddress() 197 // Default address. 198 require.Equal(t, "NMUedC8TSV2rE17wGguSvPk9XcmHSaT275", address.Uint160ToString(sh)) 199 } 200 201 func TestWalletForExamples(t *testing.T) { 202 const ( 203 examplesDir = "../../examples" 204 walletFile = "my_wallet.json" 205 walletPass = "qwerty" 206 accountLabel = "my_account" 207 ) 208 w, err := NewWalletFromFile(path.Join(examplesDir, walletFile)) 209 require.NoError(t, err) 210 require.Equal(t, 1, len(w.Accounts)) 211 require.Equal(t, accountLabel, w.Accounts[0].Label) 212 require.NoError(t, w.Accounts[0].Decrypt(walletPass, w.Scrypt)) 213 214 // we need to keep the owner of the example contracts the same as the wallet account 215 require.Equal(t, "NbrUYaZgyhSkNoRo9ugRyEMdUZxrhkNaWB", w.Accounts[0].Address, "need to change `owner` in the example contracts") 216 } 217 218 func TestFromBytes(t *testing.T) { 219 wallet := checkWalletConstructor(t) 220 bts, err := wallet.JSON() 221 require.NoError(t, err) 222 223 w, err := NewWalletFromBytes(bts) 224 require.NoError(t, err) 225 226 require.Len(t, w.path, 0) 227 w.SetPath(wallet.path) 228 229 require.Equal(t, wallet, w) 230 }