github.com/ethersphere/bee/v2@v2.2.0/pkg/settlement/swap/chequebook/chequestore_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 "math/big" 11 "testing" 12 13 "github.com/ethereum/go-ethereum/common" 14 "github.com/ethersphere/bee/v2/pkg/settlement/swap/chequebook" 15 storemock "github.com/ethersphere/bee/v2/pkg/statestore/mock" 16 transactionmock "github.com/ethersphere/bee/v2/pkg/transaction/mock" 17 ) 18 19 func TestReceiveCheque(t *testing.T) { 20 t.Parallel() 21 22 store := storemock.NewStateStore() 23 beneficiary := common.HexToAddress("0xffff") 24 issuer := common.HexToAddress("0xbeee") 25 cumulativePayout := big.NewInt(101) 26 cumulativePayout2 := big.NewInt(201) 27 chequebookAddress := common.HexToAddress("0xeeee") 28 sig := make([]byte, 65) 29 chainID := int64(1) 30 exchangeRate := big.NewInt(10) 31 deduction := big.NewInt(1) 32 33 cheque := &chequebook.SignedCheque{ 34 Cheque: chequebook.Cheque{ 35 Beneficiary: beneficiary, 36 CumulativePayout: cumulativePayout, 37 Chequebook: chequebookAddress, 38 }, 39 Signature: sig, 40 } 41 42 var verifiedWithFactory bool 43 factory := &factoryMock{ 44 verifyChequebook: func(ctx context.Context, address common.Address) error { 45 if address != chequebookAddress { 46 t.Fatal("verifying wrong chequebook") 47 } 48 verifiedWithFactory = true 49 return nil 50 }, 51 } 52 53 chequestore := chequebook.NewChequeStore( 54 store, 55 factory, 56 chainID, 57 beneficiary, 58 transactionmock.New( 59 transactionmock.WithABICallSequence( 60 transactionmock.ABICall(&chequebookABI, chequebookAddress, common.BytesToHash(issuer.Bytes()).Bytes(), "issuer"), 61 transactionmock.ABICall(&chequebookABI, chequebookAddress, cumulativePayout2.FillBytes(make([]byte, 32)), "balance"), 62 transactionmock.ABICall(&chequebookABI, chequebookAddress, big.NewInt(0).FillBytes(make([]byte, 32)), "paidOut", beneficiary), 63 transactionmock.ABICall(&chequebookABI, chequebookAddress, common.BytesToHash(issuer.Bytes()).Bytes(), "issuer"), 64 transactionmock.ABICall(&chequebookABI, chequebookAddress, cumulativePayout2.FillBytes(make([]byte, 32)), "balance"), 65 transactionmock.ABICall(&chequebookABI, chequebookAddress, big.NewInt(0).FillBytes(make([]byte, 32)), "paidOut", beneficiary), 66 ), 67 ), 68 func(c *chequebook.SignedCheque, cid int64) (common.Address, error) { 69 if cid != chainID { 70 t.Fatalf("recovery with wrong chain id. wanted %d, got %d", chainID, cid) 71 } 72 if !cheque.Equal(c) { 73 t.Fatalf("recovery with wrong cheque. wanted %v, got %v", cheque, c) 74 } 75 return issuer, nil 76 }) 77 78 received, err := chequestore.ReceiveCheque(context.Background(), cheque, exchangeRate, deduction) 79 if err != nil { 80 t.Fatal(err) 81 } 82 83 if !verifiedWithFactory { 84 t.Fatal("did not verify with factory") 85 } 86 87 if received.Cmp(cumulativePayout) != 0 { 88 t.Fatalf("calculated wrong received cumulativePayout. wanted %d, got %d", cumulativePayout, received) 89 } 90 91 lastCheque, err := chequestore.LastCheque(chequebookAddress) 92 if err != nil { 93 t.Fatal(err) 94 } 95 96 if !cheque.Equal(lastCheque) { 97 t.Fatalf("stored wrong cheque. wanted %v, got %v", cheque, lastCheque) 98 } 99 100 cheque = &chequebook.SignedCheque{ 101 Cheque: chequebook.Cheque{ 102 Beneficiary: beneficiary, 103 CumulativePayout: cumulativePayout2, 104 Chequebook: chequebookAddress, 105 }, 106 Signature: sig, 107 } 108 109 verifiedWithFactory = false 110 received, err = chequestore.ReceiveCheque(context.Background(), cheque, exchangeRate, deduction) 111 if err != nil { 112 t.Fatal(err) 113 } 114 115 if verifiedWithFactory { 116 t.Fatal("needlessly verify with factory") 117 } 118 119 expectedReceived := big.NewInt(0).Sub(cumulativePayout2, cumulativePayout) 120 if received.Cmp(expectedReceived) != 0 { 121 t.Fatalf("calculated wrong received cumulativePayout. wanted %d, got %d", expectedReceived, received) 122 } 123 } 124 125 func TestReceiveChequeInvalidBeneficiary(t *testing.T) { 126 t.Parallel() 127 128 store := storemock.NewStateStore() 129 beneficiary := common.HexToAddress("0xffff") 130 issuer := common.HexToAddress("0xbeee") 131 cumulativePayout := big.NewInt(10) 132 chequebookAddress := common.HexToAddress("0xeeee") 133 sig := make([]byte, 65) 134 chainID := int64(1) 135 136 cheque := &chequebook.SignedCheque{ 137 Cheque: chequebook.Cheque{ 138 Beneficiary: issuer, 139 CumulativePayout: cumulativePayout, 140 Chequebook: chequebookAddress, 141 }, 142 Signature: sig, 143 } 144 145 chequestore := chequebook.NewChequeStore( 146 store, 147 &factoryMock{}, 148 chainID, 149 beneficiary, 150 transactionmock.New(), 151 nil, 152 ) 153 154 _, err := chequestore.ReceiveCheque(context.Background(), cheque, cumulativePayout, big.NewInt(0)) 155 if err == nil { 156 t.Fatal("accepted cheque with wrong beneficiary") 157 } 158 if !errors.Is(err, chequebook.ErrWrongBeneficiary) { 159 t.Fatalf("wrong error. wanted %v, got %v", chequebook.ErrWrongBeneficiary, err) 160 } 161 } 162 163 func TestReceiveChequeInvalidAmount(t *testing.T) { 164 t.Parallel() 165 166 store := storemock.NewStateStore() 167 beneficiary := common.HexToAddress("0xffff") 168 issuer := common.HexToAddress("0xbeee") 169 cumulativePayout := big.NewInt(10) 170 cumulativePayoutLower := big.NewInt(5) 171 chequebookAddress := common.HexToAddress("0xeeee") 172 sig := make([]byte, 65) 173 chainID := int64(1) 174 175 chequestore := chequebook.NewChequeStore( 176 store, 177 &factoryMock{ 178 verifyChequebook: func(ctx context.Context, address common.Address) error { 179 return nil 180 }, 181 }, 182 chainID, 183 beneficiary, 184 transactionmock.New( 185 transactionmock.WithABICallSequence( 186 transactionmock.ABICall(&chequebookABI, chequebookAddress, common.BytesToHash(issuer.Bytes()).Bytes(), "issuer"), 187 transactionmock.ABICall(&chequebookABI, chequebookAddress, cumulativePayout.FillBytes(make([]byte, 32)), "balance"), 188 transactionmock.ABICall(&chequebookABI, chequebookAddress, big.NewInt(0).FillBytes(make([]byte, 32)), "paidOut", beneficiary), 189 ), 190 ), 191 func(c *chequebook.SignedCheque, cid int64) (common.Address, error) { 192 return issuer, nil 193 }) 194 195 _, err := chequestore.ReceiveCheque(context.Background(), &chequebook.SignedCheque{ 196 Cheque: chequebook.Cheque{ 197 Beneficiary: beneficiary, 198 CumulativePayout: cumulativePayout, 199 Chequebook: chequebookAddress, 200 }, 201 Signature: sig, 202 }, cumulativePayout, big.NewInt(0)) 203 if err != nil { 204 t.Fatal(err) 205 } 206 207 _, err = chequestore.ReceiveCheque(context.Background(), &chequebook.SignedCheque{ 208 Cheque: chequebook.Cheque{ 209 Beneficiary: beneficiary, 210 CumulativePayout: cumulativePayoutLower, 211 Chequebook: chequebookAddress, 212 }, 213 Signature: sig, 214 }, cumulativePayout, big.NewInt(0)) 215 if err == nil { 216 t.Fatal("accepted lower amount cheque") 217 } 218 if !errors.Is(err, chequebook.ErrChequeNotIncreasing) { 219 t.Fatalf("wrong error. wanted %v, got %v", chequebook.ErrChequeNotIncreasing, err) 220 } 221 } 222 223 func TestReceiveChequeInvalidChequebook(t *testing.T) { 224 t.Parallel() 225 226 store := storemock.NewStateStore() 227 beneficiary := common.HexToAddress("0xffff") 228 issuer := common.HexToAddress("0xbeee") 229 cumulativePayout := big.NewInt(10) 230 chequebookAddress := common.HexToAddress("0xeeee") 231 sig := make([]byte, 65) 232 chainID := int64(1) 233 234 chequestore := chequebook.NewChequeStore( 235 store, 236 &factoryMock{ 237 verifyChequebook: func(ctx context.Context, address common.Address) error { 238 return chequebook.ErrNotDeployedByFactory 239 }, 240 }, 241 chainID, 242 beneficiary, 243 transactionmock.New( 244 transactionmock.WithABICallSequence( 245 transactionmock.ABICall(&chequebookABI, chequebookAddress, issuer.Bytes(), "issuer"), 246 transactionmock.ABICall(&chequebookABI, chequebookAddress, cumulativePayout.FillBytes(make([]byte, 32)), "balance"), 247 ), 248 ), 249 func(c *chequebook.SignedCheque, cid int64) (common.Address, error) { 250 return issuer, nil 251 }) 252 253 _, err := chequestore.ReceiveCheque(context.Background(), &chequebook.SignedCheque{ 254 Cheque: chequebook.Cheque{ 255 Beneficiary: beneficiary, 256 CumulativePayout: cumulativePayout, 257 Chequebook: chequebookAddress, 258 }, 259 Signature: sig, 260 }, cumulativePayout, big.NewInt(0)) 261 if !errors.Is(err, chequebook.ErrNotDeployedByFactory) { 262 t.Fatalf("wrong error. wanted %v, got %v", chequebook.ErrNotDeployedByFactory, err) 263 } 264 } 265 266 func TestReceiveChequeInvalidSignature(t *testing.T) { 267 t.Parallel() 268 269 store := storemock.NewStateStore() 270 beneficiary := common.HexToAddress("0xffff") 271 issuer := common.HexToAddress("0xbeee") 272 cumulativePayout := big.NewInt(10) 273 chequebookAddress := common.HexToAddress("0xeeee") 274 sig := make([]byte, 65) 275 chainID := int64(1) 276 277 chequestore := chequebook.NewChequeStore( 278 store, 279 &factoryMock{ 280 verifyChequebook: func(ctx context.Context, address common.Address) error { 281 return nil 282 }, 283 }, 284 chainID, 285 beneficiary, 286 transactionmock.New( 287 transactionmock.WithABICallSequence( 288 transactionmock.ABICall(&chequebookABI, chequebookAddress, common.BytesToHash(issuer.Bytes()).Bytes(), "issuer"), 289 ), 290 ), 291 func(c *chequebook.SignedCheque, cid int64) (common.Address, error) { 292 return common.Address{}, nil 293 }) 294 295 _, err := chequestore.ReceiveCheque(context.Background(), &chequebook.SignedCheque{ 296 Cheque: chequebook.Cheque{ 297 Beneficiary: beneficiary, 298 CumulativePayout: cumulativePayout, 299 Chequebook: chequebookAddress, 300 }, 301 Signature: sig, 302 }, cumulativePayout, big.NewInt(0)) 303 if !errors.Is(err, chequebook.ErrChequeInvalid) { 304 t.Fatalf("wrong error. wanted %v, got %v", chequebook.ErrChequeInvalid, err) 305 } 306 } 307 308 func TestReceiveChequeInsufficientBalance(t *testing.T) { 309 t.Parallel() 310 311 store := storemock.NewStateStore() 312 beneficiary := common.HexToAddress("0xffff") 313 issuer := common.HexToAddress("0xbeee") 314 cumulativePayout := big.NewInt(10) 315 chequebookAddress := common.HexToAddress("0xeeee") 316 sig := make([]byte, 65) 317 chainID := int64(1) 318 319 chequestore := chequebook.NewChequeStore( 320 store, 321 &factoryMock{ 322 verifyChequebook: func(ctx context.Context, address common.Address) error { 323 return nil 324 }, 325 }, 326 chainID, 327 beneficiary, 328 transactionmock.New( 329 transactionmock.WithABICallSequence( 330 transactionmock.ABICall(&chequebookABI, chequebookAddress, common.BytesToHash(issuer.Bytes()).Bytes(), "issuer"), 331 transactionmock.ABICall(&chequebookABI, chequebookAddress, new(big.Int).Sub(cumulativePayout, big.NewInt(1)).FillBytes(make([]byte, 32)), "balance"), 332 transactionmock.ABICall(&chequebookABI, chequebookAddress, big.NewInt(0).FillBytes(make([]byte, 32)), "paidOut", beneficiary), 333 ), 334 ), 335 func(c *chequebook.SignedCheque, cid int64) (common.Address, error) { 336 return issuer, nil 337 }) 338 339 _, err := chequestore.ReceiveCheque(context.Background(), &chequebook.SignedCheque{ 340 Cheque: chequebook.Cheque{ 341 Beneficiary: beneficiary, 342 CumulativePayout: cumulativePayout, 343 Chequebook: chequebookAddress, 344 }, 345 Signature: sig, 346 }, cumulativePayout, big.NewInt(0)) 347 if !errors.Is(err, chequebook.ErrBouncingCheque) { 348 t.Fatalf("wrong error. wanted %v, got %v", chequebook.ErrBouncingCheque, err) 349 } 350 } 351 352 func TestReceiveChequeSufficientBalancePaidOut(t *testing.T) { 353 t.Parallel() 354 355 store := storemock.NewStateStore() 356 beneficiary := common.HexToAddress("0xffff") 357 issuer := common.HexToAddress("0xbeee") 358 cumulativePayout := big.NewInt(10) 359 chequebookAddress := common.HexToAddress("0xeeee") 360 sig := make([]byte, 65) 361 chainID := int64(1) 362 363 chequestore := chequebook.NewChequeStore( 364 store, 365 &factoryMock{ 366 verifyChequebook: func(ctx context.Context, address common.Address) error { 367 return nil 368 }, 369 }, 370 chainID, 371 beneficiary, 372 transactionmock.New( 373 transactionmock.WithABICallSequence( 374 transactionmock.ABICall(&chequebookABI, chequebookAddress, common.BytesToHash(issuer.Bytes()).Bytes(), "issuer"), 375 transactionmock.ABICall(&chequebookABI, chequebookAddress, new(big.Int).Sub(cumulativePayout, big.NewInt(100)).FillBytes(make([]byte, 32)), "balance"), 376 transactionmock.ABICall(&chequebookABI, chequebookAddress, big.NewInt(0).FillBytes(make([]byte, 32)), "paidOut", beneficiary), 377 ), 378 ), 379 func(c *chequebook.SignedCheque, cid int64) (common.Address, error) { 380 return issuer, nil 381 }) 382 383 _, err := chequestore.ReceiveCheque(context.Background(), &chequebook.SignedCheque{ 384 Cheque: chequebook.Cheque{ 385 Beneficiary: beneficiary, 386 CumulativePayout: cumulativePayout, 387 Chequebook: chequebookAddress, 388 }, 389 Signature: sig, 390 }, cumulativePayout, big.NewInt(0)) 391 if err != nil { 392 t.Fatal(err) 393 } 394 } 395 396 func TestReceiveChequeNotEnoughValue(t *testing.T) { 397 t.Parallel() 398 399 store := storemock.NewStateStore() 400 beneficiary := common.HexToAddress("0xffff") 401 issuer := common.HexToAddress("0xbeee") 402 cumulativePayout := big.NewInt(100) 403 chequebookAddress := common.HexToAddress("0xeeee") 404 sig := make([]byte, 65) 405 chainID := int64(1) 406 exchangeRate := big.NewInt(101) 407 deduction := big.NewInt(0) 408 409 cheque := &chequebook.SignedCheque{ 410 Cheque: chequebook.Cheque{ 411 Beneficiary: beneficiary, 412 CumulativePayout: cumulativePayout, 413 Chequebook: chequebookAddress, 414 }, 415 Signature: sig, 416 } 417 418 factory := &factoryMock{ 419 verifyChequebook: func(ctx context.Context, address common.Address) error { 420 if address != chequebookAddress { 421 t.Fatal("verifying wrong chequebook") 422 } 423 return nil 424 }, 425 } 426 427 chequestore := chequebook.NewChequeStore( 428 store, 429 factory, 430 chainID, 431 beneficiary, 432 transactionmock.New( 433 transactionmock.WithABICallSequence( 434 transactionmock.ABICall(&chequebookABI, chequebookAddress, common.BytesToHash(issuer.Bytes()).Bytes(), "issuer"), 435 transactionmock.ABICall(&chequebookABI, chequebookAddress, cumulativePayout.FillBytes(make([]byte, 32)), "balance"), 436 transactionmock.ABICall(&chequebookABI, chequebookAddress, big.NewInt(0).FillBytes(make([]byte, 32)), "paidOut", beneficiary), 437 ), 438 ), 439 func(c *chequebook.SignedCheque, cid int64) (common.Address, error) { 440 if cid != chainID { 441 t.Fatalf("recovery with wrong chain id. wanted %d, got %d", chainID, cid) 442 } 443 if !cheque.Equal(c) { 444 t.Fatalf("recovery with wrong cheque. wanted %v, got %v", cheque, c) 445 } 446 return issuer, nil 447 }) 448 449 _, err := chequestore.ReceiveCheque(context.Background(), cheque, exchangeRate, deduction) 450 if !errors.Is(err, chequebook.ErrChequeValueTooLow) { 451 t.Fatalf("got wrong error. wanted %v, got %v", chequebook.ErrChequeValueTooLow, err) 452 } 453 } 454 455 func TestReceiveChequeNotEnoughValueAfterDeduction(t *testing.T) { 456 t.Parallel() 457 458 store := storemock.NewStateStore() 459 beneficiary := common.HexToAddress("0xffff") 460 issuer := common.HexToAddress("0xbeee") 461 cumulativePayout := big.NewInt(100) 462 chequebookAddress := common.HexToAddress("0xeeee") 463 sig := make([]byte, 65) 464 chainID := int64(1) 465 466 // cheque needs to cover initial deduction (if applicable) plus one times the exchange rate 467 // in order to amount to at least 1 accounting credit and be accepted 468 // in this test cheque amount is just not enough to cover that therefore we expect 469 470 exchangeRate := big.NewInt(100) 471 deduction := big.NewInt(1) 472 473 cheque := &chequebook.SignedCheque{ 474 Cheque: chequebook.Cheque{ 475 Beneficiary: beneficiary, 476 CumulativePayout: cumulativePayout, 477 Chequebook: chequebookAddress, 478 }, 479 Signature: sig, 480 } 481 482 factory := &factoryMock{ 483 verifyChequebook: func(ctx context.Context, address common.Address) error { 484 if address != chequebookAddress { 485 t.Fatal("verifying wrong chequebook") 486 } 487 return nil 488 }, 489 } 490 491 chequestore := chequebook.NewChequeStore( 492 store, 493 factory, 494 chainID, 495 beneficiary, 496 transactionmock.New( 497 transactionmock.WithABICallSequence( 498 transactionmock.ABICall(&chequebookABI, chequebookAddress, common.BytesToHash(issuer.Bytes()).Bytes(), "issuer"), 499 transactionmock.ABICall(&chequebookABI, chequebookAddress, cumulativePayout.FillBytes(make([]byte, 32)), "balance"), 500 transactionmock.ABICall(&chequebookABI, chequebookAddress, big.NewInt(0).FillBytes(make([]byte, 32)), "paidOut", beneficiary), 501 ), 502 ), 503 func(c *chequebook.SignedCheque, cid int64) (common.Address, error) { 504 if cid != chainID { 505 t.Fatalf("recovery with wrong chain id. wanted %d, got %d", chainID, cid) 506 } 507 if !cheque.Equal(c) { 508 t.Fatalf("recovery with wrong cheque. wanted %v, got %v", cheque, c) 509 } 510 return issuer, nil 511 }) 512 513 _, err := chequestore.ReceiveCheque(context.Background(), cheque, exchangeRate, deduction) 514 if !errors.Is(err, chequebook.ErrChequeValueTooLow) { 515 t.Fatalf("got wrong error. wanted %v, got %v", chequebook.ErrChequeValueTooLow, err) 516 } 517 }