github.com/ethersphere/bee/v2@v2.2.0/pkg/api/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 api_test
     6  
     7  import (
     8  	"context"
     9  	"errors"
    10  	"math/big"
    11  	"net/http"
    12  	"reflect"
    13  	"testing"
    14  
    15  	"github.com/ethereum/go-ethereum/common"
    16  	"github.com/ethersphere/bee/v2/pkg/api"
    17  	"github.com/ethersphere/bee/v2/pkg/bigint"
    18  	"github.com/ethersphere/bee/v2/pkg/jsonhttp"
    19  	"github.com/ethersphere/bee/v2/pkg/jsonhttp/jsonhttptest"
    20  	"github.com/ethersphere/bee/v2/pkg/sctx"
    21  	"github.com/ethersphere/bee/v2/pkg/settlement/swap/chequebook"
    22  	"github.com/ethersphere/bee/v2/pkg/settlement/swap/chequebook/mock"
    23  	swapmock "github.com/ethersphere/bee/v2/pkg/settlement/swap/mock"
    24  
    25  	"github.com/ethersphere/bee/v2/pkg/swarm"
    26  )
    27  
    28  func TestChequebookBalance(t *testing.T) {
    29  	t.Parallel()
    30  
    31  	returnedBalance := big.NewInt(9000)
    32  	returnedAvailableBalance := big.NewInt(1000)
    33  
    34  	chequebookBalanceFunc := func(context.Context) (ret *big.Int, err error) {
    35  		return returnedBalance, nil
    36  	}
    37  
    38  	chequebookAvailableBalanceFunc := func(context.Context) (ret *big.Int, err error) {
    39  		return returnedAvailableBalance, nil
    40  	}
    41  
    42  	testServer, _, _, _ := newTestServer(t, testServerOptions{
    43  		ChequebookOpts: []mock.Option{
    44  			mock.WithChequebookBalanceFunc(chequebookBalanceFunc),
    45  			mock.WithChequebookAvailableBalanceFunc(chequebookAvailableBalanceFunc),
    46  		},
    47  	})
    48  
    49  	expected := &api.ChequebookBalanceResponse{
    50  		TotalBalance:     bigint.Wrap(returnedBalance),
    51  		AvailableBalance: bigint.Wrap(returnedAvailableBalance),
    52  	}
    53  
    54  	var got *api.ChequebookBalanceResponse
    55  	jsonhttptest.Request(t, testServer, http.MethodGet, "/chequebook/balance", http.StatusOK,
    56  		jsonhttptest.WithUnmarshalJSONResponse(&got),
    57  	)
    58  
    59  	if !reflect.DeepEqual(got, expected) {
    60  		t.Errorf("got balance: %+v, expected: %+v", got, expected)
    61  	}
    62  }
    63  
    64  func TestChequebookBalanceError(t *testing.T) {
    65  	t.Parallel()
    66  
    67  	wantErr := errors.New("New errors")
    68  	chequebookBalanceFunc := func(context.Context) (ret *big.Int, err error) {
    69  		return big.NewInt(0), wantErr
    70  	}
    71  
    72  	testServer, _, _, _ := newTestServer(t, testServerOptions{
    73  		ChequebookOpts: []mock.Option{mock.WithChequebookBalanceFunc(chequebookBalanceFunc)},
    74  	})
    75  
    76  	jsonhttptest.Request(t, testServer, http.MethodGet, "/chequebook/balance", http.StatusInternalServerError,
    77  		jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
    78  			Message: api.ErrChequebookBalance,
    79  			Code:    http.StatusInternalServerError,
    80  		}),
    81  	)
    82  }
    83  
    84  func TestChequebookAvailableBalanceError(t *testing.T) {
    85  	t.Parallel()
    86  
    87  	chequebookBalanceFunc := func(context.Context) (ret *big.Int, err error) {
    88  		return big.NewInt(0), nil
    89  	}
    90  
    91  	chequebookAvailableBalanceFunc := func(context.Context) (ret *big.Int, err error) {
    92  		return nil, errors.New("New errors")
    93  	}
    94  
    95  	testServer, _, _, _ := newTestServer(t, testServerOptions{
    96  		ChequebookOpts: []mock.Option{
    97  			mock.WithChequebookBalanceFunc(chequebookBalanceFunc),
    98  			mock.WithChequebookAvailableBalanceFunc(chequebookAvailableBalanceFunc),
    99  		},
   100  	})
   101  
   102  	jsonhttptest.Request(t, testServer, http.MethodGet, "/chequebook/balance", http.StatusInternalServerError,
   103  		jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
   104  			Message: api.ErrChequebookBalance,
   105  			Code:    http.StatusInternalServerError,
   106  		}),
   107  	)
   108  }
   109  
   110  func TestChequebookAddress(t *testing.T) {
   111  	t.Parallel()
   112  
   113  	chequebookAddressFunc := func() common.Address {
   114  		return common.HexToAddress("0xfffff")
   115  	}
   116  
   117  	testServer, _, _, _ := newTestServer(t, testServerOptions{
   118  		ChequebookOpts: []mock.Option{mock.WithChequebookAddressFunc(chequebookAddressFunc)},
   119  	})
   120  
   121  	address := common.HexToAddress("0xfffff")
   122  
   123  	expected := &api.ChequebookAddressResponse{
   124  		Address: address.String(),
   125  	}
   126  
   127  	var got *api.ChequebookAddressResponse
   128  	jsonhttptest.Request(t, testServer, http.MethodGet, "/chequebook/address", http.StatusOK,
   129  		jsonhttptest.WithUnmarshalJSONResponse(&got),
   130  	)
   131  
   132  	if !reflect.DeepEqual(got, expected) {
   133  		t.Errorf("got address: %+v, expected: %+v", got, expected)
   134  	}
   135  }
   136  
   137  func TestChequebookWithdraw(t *testing.T) {
   138  	t.Parallel()
   139  
   140  	txHash := common.HexToHash("0xfffff")
   141  
   142  	t.Run("ok", func(t *testing.T) {
   143  		t.Parallel()
   144  
   145  		chequebookWithdrawFunc := func(ctx context.Context, amount *big.Int) (hash common.Hash, err error) {
   146  			if amount.Cmp(big.NewInt(500)) == 0 {
   147  				return txHash, nil
   148  			}
   149  			return common.Hash{}, nil
   150  		}
   151  
   152  		testServer, _, _, _ := newTestServer(t, testServerOptions{
   153  			ChequebookOpts: []mock.Option{mock.WithChequebookWithdrawFunc(chequebookWithdrawFunc)},
   154  		})
   155  
   156  		expected := &api.ChequebookTxResponse{TransactionHash: txHash}
   157  
   158  		var got *api.ChequebookTxResponse
   159  		jsonhttptest.Request(t, testServer, http.MethodPost, "/chequebook/withdraw?amount=500", http.StatusOK,
   160  			jsonhttptest.WithUnmarshalJSONResponse(&got),
   161  		)
   162  
   163  		if !reflect.DeepEqual(got, expected) {
   164  			t.Errorf("got address: %+v, expected: %+v", got, expected)
   165  		}
   166  	})
   167  
   168  	t.Run("custom gas", func(t *testing.T) {
   169  		t.Parallel()
   170  
   171  		chequebookWithdrawFunc := func(ctx context.Context, amount *big.Int) (hash common.Hash, err error) {
   172  			if sctx.GetGasPrice(ctx).Cmp(big.NewInt(10)) != 0 {
   173  				return common.Hash{}, errors.New("wrong gas price")
   174  			}
   175  			if amount.Cmp(big.NewInt(500)) == 0 {
   176  				return txHash, nil
   177  			}
   178  			return common.Hash{}, nil
   179  		}
   180  
   181  		testServer, _, _, _ := newTestServer(t, testServerOptions{
   182  			ChequebookOpts: []mock.Option{mock.WithChequebookWithdrawFunc(chequebookWithdrawFunc)},
   183  		})
   184  
   185  		expected := &api.ChequebookTxResponse{TransactionHash: txHash}
   186  
   187  		var got *api.ChequebookTxResponse
   188  		jsonhttptest.Request(t, testServer, http.MethodPost, "/chequebook/withdraw?amount=500", http.StatusOK,
   189  			jsonhttptest.WithRequestHeader(api.GasPriceHeader, "10"),
   190  			jsonhttptest.WithUnmarshalJSONResponse(&got),
   191  		)
   192  
   193  		if !reflect.DeepEqual(got, expected) {
   194  			t.Errorf("got address: %+v, expected: %+v", got, expected)
   195  		}
   196  	})
   197  }
   198  
   199  func TestChequebookDeposit(t *testing.T) {
   200  	t.Parallel()
   201  
   202  	txHash := common.HexToHash("0xfffff")
   203  
   204  	t.Run("ok", func(t *testing.T) {
   205  		t.Parallel()
   206  
   207  		chequebookDepositFunc := func(ctx context.Context, amount *big.Int) (hash common.Hash, err error) {
   208  			if amount.Cmp(big.NewInt(700)) == 0 {
   209  				return txHash, nil
   210  			}
   211  			return common.Hash{}, nil
   212  		}
   213  
   214  		testServer, _, _, _ := newTestServer(t, testServerOptions{
   215  			ChequebookOpts: []mock.Option{mock.WithChequebookDepositFunc(chequebookDepositFunc)},
   216  		})
   217  
   218  		expected := &api.ChequebookTxResponse{TransactionHash: txHash}
   219  
   220  		var got *api.ChequebookTxResponse
   221  		jsonhttptest.Request(t, testServer, http.MethodPost, "/chequebook/deposit?amount=700", http.StatusOK,
   222  			jsonhttptest.WithUnmarshalJSONResponse(&got),
   223  		)
   224  
   225  		if !reflect.DeepEqual(got, expected) {
   226  			t.Errorf("got address: %+v, expected: %+v", got, expected)
   227  		}
   228  	})
   229  
   230  	t.Run("custom gas", func(t *testing.T) {
   231  		t.Parallel()
   232  
   233  		chequebookDepositFunc := func(ctx context.Context, amount *big.Int) (hash common.Hash, err error) {
   234  			if sctx.GetGasPrice(ctx).Cmp(big.NewInt(10)) != 0 {
   235  				return common.Hash{}, errors.New("wrong gas price")
   236  			}
   237  
   238  			if amount.Cmp(big.NewInt(700)) == 0 {
   239  				return txHash, nil
   240  			}
   241  			return common.Hash{}, nil
   242  		}
   243  
   244  		testServer, _, _, _ := newTestServer(t, testServerOptions{
   245  			ChequebookOpts: []mock.Option{mock.WithChequebookDepositFunc(chequebookDepositFunc)},
   246  		})
   247  
   248  		expected := &api.ChequebookTxResponse{TransactionHash: txHash}
   249  
   250  		var got *api.ChequebookTxResponse
   251  		jsonhttptest.Request(t, testServer, http.MethodPost, "/chequebook/deposit?amount=700", http.StatusOK,
   252  			jsonhttptest.WithRequestHeader(api.GasPriceHeader, "10"),
   253  			jsonhttptest.WithUnmarshalJSONResponse(&got),
   254  		)
   255  
   256  		if !reflect.DeepEqual(got, expected) {
   257  			t.Errorf("got address: %+v, expected: %+v", got, expected)
   258  		}
   259  	})
   260  }
   261  
   262  func TestChequebookLastCheques(t *testing.T) {
   263  	t.Parallel()
   264  
   265  	addr1 := swarm.MustParseHexAddress("1000000000000000000000000000000000000000000000000000000000000000")
   266  	addr2 := swarm.MustParseHexAddress("2000000000000000000000000000000000000000000000000000000000000000")
   267  	addr3 := swarm.MustParseHexAddress("3000000000000000000000000000000000000000000000000000000000000000")
   268  	addr4 := swarm.MustParseHexAddress("4000000000000000000000000000000000000000000000000000000000000000")
   269  	addr5 := swarm.MustParseHexAddress("5000000000000000000000000000000000000000000000000000000000000000")
   270  	beneficiary := common.HexToAddress("0xfff5")
   271  	beneficiary1 := common.HexToAddress("0xfff0")
   272  	beneficiary2 := common.HexToAddress("0xfff1")
   273  	beneficiary3 := common.HexToAddress("0xfff2")
   274  	cumulativePayout1 := big.NewInt(700)
   275  	cumulativePayout2 := big.NewInt(900)
   276  	cumulativePayout3 := big.NewInt(600)
   277  	cumulativePayout4 := big.NewInt(550)
   278  	cumulativePayout5 := big.NewInt(400)
   279  	cumulativePayout6 := big.NewInt(720)
   280  	chequebookAddress1 := common.HexToAddress("0xeee1")
   281  	chequebookAddress2 := common.HexToAddress("0xeee2")
   282  	chequebookAddress3 := common.HexToAddress("0xeee3")
   283  	chequebookAddress4 := common.HexToAddress("0xeee4")
   284  	chequebookAddress5 := common.HexToAddress("0xeee5")
   285  
   286  	lastSentChequesFunc := func() (map[string]*chequebook.SignedCheque, error) {
   287  		lastSentCheques := make(map[string]*chequebook.SignedCheque, 3)
   288  		sig := make([]byte, 65)
   289  		lastSentCheques[addr1.String()] = &chequebook.SignedCheque{
   290  			Cheque: chequebook.Cheque{
   291  				Beneficiary:      beneficiary1,
   292  				CumulativePayout: cumulativePayout1,
   293  				Chequebook:       chequebookAddress1,
   294  			},
   295  			Signature: sig,
   296  		}
   297  
   298  		lastSentCheques[addr2.String()] = &chequebook.SignedCheque{
   299  			Cheque: chequebook.Cheque{
   300  				Beneficiary:      beneficiary2,
   301  				CumulativePayout: cumulativePayout2,
   302  				Chequebook:       chequebookAddress2,
   303  			},
   304  			Signature: sig,
   305  		}
   306  
   307  		lastSentCheques[addr3.String()] = &chequebook.SignedCheque{
   308  			Cheque: chequebook.Cheque{
   309  				Beneficiary:      beneficiary3,
   310  				CumulativePayout: cumulativePayout3,
   311  				Chequebook:       chequebookAddress3,
   312  			},
   313  			Signature: sig,
   314  		}
   315  		return lastSentCheques, nil
   316  	}
   317  
   318  	lastReceivedChequesFunc := func() (map[string]*chequebook.SignedCheque, error) {
   319  		lastReceivedCheques := make(map[string]*chequebook.SignedCheque, 3)
   320  		sig := make([]byte, 65)
   321  
   322  		lastReceivedCheques[addr1.String()] = &chequebook.SignedCheque{
   323  			Cheque: chequebook.Cheque{
   324  				Beneficiary:      beneficiary,
   325  				CumulativePayout: cumulativePayout4,
   326  				Chequebook:       chequebookAddress1,
   327  			},
   328  			Signature: sig,
   329  		}
   330  
   331  		lastReceivedCheques[addr4.String()] = &chequebook.SignedCheque{
   332  			Cheque: chequebook.Cheque{
   333  				Beneficiary:      beneficiary,
   334  				CumulativePayout: cumulativePayout5,
   335  				Chequebook:       chequebookAddress4,
   336  			},
   337  			Signature: sig,
   338  		}
   339  
   340  		lastReceivedCheques[addr5.String()] = &chequebook.SignedCheque{
   341  			Cheque: chequebook.Cheque{
   342  				Beneficiary:      beneficiary,
   343  				CumulativePayout: cumulativePayout6,
   344  				Chequebook:       chequebookAddress5,
   345  			},
   346  			Signature: sig,
   347  		}
   348  
   349  		return lastReceivedCheques, nil
   350  	}
   351  
   352  	testServer, _, _, _ := newTestServer(t, testServerOptions{
   353  		SwapOpts: []swapmock.Option{swapmock.WithLastReceivedChequesFunc(lastReceivedChequesFunc), swapmock.WithLastSentChequesFunc(lastSentChequesFunc)},
   354  	})
   355  
   356  	lastchequesexpected := []api.ChequebookLastChequesPeerResponse{
   357  		{
   358  			Peer: addr1.String(),
   359  			LastReceived: &api.ChequebookLastChequePeerResponse{
   360  				Beneficiary: beneficiary.String(),
   361  				Chequebook:  chequebookAddress1.String(),
   362  				Payout:      bigint.Wrap(cumulativePayout4),
   363  			},
   364  			LastSent: &api.ChequebookLastChequePeerResponse{
   365  				Beneficiary: beneficiary1.String(),
   366  				Chequebook:  chequebookAddress1.String(),
   367  				Payout:      bigint.Wrap(cumulativePayout1),
   368  			},
   369  		},
   370  		{
   371  			Peer:         addr2.String(),
   372  			LastReceived: nil,
   373  			LastSent: &api.ChequebookLastChequePeerResponse{
   374  				Beneficiary: beneficiary2.String(),
   375  				Chequebook:  chequebookAddress2.String(),
   376  				Payout:      bigint.Wrap(cumulativePayout2),
   377  			},
   378  		},
   379  		{
   380  			Peer:         addr3.String(),
   381  			LastReceived: nil,
   382  			LastSent: &api.ChequebookLastChequePeerResponse{
   383  				Beneficiary: beneficiary3.String(),
   384  				Chequebook:  chequebookAddress3.String(),
   385  				Payout:      bigint.Wrap(cumulativePayout3),
   386  			},
   387  		},
   388  		{
   389  			Peer: addr4.String(),
   390  			LastReceived: &api.ChequebookLastChequePeerResponse{
   391  				Beneficiary: beneficiary.String(),
   392  				Chequebook:  chequebookAddress4.String(),
   393  				Payout:      bigint.Wrap(cumulativePayout5),
   394  			},
   395  			LastSent: nil,
   396  		},
   397  		{
   398  			Peer: addr5.String(),
   399  			LastReceived: &api.ChequebookLastChequePeerResponse{
   400  				Beneficiary: beneficiary.String(),
   401  				Chequebook:  chequebookAddress5.String(),
   402  				Payout:      bigint.Wrap(cumulativePayout6),
   403  			},
   404  			LastSent: nil,
   405  		},
   406  	}
   407  
   408  	expected := &api.ChequebookLastChequesResponse{
   409  		LastCheques: lastchequesexpected,
   410  	}
   411  
   412  	// We expect a list of items unordered by peer:
   413  	var got *api.ChequebookLastChequesResponse
   414  	jsonhttptest.Request(t, testServer, http.MethodGet, "/chequebook/cheque", http.StatusOK,
   415  		jsonhttptest.WithUnmarshalJSONResponse(&got),
   416  	)
   417  
   418  	if !LastChequesEqual(got, expected) {
   419  		t.Fatalf("Got: \n %+v \n\n Expected: \n %+v \n\n", got, expected)
   420  	}
   421  
   422  }
   423  
   424  func TestChequebookLastChequesPeer(t *testing.T) {
   425  	t.Parallel()
   426  
   427  	addr := swarm.MustParseHexAddress("1000000000000000000000000000000000000000000000000000000000000000")
   428  	beneficiary0 := common.HexToAddress("0xfff5")
   429  	beneficiary1 := common.HexToAddress("0xfff0")
   430  	cumulativePayout1 := big.NewInt(700)
   431  	cumulativePayout2 := big.NewInt(900)
   432  	chequebookAddress := common.HexToAddress("0xeee1")
   433  	sig := make([]byte, 65)
   434  
   435  	lastSentChequeFunc := func(swarm.Address) (*chequebook.SignedCheque, error) {
   436  
   437  		sig := make([]byte, 65)
   438  
   439  		lastSentCheque := &chequebook.SignedCheque{
   440  			Cheque: chequebook.Cheque{
   441  				Beneficiary:      beneficiary1,
   442  				CumulativePayout: cumulativePayout1,
   443  				Chequebook:       chequebookAddress,
   444  			},
   445  			Signature: sig,
   446  		}
   447  
   448  		return lastSentCheque, nil
   449  	}
   450  
   451  	lastReceivedChequeFunc := func(swarm.Address) (*chequebook.SignedCheque, error) {
   452  
   453  		lastReceivedCheque := &chequebook.SignedCheque{
   454  			Cheque: chequebook.Cheque{
   455  				Beneficiary:      beneficiary0,
   456  				CumulativePayout: cumulativePayout2,
   457  				Chequebook:       chequebookAddress,
   458  			},
   459  			Signature: sig,
   460  		}
   461  
   462  		return lastReceivedCheque, nil
   463  	}
   464  
   465  	testServer, _, _, _ := newTestServer(t, testServerOptions{
   466  		SwapOpts: []swapmock.Option{swapmock.WithLastReceivedChequeFunc(lastReceivedChequeFunc), swapmock.WithLastSentChequeFunc(lastSentChequeFunc)},
   467  	})
   468  
   469  	expected := &api.ChequebookLastChequesPeerResponse{
   470  		Peer: addr.String(),
   471  		LastReceived: &api.ChequebookLastChequePeerResponse{
   472  			Beneficiary: beneficiary0.String(),
   473  			Chequebook:  chequebookAddress.String(),
   474  			Payout:      bigint.Wrap(cumulativePayout2),
   475  		},
   476  		LastSent: &api.ChequebookLastChequePeerResponse{
   477  			Beneficiary: beneficiary1.String(),
   478  			Chequebook:  chequebookAddress.String(),
   479  			Payout:      bigint.Wrap(cumulativePayout1),
   480  		},
   481  	}
   482  
   483  	var got *api.ChequebookLastChequesPeerResponse
   484  	jsonhttptest.Request(t, testServer, http.MethodGet, "/chequebook/cheque/"+addr.String(), http.StatusOK,
   485  		jsonhttptest.WithUnmarshalJSONResponse(&got),
   486  	)
   487  
   488  	if !reflect.DeepEqual(got, expected) {
   489  		t.Fatalf("Got: \n %+v \n\n Expected: \n %+v \n\n", got, expected)
   490  	}
   491  
   492  }
   493  
   494  func TestChequebookCashout(t *testing.T) {
   495  	t.Parallel()
   496  
   497  	addr := swarm.MustParseHexAddress("1000000000000000000000000000000000000000000000000000000000000000")
   498  	deployCashingHash := common.HexToHash("0xffff")
   499  
   500  	cashChequeFunc := func(ctx context.Context, peer swarm.Address) (common.Hash, error) {
   501  		return deployCashingHash, nil
   502  	}
   503  
   504  	testServer, _, _, _ := newTestServer(t, testServerOptions{
   505  		SwapOpts: []swapmock.Option{swapmock.WithCashChequeFunc(cashChequeFunc)},
   506  	})
   507  
   508  	expected := &api.SwapCashoutResponse{TransactionHash: deployCashingHash.String()}
   509  
   510  	var got *api.SwapCashoutResponse
   511  	jsonhttptest.Request(t, testServer, http.MethodPost, "/chequebook/cashout/"+addr.String(), http.StatusOK,
   512  		jsonhttptest.WithUnmarshalJSONResponse(&got),
   513  	)
   514  
   515  	if !reflect.DeepEqual(got, expected) {
   516  		t.Fatalf("Got: \n %+v \n\n Expected: \n %+v \n\n", got, expected)
   517  	}
   518  }
   519  
   520  func TestChequebookCashout_CustomGas(t *testing.T) {
   521  	t.Parallel()
   522  
   523  	addr := swarm.MustParseHexAddress("1000000000000000000000000000000000000000000000000000000000000000")
   524  	deployCashingHash := common.HexToHash("0xffff")
   525  
   526  	var price *big.Int
   527  	var limit uint64
   528  	cashChequeFunc := func(ctx context.Context, peer swarm.Address) (common.Hash, error) {
   529  		price = sctx.GetGasPrice(ctx)
   530  		limit = sctx.GetGasLimit(ctx)
   531  		return deployCashingHash, nil
   532  	}
   533  
   534  	testServer, _, _, _ := newTestServer(t, testServerOptions{
   535  		SwapOpts: []swapmock.Option{swapmock.WithCashChequeFunc(cashChequeFunc)},
   536  	})
   537  
   538  	expected := &api.SwapCashoutResponse{TransactionHash: deployCashingHash.String()}
   539  
   540  	var got *api.SwapCashoutResponse
   541  	jsonhttptest.Request(t, testServer, http.MethodPost, "/chequebook/cashout/"+addr.String(), http.StatusOK,
   542  		jsonhttptest.WithRequestHeader(api.GasPriceHeader, "10000"),
   543  		jsonhttptest.WithRequestHeader(api.GasLimitHeader, "12221"),
   544  		jsonhttptest.WithUnmarshalJSONResponse(&got),
   545  	)
   546  
   547  	if !reflect.DeepEqual(got, expected) {
   548  		t.Fatalf("Got: \n %+v \n\n Expected: \n %+v \n\n", got, expected)
   549  	}
   550  
   551  	if price.Cmp(big.NewInt(10000)) != 0 {
   552  		t.Fatalf("expected gas price 10000 got %s", price)
   553  	}
   554  
   555  	if limit != 12221 {
   556  		t.Fatalf("expected gas limit 12221 got %d", limit)
   557  	}
   558  }
   559  
   560  func TestChequebookCashoutStatus(t *testing.T) {
   561  	t.Parallel()
   562  
   563  	actionTxHash := common.HexToHash("0xacfe")
   564  	addr := swarm.MustParseHexAddress("1000000000000000000000000000000000000000000000000000000000000000")
   565  	beneficiary := common.HexToAddress("0xfff0")
   566  	recipientAddress := common.HexToAddress("efff")
   567  	totalPayout := big.NewInt(100)
   568  	cumulativePayout := big.NewInt(700)
   569  	uncashedAmount := big.NewInt(200)
   570  	chequebookAddress := common.HexToAddress("0xcfec")
   571  	peer := swarm.MustParseHexAddress("1000000000000000000000000000000000000000000000000000000000000000")
   572  
   573  	sig := make([]byte, 65)
   574  	cheque := &chequebook.SignedCheque{
   575  		Cheque: chequebook.Cheque{
   576  			Beneficiary:      beneficiary,
   577  			CumulativePayout: cumulativePayout,
   578  			Chequebook:       chequebookAddress,
   579  		},
   580  		Signature: sig,
   581  	}
   582  
   583  	result := &chequebook.CashChequeResult{
   584  		Beneficiary:      cheque.Beneficiary,
   585  		Recipient:        recipientAddress,
   586  		Caller:           cheque.Beneficiary,
   587  		TotalPayout:      totalPayout,
   588  		CumulativePayout: cumulativePayout,
   589  		CallerPayout:     big.NewInt(0),
   590  		Bounced:          false,
   591  	}
   592  
   593  	t.Run("with result", func(t *testing.T) {
   594  		t.Parallel()
   595  
   596  		cashoutStatusFunc := func(ctx context.Context, peer swarm.Address) (*chequebook.CashoutStatus, error) {
   597  			status := &chequebook.CashoutStatus{
   598  				Last: &chequebook.LastCashout{
   599  					TxHash:   actionTxHash,
   600  					Cheque:   *cheque,
   601  					Result:   result,
   602  					Reverted: false,
   603  				},
   604  				UncashedAmount: uncashedAmount,
   605  			}
   606  			return status, nil
   607  		}
   608  
   609  		testServer, _, _, _ := newTestServer(t, testServerOptions{
   610  			SwapOpts: []swapmock.Option{swapmock.WithCashoutStatusFunc(cashoutStatusFunc)},
   611  		})
   612  
   613  		expected := &api.SwapCashoutStatusResponse{
   614  			Peer:            peer,
   615  			TransactionHash: &actionTxHash,
   616  			Cheque: &api.ChequebookLastChequePeerResponse{
   617  				Chequebook:  chequebookAddress.String(),
   618  				Payout:      bigint.Wrap(cumulativePayout),
   619  				Beneficiary: cheque.Beneficiary.String(),
   620  			},
   621  			Result: &api.SwapCashoutStatusResult{
   622  				Recipient:  recipientAddress,
   623  				LastPayout: bigint.Wrap(totalPayout),
   624  				Bounced:    false,
   625  			},
   626  			UncashedAmount: bigint.Wrap(uncashedAmount),
   627  		}
   628  
   629  		var got *api.SwapCashoutStatusResponse
   630  		jsonhttptest.Request(t, testServer, http.MethodGet, "/chequebook/cashout/"+addr.String(), http.StatusOK,
   631  
   632  			jsonhttptest.WithUnmarshalJSONResponse(&got),
   633  		)
   634  
   635  		if !reflect.DeepEqual(got, expected) {
   636  			t.Fatalf("Got: \n %+v \n\n Expected: \n %+v \n\n", got, expected)
   637  		}
   638  	})
   639  
   640  	t.Run("without result", func(t *testing.T) {
   641  		t.Parallel()
   642  
   643  		cashoutStatusFunc := func(ctx context.Context, peer swarm.Address) (*chequebook.CashoutStatus, error) {
   644  			status := &chequebook.CashoutStatus{
   645  				Last: &chequebook.LastCashout{
   646  					TxHash:   actionTxHash,
   647  					Cheque:   *cheque,
   648  					Result:   nil,
   649  					Reverted: false,
   650  				},
   651  				UncashedAmount: uncashedAmount,
   652  			}
   653  			return status, nil
   654  		}
   655  
   656  		testServer, _, _, _ := newTestServer(t, testServerOptions{
   657  			SwapOpts: []swapmock.Option{swapmock.WithCashoutStatusFunc(cashoutStatusFunc)},
   658  		})
   659  
   660  		expected := &api.SwapCashoutStatusResponse{
   661  			Peer:            peer,
   662  			TransactionHash: &actionTxHash,
   663  			Cheque: &api.ChequebookLastChequePeerResponse{
   664  				Chequebook:  chequebookAddress.String(),
   665  				Payout:      bigint.Wrap(cumulativePayout),
   666  				Beneficiary: cheque.Beneficiary.String(),
   667  			},
   668  			Result:         nil,
   669  			UncashedAmount: bigint.Wrap(uncashedAmount),
   670  		}
   671  
   672  		var got *api.SwapCashoutStatusResponse
   673  		jsonhttptest.Request(t, testServer, http.MethodGet, "/chequebook/cashout/"+addr.String(), http.StatusOK,
   674  
   675  			jsonhttptest.WithUnmarshalJSONResponse(&got),
   676  		)
   677  
   678  		if !reflect.DeepEqual(got, expected) {
   679  			t.Fatalf("Got: \n %+v \n\n Expected: \n %+v \n\n", got, expected)
   680  		}
   681  	})
   682  
   683  	t.Run("without last", func(t *testing.T) {
   684  		t.Parallel()
   685  
   686  		cashoutStatusFunc := func(ctx context.Context, peer swarm.Address) (*chequebook.CashoutStatus, error) {
   687  			status := &chequebook.CashoutStatus{
   688  				Last:           nil,
   689  				UncashedAmount: uncashedAmount,
   690  			}
   691  			return status, nil
   692  		}
   693  
   694  		testServer, _, _, _ := newTestServer(t, testServerOptions{
   695  			SwapOpts: []swapmock.Option{swapmock.WithCashoutStatusFunc(cashoutStatusFunc)},
   696  		})
   697  
   698  		expected := &api.SwapCashoutStatusResponse{
   699  			Peer:            peer,
   700  			TransactionHash: nil,
   701  			Cheque:          nil,
   702  			Result:          nil,
   703  			UncashedAmount:  bigint.Wrap(uncashedAmount),
   704  		}
   705  
   706  		var got *api.SwapCashoutStatusResponse
   707  		jsonhttptest.Request(t, testServer, http.MethodGet, "/chequebook/cashout/"+addr.String(), http.StatusOK,
   708  
   709  			jsonhttptest.WithUnmarshalJSONResponse(&got),
   710  		)
   711  
   712  		if !reflect.DeepEqual(got, expected) {
   713  			t.Fatalf("Got: \n %+v \n\n Expected: \n %+v \n\n", got, expected)
   714  		}
   715  	})
   716  }
   717  
   718  func Test_chequebookLastPeerHandler_invalidInputs(t *testing.T) {
   719  	t.Parallel()
   720  
   721  	client, _, _, _ := newTestServer(t, testServerOptions{})
   722  
   723  	tests := []struct {
   724  		name string
   725  		peer string
   726  		want jsonhttp.StatusResponse
   727  	}{{
   728  		name: "peer - odd hex string",
   729  		peer: "123",
   730  		want: jsonhttp.StatusResponse{
   731  			Code:    http.StatusBadRequest,
   732  			Message: "invalid path params",
   733  			Reasons: []jsonhttp.Reason{
   734  				{
   735  					Field: "peer",
   736  					Error: api.ErrHexLength.Error(),
   737  				},
   738  			},
   739  		},
   740  	}, {
   741  		name: "peer - invalid hex character",
   742  		peer: "123G",
   743  		want: jsonhttp.StatusResponse{
   744  			Code:    http.StatusBadRequest,
   745  			Message: "invalid path params",
   746  			Reasons: []jsonhttp.Reason{
   747  				{
   748  					Field: "peer",
   749  					Error: api.HexInvalidByteError('G').Error(),
   750  				},
   751  			},
   752  		},
   753  	}}
   754  
   755  	for _, tc := range tests {
   756  		tc := tc
   757  		t.Run(tc.name, func(t *testing.T) {
   758  			t.Parallel()
   759  
   760  			jsonhttptest.Request(t, client, http.MethodGet, "/chequebook/cheque/"+tc.peer, tc.want.Code,
   761  				jsonhttptest.WithExpectedJSONResponse(tc.want),
   762  			)
   763  		})
   764  	}
   765  }
   766  
   767  func LastChequesEqual(a, b *api.ChequebookLastChequesResponse) bool {
   768  
   769  	var state bool
   770  
   771  	for akeys := range a.LastCheques {
   772  		state = false
   773  		for bkeys := range b.LastCheques {
   774  			if reflect.DeepEqual(a.LastCheques[akeys], b.LastCheques[bkeys]) {
   775  				state = true
   776  				break
   777  			}
   778  		}
   779  		if !state {
   780  			return false
   781  		}
   782  	}
   783  
   784  	for bkeys := range b.LastCheques {
   785  		state = false
   786  		for akeys := range a.LastCheques {
   787  			if reflect.DeepEqual(a.LastCheques[akeys], b.LastCheques[bkeys]) {
   788  				state = true
   789  				break
   790  			}
   791  		}
   792  		if !state {
   793  			return false
   794  		}
   795  	}
   796  
   797  	return true
   798  }