github.com/ethersphere/bee/v2@v2.2.0/pkg/settlement/swap/chequebook/chequebook_test.go (about) 1 // Copyright 2020 The Swarm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package chequebook_test 6 7 import ( 8 "context" 9 "errors" 10 "fmt" 11 "math/big" 12 "testing" 13 14 "github.com/ethereum/go-ethereum/common" 15 "github.com/ethereum/go-ethereum/core/types" 16 "github.com/ethersphere/bee/v2/pkg/settlement/swap/chequebook" 17 erc20mock "github.com/ethersphere/bee/v2/pkg/settlement/swap/erc20/mock" 18 storemock "github.com/ethersphere/bee/v2/pkg/statestore/mock" 19 "github.com/ethersphere/bee/v2/pkg/transaction" 20 transactionmock "github.com/ethersphere/bee/v2/pkg/transaction/mock" 21 ) 22 23 func TestChequebookAddress(t *testing.T) { 24 t.Parallel() 25 26 address := common.HexToAddress("0xabcd") 27 ownerAdress := common.HexToAddress("0xfff") 28 chequebookService, err := chequebook.New( 29 transactionmock.New(), 30 address, 31 ownerAdress, 32 nil, 33 &chequeSignerMock{}, 34 erc20mock.New(), 35 ) 36 if err != nil { 37 t.Fatal(err) 38 } 39 40 if chequebookService.Address() != address { 41 t.Fatalf("returned wrong address. wanted %x, got %x", address, chequebookService.Address()) 42 } 43 } 44 45 func TestChequebookBalance(t *testing.T) { 46 t.Parallel() 47 48 address := common.HexToAddress("0xabcd") 49 ownerAdress := common.HexToAddress("0xfff") 50 balance := big.NewInt(10) 51 chequebookService, err := chequebook.New( 52 transactionmock.New( 53 transactionmock.WithABICall(&chequebookABI, address, balance.FillBytes(make([]byte, 32)), "balance"), 54 ), 55 address, 56 ownerAdress, 57 nil, 58 &chequeSignerMock{}, 59 erc20mock.New(), 60 ) 61 if err != nil { 62 t.Fatal(err) 63 } 64 65 returnedBalance, err := chequebookService.Balance(context.Background()) 66 if err != nil { 67 t.Fatal(err) 68 } 69 70 if returnedBalance.Cmp(balance) != 0 { 71 t.Fatalf("returned wrong balance. wanted %d, got %d", balance, returnedBalance) 72 } 73 } 74 75 func TestChequebookDeposit(t *testing.T) { 76 t.Parallel() 77 78 address := common.HexToAddress("0xabcd") 79 ownerAdress := common.HexToAddress("0xfff") 80 balance := big.NewInt(30) 81 depositAmount := big.NewInt(20) 82 txHash := common.HexToHash("0xdddd") 83 chequebookService, err := chequebook.New( 84 transactionmock.New(), 85 address, 86 ownerAdress, 87 nil, 88 &chequeSignerMock{}, 89 erc20mock.New( 90 erc20mock.WithBalanceOfFunc(func(ctx context.Context, address common.Address) (*big.Int, error) { 91 if address != ownerAdress { 92 return nil, errors.New("getting balance of wrong address") 93 } 94 return balance, nil 95 }), 96 erc20mock.WithTransferFunc(func(ctx context.Context, to common.Address, value *big.Int) (common.Hash, error) { 97 if to != address { 98 return common.Hash{}, fmt.Errorf("sending to wrong address. wanted %x, got %x", address, to) 99 } 100 if depositAmount.Cmp(value) != 0 { 101 return common.Hash{}, fmt.Errorf("sending wrong value. wanted %d, got %d", depositAmount, value) 102 } 103 return txHash, nil 104 }), 105 ), 106 ) 107 if err != nil { 108 t.Fatal(err) 109 } 110 111 returnedTxHash, err := chequebookService.Deposit(context.Background(), depositAmount) 112 if err != nil { 113 t.Fatal(err) 114 } 115 116 if txHash != returnedTxHash { 117 t.Fatalf("returned wrong transaction hash. wanted %v, got %v", txHash, returnedTxHash) 118 } 119 } 120 121 func TestChequebookWaitForDeposit(t *testing.T) { 122 t.Parallel() 123 124 address := common.HexToAddress("0xabcd") 125 ownerAdress := common.HexToAddress("0xfff") 126 txHash := common.HexToHash("0xdddd") 127 chequebookService, err := chequebook.New( 128 transactionmock.New( 129 transactionmock.WithWaitForReceiptFunc(func(ctx context.Context, tx common.Hash) (*types.Receipt, error) { 130 if tx != txHash { 131 t.Fatalf("waiting for wrong transaction. wanted %x, got %x", txHash, tx) 132 } 133 return &types.Receipt{ 134 Status: 1, 135 }, nil 136 }), 137 ), 138 address, 139 ownerAdress, 140 nil, 141 &chequeSignerMock{}, 142 erc20mock.New(), 143 ) 144 if err != nil { 145 t.Fatal(err) 146 } 147 148 err = chequebookService.WaitForDeposit(context.Background(), txHash) 149 if err != nil { 150 t.Fatal(err) 151 } 152 } 153 154 func TestChequebookWaitForDepositReverted(t *testing.T) { 155 t.Parallel() 156 157 address := common.HexToAddress("0xabcd") 158 ownerAdress := common.HexToAddress("0xfff") 159 txHash := common.HexToHash("0xdddd") 160 chequebookService, err := chequebook.New( 161 transactionmock.New( 162 transactionmock.WithWaitForReceiptFunc(func(ctx context.Context, tx common.Hash) (*types.Receipt, error) { 163 if tx != txHash { 164 t.Fatalf("waiting for wrong transaction. wanted %x, got %x", txHash, tx) 165 } 166 return &types.Receipt{ 167 Status: 0, 168 }, nil 169 }), 170 ), 171 address, 172 ownerAdress, 173 nil, 174 &chequeSignerMock{}, 175 erc20mock.New(), 176 ) 177 if err != nil { 178 t.Fatal(err) 179 } 180 181 err = chequebookService.WaitForDeposit(context.Background(), txHash) 182 if err == nil { 183 t.Fatal("expected reverted error") 184 } 185 if !errors.Is(err, transaction.ErrTransactionReverted) { 186 t.Fatalf("wrong error. wanted %v, got %v", transaction.ErrTransactionReverted, err) 187 } 188 } 189 190 func TestChequebookIssue(t *testing.T) { 191 t.Parallel() 192 193 address := common.HexToAddress("0xabcd") 194 beneficiary := common.HexToAddress("0xdddd") 195 ownerAdress := common.HexToAddress("0xfff") 196 store := storemock.NewStateStore() 197 amount := big.NewInt(20) 198 amount2 := big.NewInt(30) 199 expectedCumulative := big.NewInt(50) 200 sig := common.Hex2Bytes("0xffff") 201 chequeSigner := &chequeSignerMock{} 202 203 chequebookService, err := chequebook.New( 204 transactionmock.New( 205 transactionmock.WithABICallSequence( 206 transactionmock.ABICall(&chequebookABI, address, big.NewInt(100).FillBytes(make([]byte, 32)), "balance"), 207 transactionmock.ABICall(&chequebookABI, address, big.NewInt(0).FillBytes(make([]byte, 32)), "totalPaidOut"), 208 transactionmock.ABICall(&chequebookABI, address, big.NewInt(100).FillBytes(make([]byte, 32)), "balance"), 209 transactionmock.ABICall(&chequebookABI, address, big.NewInt(0).FillBytes(make([]byte, 32)), "totalPaidOut"), 210 transactionmock.ABICall(&chequebookABI, address, big.NewInt(100).FillBytes(make([]byte, 32)), "balance"), 211 transactionmock.ABICall(&chequebookABI, address, big.NewInt(0).FillBytes(make([]byte, 32)), "totalPaidOut"), 212 ), 213 ), 214 address, 215 ownerAdress, 216 store, 217 chequeSigner, 218 erc20mock.New(), 219 ) 220 if err != nil { 221 t.Fatal(err) 222 } 223 224 // issue a cheque 225 expectedCheque := &chequebook.SignedCheque{ 226 Cheque: chequebook.Cheque{ 227 Beneficiary: beneficiary, 228 CumulativePayout: amount, 229 Chequebook: address, 230 }, 231 Signature: sig, 232 } 233 234 chequeSigner.sign = func(cheque *chequebook.Cheque) ([]byte, error) { 235 if !cheque.Equal(&expectedCheque.Cheque) { 236 t.Fatalf("wrong cheque. wanted %v got %v", expectedCheque.Cheque, cheque) 237 } 238 return sig, nil 239 } 240 241 _, err = chequebookService.Issue(context.Background(), beneficiary, amount, func(cheque *chequebook.SignedCheque) error { 242 if !cheque.Equal(expectedCheque) { 243 t.Fatalf("wrong cheque. wanted %v got %v", expectedCheque, cheque) 244 } 245 return nil 246 }) 247 if err != nil { 248 t.Fatal(err) 249 } 250 251 lastCheque, err := chequebookService.LastCheque(beneficiary) 252 if err != nil { 253 t.Fatal(err) 254 } 255 256 if !lastCheque.Equal(expectedCheque) { 257 t.Fatalf("wrong cheque stored. wanted %v got %v", expectedCheque, lastCheque) 258 } 259 260 // issue another cheque for the same beneficiary 261 expectedCheque = &chequebook.SignedCheque{ 262 Cheque: chequebook.Cheque{ 263 Beneficiary: beneficiary, 264 CumulativePayout: expectedCumulative, 265 Chequebook: address, 266 }, 267 Signature: sig, 268 } 269 270 chequeSigner.sign = func(cheque *chequebook.Cheque) ([]byte, error) { 271 if !cheque.Equal(&expectedCheque.Cheque) { 272 t.Fatalf("wrong cheque. wanted %v got %v", expectedCheque, cheque) 273 } 274 return sig, nil 275 } 276 277 _, err = chequebookService.Issue(context.Background(), beneficiary, amount2, func(cheque *chequebook.SignedCheque) error { 278 if !cheque.Equal(expectedCheque) { 279 t.Fatalf("wrong cheque. wanted %v got %v", expectedCheque, cheque) 280 } 281 return nil 282 }) 283 if err != nil { 284 t.Fatal(err) 285 } 286 287 lastCheque, err = chequebookService.LastCheque(beneficiary) 288 if err != nil { 289 t.Fatal(err) 290 } 291 292 if !lastCheque.Equal(expectedCheque) { 293 t.Fatalf("wrong cheque stored. wanted %v got %v", expectedCheque, lastCheque) 294 } 295 296 // issue another cheque for the different beneficiary 297 expectedChequeOwner := &chequebook.SignedCheque{ 298 Cheque: chequebook.Cheque{ 299 Beneficiary: ownerAdress, 300 CumulativePayout: amount, 301 Chequebook: address, 302 }, 303 Signature: sig, 304 } 305 306 chequeSigner.sign = func(cheque *chequebook.Cheque) ([]byte, error) { 307 if !cheque.Equal(&expectedChequeOwner.Cheque) { 308 t.Fatalf("wrong cheque. wanted %v got %v", expectedCheque, cheque) 309 } 310 return sig, nil 311 } 312 313 _, err = chequebookService.Issue(context.Background(), ownerAdress, amount, func(cheque *chequebook.SignedCheque) error { 314 if !cheque.Equal(expectedChequeOwner) { 315 t.Fatalf("wrong cheque. wanted %v got %v", expectedChequeOwner, cheque) 316 } 317 return nil 318 }) 319 if err != nil { 320 t.Fatal(err) 321 } 322 323 lastCheque, err = chequebookService.LastCheque(ownerAdress) 324 if err != nil { 325 t.Fatal(err) 326 } 327 328 if !lastCheque.Equal(expectedChequeOwner) { 329 t.Fatalf("wrong cheque stored. wanted %v got %v", expectedChequeOwner, lastCheque) 330 } 331 332 // finally check this did not interfere with the beneficiary cheque 333 lastCheque, err = chequebookService.LastCheque(beneficiary) 334 if err != nil { 335 t.Fatal(err) 336 } 337 338 if !lastCheque.Equal(expectedCheque) { 339 t.Fatalf("wrong cheque stored. wanted %v got %v", expectedCheque, lastCheque) 340 } 341 } 342 343 func TestChequebookIssueErrorSend(t *testing.T) { 344 t.Parallel() 345 346 address := common.HexToAddress("0xabcd") 347 beneficiary := common.HexToAddress("0xdddd") 348 ownerAdress := common.HexToAddress("0xfff") 349 store := storemock.NewStateStore() 350 amount := big.NewInt(20) 351 sig := common.Hex2Bytes("0xffff") 352 chequeSigner := &chequeSignerMock{} 353 354 chequebookService, err := chequebook.New( 355 transactionmock.New(), 356 address, 357 ownerAdress, 358 store, 359 chequeSigner, 360 erc20mock.New(), 361 ) 362 if err != nil { 363 t.Fatal(err) 364 } 365 366 chequeSigner.sign = func(cheque *chequebook.Cheque) ([]byte, error) { 367 return sig, nil 368 } 369 370 _, err = chequebookService.Issue(context.Background(), beneficiary, amount, func(cheque *chequebook.SignedCheque) error { 371 return errors.New("err") 372 }) 373 if err == nil { 374 t.Fatal("expected error") 375 } 376 377 // verify the cheque was not saved 378 _, err = chequebookService.LastCheque(beneficiary) 379 if !errors.Is(err, chequebook.ErrNoCheque) { 380 t.Fatalf("wrong error. wanted %v, got %v", chequebook.ErrNoCheque, err) 381 } 382 } 383 384 func TestChequebookIssueOutOfFunds(t *testing.T) { 385 t.Parallel() 386 387 address := common.HexToAddress("0xabcd") 388 beneficiary := common.HexToAddress("0xdddd") 389 ownerAdress := common.HexToAddress("0xfff") 390 store := storemock.NewStateStore() 391 amount := big.NewInt(20) 392 393 chequebookService, err := chequebook.New( 394 transactionmock.New( 395 transactionmock.WithABICallSequence( 396 transactionmock.ABICall(&chequebookABI, address, big.NewInt(0).FillBytes(make([]byte, 32)), "balance"), 397 transactionmock.ABICall(&chequebookABI, address, big.NewInt(0).FillBytes(make([]byte, 32)), "totalPaidOut"), 398 ), 399 ), 400 address, 401 ownerAdress, 402 store, 403 &chequeSignerMock{}, 404 erc20mock.New(), 405 ) 406 if err != nil { 407 t.Fatal(err) 408 } 409 410 _, err = chequebookService.Issue(context.Background(), beneficiary, amount, func(cheque *chequebook.SignedCheque) error { 411 return nil 412 }) 413 if !errors.Is(err, chequebook.ErrOutOfFunds) { 414 t.Fatalf("wrong error. wanted %v, got %v", chequebook.ErrOutOfFunds, err) 415 } 416 417 // verify the cheque was not saved 418 _, err = chequebookService.LastCheque(beneficiary) 419 420 if !errors.Is(err, chequebook.ErrNoCheque) { 421 t.Fatalf("wrong error. wanted %v, got %v", chequebook.ErrNoCheque, err) 422 } 423 } 424 425 func TestChequebookWithdraw(t *testing.T) { 426 t.Parallel() 427 428 address := common.HexToAddress("0xabcd") 429 ownerAdress := common.HexToAddress("0xfff") 430 balance := big.NewInt(30) 431 withdrawAmount := big.NewInt(20) 432 txHash := common.HexToHash("0xdddd") 433 store := storemock.NewStateStore() 434 chequebookService, err := chequebook.New( 435 transactionmock.New( 436 transactionmock.WithABICallSequence( 437 transactionmock.ABICall(&chequebookABI, address, balance.FillBytes(make([]byte, 32)), "balance"), 438 transactionmock.ABICall(&chequebookABI, address, big.NewInt(0).FillBytes(make([]byte, 32)), "totalPaidOut"), 439 ), 440 transactionmock.WithABISend(&chequebookABI, txHash, address, big.NewInt(0), "withdraw", withdrawAmount), 441 ), 442 address, 443 ownerAdress, 444 store, 445 &chequeSignerMock{}, 446 erc20mock.New(), 447 ) 448 if err != nil { 449 t.Fatal(err) 450 } 451 452 returnedTxHash, err := chequebookService.Withdraw(context.Background(), withdrawAmount) 453 if err != nil { 454 t.Fatal(err) 455 } 456 457 if txHash != returnedTxHash { 458 t.Fatalf("returned wrong transaction hash. wanted %v, got %v", txHash, returnedTxHash) 459 } 460 } 461 462 func TestChequebookWithdrawInsufficientFunds(t *testing.T) { 463 t.Parallel() 464 465 address := common.HexToAddress("0xabcd") 466 ownerAdress := common.HexToAddress("0xfff") 467 withdrawAmount := big.NewInt(20) 468 txHash := common.HexToHash("0xdddd") 469 store := storemock.NewStateStore() 470 chequebookService, err := chequebook.New( 471 transactionmock.New( 472 transactionmock.WithABISend(&chequebookABI, txHash, address, big.NewInt(0), "withdraw", withdrawAmount), 473 transactionmock.WithABICallSequence( 474 transactionmock.ABICall(&chequebookABI, address, big.NewInt(0).FillBytes(make([]byte, 32)), "balance"), 475 transactionmock.ABICall(&chequebookABI, address, big.NewInt(0).FillBytes(make([]byte, 32)), "totalPaidOut"), 476 ), 477 ), 478 address, 479 ownerAdress, 480 store, 481 &chequeSignerMock{}, 482 erc20mock.New(), 483 ) 484 if err != nil { 485 t.Fatal(err) 486 } 487 488 _, err = chequebookService.Withdraw(context.Background(), withdrawAmount) 489 if !errors.Is(err, chequebook.ErrInsufficientFunds) { 490 t.Fatalf("got wrong error. wanted %v, got %v", chequebook.ErrInsufficientFunds, err) 491 } 492 } 493 494 func TestStateStoreKeys(t *testing.T) { 495 t.Parallel() 496 497 address := common.HexToAddress("0xabcd") 498 499 expected := "swap_cashout_000000000000000000000000000000000000abcd" 500 if chequebook.CashoutActionKey(address) != expected { 501 t.Fatalf("wrong cashout action key. wanted %s, got %s", expected, chequebook.CashoutActionKey(address)) 502 } 503 504 expected = "swap_chequebook_last_issued_cheque_000000000000000000000000000000000000abcd" 505 if chequebook.LastIssuedChequeKey(address) != expected { 506 t.Fatalf("wrong last issued cheque key. wanted %s, got %s", expected, chequebook.LastIssuedChequeKey(address)) 507 } 508 509 expected = "swap_chequebook_last_received_cheque__000000000000000000000000000000000000abcd" 510 if chequebook.LastReceivedChequeKey(address) != expected { 511 t.Fatalf("wrong last received cheque key. wanted %s, got %s", expected, chequebook.LastReceivedChequeKey(address)) 512 } 513 }