github.com/ethersphere/bee/v2@v2.2.0/pkg/storageincentives/staking/contract_test.go (about)

     1  // Copyright 2022 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 staking_test
     6  
     7  import (
     8  	"bytes"
     9  	"context"
    10  	"errors"
    11  	"fmt"
    12  	"math/big"
    13  	"strings"
    14  	"testing"
    15  
    16  	"github.com/ethereum/go-ethereum/common"
    17  	"github.com/ethereum/go-ethereum/core/types"
    18  	chaincfg "github.com/ethersphere/bee/v2/pkg/config"
    19  	"github.com/ethersphere/bee/v2/pkg/storageincentives/staking"
    20  	"github.com/ethersphere/bee/v2/pkg/swarm"
    21  	"github.com/ethersphere/bee/v2/pkg/transaction"
    22  	transactionMock "github.com/ethersphere/bee/v2/pkg/transaction/mock"
    23  	"github.com/ethersphere/bee/v2/pkg/util/abiutil"
    24  )
    25  
    26  var stakingContractABI = abiutil.MustParseABI(chaincfg.Testnet.StakingABI)
    27  
    28  func TestIsOverlayFrozen(t *testing.T) {
    29  	t.Parallel()
    30  
    31  	ctx := context.Background()
    32  	owner := common.HexToAddress("abcd")
    33  	stakingContractAddress := common.HexToAddress("ffff")
    34  	bzzTokenAddress := common.HexToAddress("eeee")
    35  	nonce := common.BytesToHash(make([]byte, 32))
    36  
    37  	height := 100
    38  	frozenHeight := big.NewInt(int64(height))
    39  
    40  	t.Run("ok", func(t *testing.T) {
    41  		t.Parallel()
    42  
    43  		contract := staking.New(
    44  			owner,
    45  			stakingContractAddress,
    46  			stakingContractABI,
    47  			bzzTokenAddress,
    48  			transactionMock.New(
    49  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
    50  					if *request.To == stakingContractAddress {
    51  						return frozenHeight.FillBytes(make([]byte, 32)), nil
    52  					}
    53  					return nil, errors.New("unexpected call")
    54  				}),
    55  			),
    56  			nonce,
    57  			false,
    58  		)
    59  
    60  		frozen, err := contract.IsOverlayFrozen(ctx, uint64(height-1))
    61  		if err != nil {
    62  			t.Fatal(err)
    63  		}
    64  
    65  		if !frozen {
    66  			t.Fatalf("expected owner to be frozen")
    67  		}
    68  
    69  		frozen, err = contract.IsOverlayFrozen(ctx, uint64(height+1))
    70  		if err != nil {
    71  			t.Fatal(err)
    72  		}
    73  
    74  		if frozen {
    75  			t.Fatalf("expected owner to not be frozen")
    76  		}
    77  
    78  	})
    79  }
    80  
    81  func TestDepositStake(t *testing.T) {
    82  	t.Parallel()
    83  
    84  	ctx := context.Background()
    85  	owner := common.HexToAddress("abcd")
    86  	stakingContractAddress := common.HexToAddress("ffff")
    87  	bzzTokenAddress := common.HexToAddress("eeee")
    88  	nonce := common.BytesToHash(make([]byte, 32))
    89  	txHashDeposited := common.HexToHash("c3a7")
    90  	stakedAmount := big.NewInt(100000000000000000)
    91  	txHashApprove := common.HexToHash("abb0")
    92  
    93  	t.Run("ok", func(t *testing.T) {
    94  		t.Parallel()
    95  
    96  		totalAmount := big.NewInt(100000000000000000)
    97  		prevStake := big.NewInt(0)
    98  		expectedCallData, err := stakingContractABI.Pack("manageStake", nonce, stakedAmount)
    99  		if err != nil {
   100  			t.Fatal(err)
   101  		}
   102  
   103  		contract := staking.New(
   104  			owner,
   105  			stakingContractAddress,
   106  			stakingContractABI,
   107  			bzzTokenAddress,
   108  			transactionMock.New(
   109  				transactionMock.WithSendFunc(func(ctx context.Context, request *transaction.TxRequest, boost int) (txHash common.Hash, err error) {
   110  					if *request.To == bzzTokenAddress {
   111  						return txHashApprove, nil
   112  					}
   113  					if *request.To == stakingContractAddress {
   114  						if !bytes.Equal(expectedCallData[:80], request.Data[:80]) {
   115  							return common.Hash{}, fmt.Errorf("got wrong call data. wanted %x, got %x", expectedCallData, request.Data)
   116  						}
   117  						return txHashDeposited, nil
   118  					}
   119  					return common.Hash{}, errors.New("sent to wrong contract")
   120  				}),
   121  				transactionMock.WithWaitForReceiptFunc(func(ctx context.Context, txHash common.Hash) (receipt *types.Receipt, err error) {
   122  					if txHash == txHashDeposited {
   123  						return &types.Receipt{
   124  							Status: 1,
   125  						}, nil
   126  					}
   127  					if txHash == txHashApprove {
   128  						return &types.Receipt{
   129  							Status: 1,
   130  						}, nil
   131  					}
   132  					return nil, errors.New("unknown tx hash")
   133  				}),
   134  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
   135  					if *request.To == bzzTokenAddress {
   136  						return totalAmount.FillBytes(make([]byte, 32)), nil
   137  					}
   138  					if *request.To == stakingContractAddress {
   139  						return getPotentialStakeResponse(t, prevStake), nil
   140  					}
   141  					return nil, errors.New("unexpected call")
   142  				}),
   143  			),
   144  			nonce,
   145  			false,
   146  		)
   147  
   148  		_, err = contract.DepositStake(ctx, stakedAmount)
   149  		if err != nil {
   150  			t.Fatal(err)
   151  		}
   152  	})
   153  
   154  	t.Run("ok with addon stake", func(t *testing.T) {
   155  		t.Parallel()
   156  
   157  		totalAmount := big.NewInt(100000000000000000)
   158  		prevStake := big.NewInt(2)
   159  		expectedCallData, err := stakingContractABI.Pack("manageStake", nonce, big.NewInt(100000000000000000))
   160  		if err != nil {
   161  			t.Fatal(err)
   162  		}
   163  
   164  		contract := staking.New(
   165  			owner,
   166  			stakingContractAddress,
   167  			stakingContractABI,
   168  			bzzTokenAddress,
   169  			transactionMock.New(
   170  				transactionMock.WithSendFunc(func(ctx context.Context, request *transaction.TxRequest, boost int) (txHash common.Hash, err error) {
   171  					if *request.To == bzzTokenAddress {
   172  						return txHashApprove, nil
   173  					}
   174  					if *request.To == stakingContractAddress {
   175  						if !bytes.Equal(expectedCallData[:80], request.Data[:80]) {
   176  							return common.Hash{}, fmt.Errorf("got wrong call data. wanted %x, got %x", expectedCallData, request.Data)
   177  						}
   178  						return txHashDeposited, nil
   179  					}
   180  					return common.Hash{}, errors.New("sent to wrong contract")
   181  				}),
   182  				transactionMock.WithWaitForReceiptFunc(func(ctx context.Context, txHash common.Hash) (receipt *types.Receipt, err error) {
   183  					if txHash == txHashDeposited {
   184  						return &types.Receipt{
   185  							Status: 1,
   186  						}, nil
   187  					}
   188  					if txHash == txHashApprove {
   189  						return &types.Receipt{
   190  							Status: 1,
   191  						}, nil
   192  					}
   193  					return nil, errors.New("unknown tx hash")
   194  				}),
   195  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
   196  					if *request.To == bzzTokenAddress {
   197  						return totalAmount.FillBytes(make([]byte, 32)), nil
   198  					}
   199  					if *request.To == stakingContractAddress {
   200  						return getPotentialStakeResponse(t, prevStake), nil
   201  					}
   202  					return nil, errors.New("unexpected call")
   203  				}),
   204  			),
   205  			nonce,
   206  			false,
   207  		)
   208  
   209  		_, err = contract.DepositStake(ctx, stakedAmount)
   210  		if err != nil {
   211  			t.Fatal(err)
   212  		}
   213  		stakedAmount, err := contract.GetPotentialStake(ctx)
   214  		if err != nil {
   215  			t.Fatal(err)
   216  		}
   217  		if stakedAmount.Cmp(big.NewInt(13)) == 0 {
   218  			t.Fatalf("expected %v, got %v", big.NewInt(13), stakedAmount)
   219  		}
   220  	})
   221  
   222  	t.Run("insufficient stake amount", func(t *testing.T) {
   223  		t.Parallel()
   224  
   225  		totalAmount := big.NewInt(102400)
   226  		prevStake := big.NewInt(0)
   227  
   228  		contract := staking.New(
   229  			owner,
   230  			stakingContractAddress,
   231  			stakingContractABI,
   232  			bzzTokenAddress,
   233  			transactionMock.New(
   234  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
   235  					if *request.To == bzzTokenAddress {
   236  						return totalAmount.FillBytes(make([]byte, 32)), nil
   237  					}
   238  					if *request.To == stakingContractAddress {
   239  						return getPotentialStakeResponse(t, prevStake), nil
   240  					}
   241  					return nil, errors.New("unexpected call")
   242  				}),
   243  			),
   244  			nonce,
   245  			false,
   246  		)
   247  
   248  		_, err := contract.DepositStake(ctx, big.NewInt(0))
   249  		if !errors.Is(err, staking.ErrInsufficientStakeAmount) {
   250  			t.Fatal(fmt.Errorf("wanted %w, got %w", staking.ErrInsufficientStakeAmount, err))
   251  		}
   252  	})
   253  
   254  	t.Run("insufficient funds", func(t *testing.T) {
   255  		t.Parallel()
   256  
   257  		totalAmount := big.NewInt(0)
   258  		prevStake := big.NewInt(0)
   259  
   260  		contract := staking.New(
   261  			owner,
   262  			stakingContractAddress,
   263  			stakingContractABI,
   264  			bzzTokenAddress,
   265  			transactionMock.New(
   266  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
   267  					if *request.To == bzzTokenAddress {
   268  						return totalAmount.FillBytes(make([]byte, 32)), nil
   269  					}
   270  					if *request.To == stakingContractAddress {
   271  						return getPotentialStakeResponse(t, prevStake), nil
   272  					}
   273  					return nil, errors.New("unexpected call")
   274  				}),
   275  			),
   276  			nonce,
   277  			false,
   278  		)
   279  
   280  		_, err := contract.DepositStake(ctx, big.NewInt(100000000000000000))
   281  		if !errors.Is(err, staking.ErrInsufficientFunds) {
   282  			t.Fatal(fmt.Errorf("wanted %w, got %w", staking.ErrInsufficientFunds, err))
   283  		}
   284  	})
   285  
   286  	t.Run("insufficient stake amount", func(t *testing.T) {
   287  		t.Parallel()
   288  
   289  		totalAmount := big.NewInt(0)
   290  		prevStake := big.NewInt(0)
   291  
   292  		contract := staking.New(
   293  			owner,
   294  			stakingContractAddress,
   295  			stakingContractABI,
   296  			bzzTokenAddress,
   297  			transactionMock.New(
   298  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
   299  					if *request.To == bzzTokenAddress {
   300  						return totalAmount.FillBytes(make([]byte, 32)), nil
   301  					}
   302  					if *request.To == stakingContractAddress {
   303  						return getPotentialStakeResponse(t, prevStake), nil
   304  					}
   305  					return nil, errors.New("unexpected call")
   306  				}),
   307  			),
   308  			nonce,
   309  			false,
   310  		)
   311  
   312  		_, err := contract.DepositStake(ctx, big.NewInt(100000000000000000))
   313  		if !errors.Is(err, staking.ErrInsufficientFunds) {
   314  			t.Fatal(fmt.Errorf("wanted %w, got %w", staking.ErrInsufficientStakeAmount, err))
   315  		}
   316  	})
   317  
   318  	t.Run("send tx failed", func(t *testing.T) {
   319  		t.Parallel()
   320  
   321  		totalAmount := big.NewInt(102400)
   322  		prevStake := big.NewInt(0)
   323  
   324  		contract := staking.New(
   325  			owner,
   326  			stakingContractAddress,
   327  			stakingContractABI,
   328  			bzzTokenAddress,
   329  			transactionMock.New(
   330  				transactionMock.WithSendFunc(func(ctx context.Context, request *transaction.TxRequest, boost int) (txHash common.Hash, err error) {
   331  					if *request.To == bzzTokenAddress {
   332  						return common.Hash{}, errors.New("send transaction failed")
   333  					}
   334  					return common.Hash{}, errors.New("sent to wrong contract")
   335  				}),
   336  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
   337  					if *request.To == bzzTokenAddress {
   338  						return totalAmount.FillBytes(make([]byte, 32)), nil
   339  					}
   340  					if *request.To == stakingContractAddress {
   341  						return prevStake.FillBytes(make([]byte, 32)), nil
   342  					}
   343  					return nil, errors.New("unexpected call")
   344  				}),
   345  			),
   346  			nonce,
   347  			false,
   348  		)
   349  
   350  		_, err := contract.DepositStake(ctx, stakedAmount)
   351  		if err == nil {
   352  			t.Fatal("expected error")
   353  		}
   354  	})
   355  
   356  	t.Run("invalid call data", func(t *testing.T) {
   357  		t.Parallel()
   358  
   359  		totalAmount := big.NewInt(102400)
   360  		prevStake := big.NewInt(0)
   361  		expectedStakeAmount := big.NewInt(100)
   362  		expectedCallData, err := staking.Erc20ABI.Pack("approve", stakingContractAddress, expectedStakeAmount)
   363  		if err != nil {
   364  			t.Fatal(err)
   365  		}
   366  
   367  		contract := staking.New(
   368  			owner,
   369  			stakingContractAddress,
   370  			stakingContractABI,
   371  			bzzTokenAddress,
   372  			transactionMock.New(
   373  				transactionMock.WithSendFunc(func(ctx context.Context, request *transaction.TxRequest, boost int) (txHash common.Hash, err error) {
   374  					if *request.To == bzzTokenAddress {
   375  						if !bytes.Equal(expectedCallData[:], request.Data[:]) {
   376  							return common.Hash{}, fmt.Errorf("got wrong call data. wanted %x, got %x", expectedCallData, request.Data)
   377  						}
   378  						return txHashApprove, nil
   379  					}
   380  					if *request.To == stakingContractAddress {
   381  						return txHashDeposited, nil
   382  					}
   383  					return common.Hash{}, errors.New("sent to wrong contract")
   384  				}),
   385  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
   386  					if *request.To == bzzTokenAddress {
   387  						return totalAmount.FillBytes(make([]byte, 32)), nil
   388  					}
   389  					if *request.To == stakingContractAddress {
   390  						return prevStake.FillBytes(make([]byte, 32)), nil
   391  					}
   392  					return nil, errors.New("unexpected call")
   393  				}),
   394  			),
   395  			nonce,
   396  			false,
   397  		)
   398  
   399  		_, err = contract.DepositStake(ctx, stakedAmount)
   400  		if err == nil {
   401  			t.Fatal("expected error")
   402  		}
   403  	})
   404  
   405  	t.Run("transaction reverted", func(t *testing.T) {
   406  		t.Parallel()
   407  
   408  		totalAmount := big.NewInt(100000000000000000)
   409  		prevStake := big.NewInt(0)
   410  		expectedCallData, err := staking.Erc20ABI.Pack("approve", stakingContractAddress, stakedAmount)
   411  		if err != nil {
   412  			t.Fatal(err)
   413  		}
   414  
   415  		contract := staking.New(
   416  			owner,
   417  			stakingContractAddress,
   418  			stakingContractABI,
   419  			bzzTokenAddress,
   420  			transactionMock.New(
   421  				transactionMock.WithSendFunc(func(ctx context.Context, request *transaction.TxRequest, boost int) (txHash common.Hash, err error) {
   422  					if *request.To == bzzTokenAddress {
   423  						return txHashApprove, nil
   424  					}
   425  					if *request.To == stakingContractAddress {
   426  						if !bytes.Equal(expectedCallData[:80], request.Data[:80]) {
   427  							return common.Hash{}, fmt.Errorf("got wrong call data. wanted %x, got %x", expectedCallData, request.Data)
   428  						}
   429  						return txHashDeposited, nil
   430  					}
   431  					return txHashDeposited, errors.New("sent to wrong contract")
   432  				}),
   433  				transactionMock.WithWaitForReceiptFunc(func(ctx context.Context, txHash common.Hash) (receipt *types.Receipt, err error) {
   434  					if txHash == txHashDeposited {
   435  						return &types.Receipt{
   436  							Status: 1,
   437  						}, nil
   438  					}
   439  					if txHash == txHashApprove {
   440  						return &types.Receipt{
   441  							Status: 0,
   442  						}, nil
   443  					}
   444  					return nil, errors.New("unknown tx hash")
   445  				}),
   446  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
   447  					if *request.To == bzzTokenAddress {
   448  						return totalAmount.FillBytes(make([]byte, 32)), nil
   449  					}
   450  					if *request.To == stakingContractAddress {
   451  						return getPotentialStakeResponse(t, prevStake), nil
   452  
   453  					}
   454  					return nil, errors.New("unexpected call")
   455  				}),
   456  			),
   457  			nonce,
   458  			false,
   459  		)
   460  
   461  		_, err = contract.DepositStake(ctx, stakedAmount)
   462  		if !errors.Is(err, transaction.ErrTransactionReverted) {
   463  			t.Fatalf("expected %v, got %v", transaction.ErrTransactionReverted, err)
   464  		}
   465  	})
   466  
   467  	t.Run("transaction error", func(t *testing.T) {
   468  		t.Parallel()
   469  
   470  		totalAmount := big.NewInt(102400)
   471  		prevStake := big.NewInt(0)
   472  		expectedCallData, err := staking.Erc20ABI.Pack("approve", stakingContractAddress, stakedAmount)
   473  		if err != nil {
   474  			t.Fatal(err)
   475  		}
   476  
   477  		contract := staking.New(
   478  			owner,
   479  			stakingContractAddress,
   480  			stakingContractABI,
   481  			bzzTokenAddress,
   482  			transactionMock.New(
   483  				transactionMock.WithSendFunc(func(ctx context.Context, request *transaction.TxRequest, boost int) (txHash common.Hash, err error) {
   484  					if *request.To == bzzTokenAddress {
   485  						return txHashApprove, nil
   486  					}
   487  					if *request.To == stakingContractAddress {
   488  						if !bytes.Equal(expectedCallData[:80], request.Data[:80]) {
   489  							return common.Hash{}, fmt.Errorf("got wrong call data. wanted %x, got %x", expectedCallData, request.Data)
   490  						}
   491  						return txHashDeposited, nil
   492  					}
   493  					return common.Hash{}, errors.New("sent to wrong contract")
   494  				}),
   495  				transactionMock.WithWaitForReceiptFunc(func(ctx context.Context, txHash common.Hash) (receipt *types.Receipt, err error) {
   496  					if txHash == txHashDeposited {
   497  						return &types.Receipt{
   498  							Status: 1,
   499  						}, nil
   500  					}
   501  					if txHash == txHashApprove {
   502  						return nil, fmt.Errorf("unknown error")
   503  					}
   504  					return nil, errors.New("unknown tx hash")
   505  				}),
   506  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
   507  					if *request.To == bzzTokenAddress {
   508  						return totalAmount.FillBytes(make([]byte, 32)), nil
   509  					}
   510  					if *request.To == stakingContractAddress {
   511  						return getPotentialStakeResponse(t, prevStake), nil
   512  
   513  					}
   514  					return nil, errors.New("unexpected call")
   515  				}),
   516  			),
   517  			nonce,
   518  			false,
   519  		)
   520  
   521  		_, err = contract.DepositStake(ctx, stakedAmount)
   522  		if err == nil {
   523  			t.Fatalf("expected error")
   524  		}
   525  	})
   526  
   527  	t.Run("transaction error in call", func(t *testing.T) {
   528  		t.Parallel()
   529  
   530  		contract := staking.New(
   531  			owner,
   532  			stakingContractAddress,
   533  			stakingContractABI,
   534  			bzzTokenAddress,
   535  			transactionMock.New(
   536  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
   537  					if *request.To == stakingContractAddress {
   538  						return nil, errors.New("some error")
   539  					}
   540  					return nil, errors.New("unexpected call")
   541  				}),
   542  			),
   543  			nonce,
   544  			false,
   545  		)
   546  
   547  		_, err := contract.DepositStake(ctx, stakedAmount)
   548  		if err == nil {
   549  			t.Fatalf("expected error")
   550  		}
   551  	})
   552  }
   553  
   554  func TestChangeStakeOverlay(t *testing.T) {
   555  	t.Parallel()
   556  
   557  	ctx := context.Background()
   558  	owner := common.HexToAddress("abcd")
   559  	stakingContractAddress := common.HexToAddress("ffff")
   560  	bzzTokenAddress := common.HexToAddress("eeee")
   561  	nonce := common.BytesToHash(make([]byte, 32))
   562  	txHashOverlayChanged := common.HexToHash("c3a7")
   563  	stakedAmount := big.NewInt(0)
   564  	txHashApprove := common.HexToHash("abb0")
   565  
   566  	t.Run("ok", func(t *testing.T) {
   567  		t.Parallel()
   568  
   569  		expectedCallData, err := stakingContractABI.Pack("manageStake", nonce, stakedAmount)
   570  		if err != nil {
   571  			t.Fatal(err)
   572  		}
   573  
   574  		contract := staking.New(
   575  			owner,
   576  			stakingContractAddress,
   577  			stakingContractABI,
   578  			bzzTokenAddress,
   579  			transactionMock.New(
   580  				transactionMock.WithSendFunc(func(ctx context.Context, request *transaction.TxRequest, boost int) (txHash common.Hash, err error) {
   581  					if *request.To == stakingContractAddress {
   582  						if !bytes.Equal(expectedCallData[:80], request.Data[:80]) {
   583  							return common.Hash{}, fmt.Errorf("got wrong call data. wanted %x, got %x", expectedCallData, request.Data)
   584  						}
   585  						return txHashOverlayChanged, nil
   586  					}
   587  					return common.Hash{}, errors.New("sent to wrong contract")
   588  				}),
   589  				transactionMock.WithWaitForReceiptFunc(func(ctx context.Context, txHash common.Hash) (receipt *types.Receipt, err error) {
   590  					if txHash == txHashOverlayChanged {
   591  						return &types.Receipt{
   592  							Status: 1,
   593  						}, nil
   594  					}
   595  					return nil, errors.New("unknown tx hash")
   596  				}),
   597  			),
   598  			nonce,
   599  			false,
   600  		)
   601  
   602  		_, err = contract.ChangeStakeOverlay(ctx, nonce)
   603  		if err != nil {
   604  			t.Fatal(err)
   605  		}
   606  	})
   607  
   608  	t.Run("send tx failed", func(t *testing.T) {
   609  		t.Parallel()
   610  
   611  		contract := staking.New(
   612  			owner,
   613  			stakingContractAddress,
   614  			stakingContractABI,
   615  			bzzTokenAddress,
   616  			transactionMock.New(
   617  				transactionMock.WithSendFunc(func(ctx context.Context, request *transaction.TxRequest, boost int) (txHash common.Hash, err error) {
   618  					if *request.To == stakingContractAddress {
   619  						return common.Hash{}, errors.New("send transaction failed")
   620  					}
   621  					return common.Hash{}, errors.New("sent to wrong contract")
   622  				}),
   623  			),
   624  			nonce,
   625  			false,
   626  		)
   627  
   628  		_, err := contract.ChangeStakeOverlay(ctx, nonce)
   629  		if err == nil || !strings.Contains(err.Error(), "send transaction failed") {
   630  			t.Fatal("expected different error")
   631  		}
   632  	})
   633  
   634  	t.Run("invalid call data", func(t *testing.T) {
   635  		t.Parallel()
   636  
   637  		expectedCallData, err := stakingContractABI.Pack("manageStake", nonce, stakedAmount)
   638  		if err != nil {
   639  			t.Fatal(err)
   640  		}
   641  
   642  		contract := staking.New(
   643  			owner,
   644  			stakingContractAddress,
   645  			stakingContractABI,
   646  			bzzTokenAddress,
   647  			transactionMock.New(
   648  				transactionMock.WithSendFunc(func(ctx context.Context, request *transaction.TxRequest, boost int) (txHash common.Hash, err error) {
   649  					if *request.To == stakingContractAddress {
   650  						if !bytes.Equal(expectedCallData[:80], request.Data[:80]) {
   651  							return common.Hash{}, fmt.Errorf("got wrong call data. wanted %x, got %x", expectedCallData, request.Data)
   652  						}
   653  						return txHashApprove, nil
   654  					}
   655  					return common.Hash{}, errors.New("sent to wrong contract")
   656  				}),
   657  			),
   658  			nonce,
   659  			false,
   660  		)
   661  
   662  		newNonce := make([]byte, 32)
   663  		copy(newNonce, nonce[:])
   664  		newNonce[0]++
   665  		_, err = contract.ChangeStakeOverlay(ctx, common.BytesToHash(newNonce))
   666  		if err == nil || !strings.Contains(err.Error(), "got wrong call data. wanted") {
   667  			t.Fatal("expected different error")
   668  		}
   669  	})
   670  
   671  	t.Run("transaction reverted", func(t *testing.T) {
   672  		t.Parallel()
   673  
   674  		expectedCallData, err := stakingContractABI.Pack("manageStake", nonce, stakedAmount)
   675  		if err != nil {
   676  			t.Fatal(err)
   677  		}
   678  
   679  		contract := staking.New(
   680  			owner,
   681  			stakingContractAddress,
   682  			stakingContractABI,
   683  			bzzTokenAddress,
   684  			transactionMock.New(
   685  				transactionMock.WithSendFunc(func(ctx context.Context, request *transaction.TxRequest, boost int) (txHash common.Hash, err error) {
   686  					if *request.To == stakingContractAddress {
   687  						if !bytes.Equal(expectedCallData[:80], request.Data[:80]) {
   688  							return common.Hash{}, fmt.Errorf("got wrong call data. wanted %x, got %x", expectedCallData, request.Data)
   689  						}
   690  						return txHashOverlayChanged, nil
   691  					}
   692  					return txHashOverlayChanged, errors.New("sent to wrong contract")
   693  				}),
   694  				transactionMock.WithWaitForReceiptFunc(func(ctx context.Context, txHash common.Hash) (receipt *types.Receipt, err error) {
   695  					if txHash == txHashOverlayChanged {
   696  						return &types.Receipt{
   697  							Status: 0,
   698  						}, nil
   699  					}
   700  					return nil, errors.New("unknown tx hash")
   701  				}),
   702  			),
   703  			nonce,
   704  			false,
   705  		)
   706  
   707  		_, err = contract.ChangeStakeOverlay(ctx, nonce)
   708  		if !errors.Is(err, transaction.ErrTransactionReverted) {
   709  			t.Fatalf("expected %v, got %v", transaction.ErrTransactionReverted, err)
   710  		}
   711  	})
   712  
   713  	t.Run("transaction error", func(t *testing.T) {
   714  		t.Parallel()
   715  
   716  		expectedCallData, err := stakingContractABI.Pack("manageStake", nonce, stakedAmount)
   717  		if err != nil {
   718  			t.Fatal(err)
   719  		}
   720  
   721  		contract := staking.New(
   722  			owner,
   723  			stakingContractAddress,
   724  			stakingContractABI,
   725  			bzzTokenAddress,
   726  			transactionMock.New(
   727  				transactionMock.WithSendFunc(func(ctx context.Context, request *transaction.TxRequest, boost int) (txHash common.Hash, err error) {
   728  					if *request.To == stakingContractAddress {
   729  						if !bytes.Equal(expectedCallData[:80], request.Data[:80]) {
   730  							return common.Hash{}, fmt.Errorf("got wrong call data. wanted %x, got %x", expectedCallData, request.Data)
   731  						}
   732  						return txHashOverlayChanged, nil
   733  					}
   734  					return common.Hash{}, errors.New("sent to wrong contract")
   735  				}),
   736  				transactionMock.WithWaitForReceiptFunc(func(ctx context.Context, txHash common.Hash) (receipt *types.Receipt, err error) {
   737  					if txHash == txHashOverlayChanged {
   738  						return nil, fmt.Errorf("unknown error")
   739  					}
   740  					return nil, errors.New("unknown tx hash")
   741  				}),
   742  			),
   743  			nonce,
   744  			false,
   745  		)
   746  
   747  		_, err = contract.ChangeStakeOverlay(ctx, nonce)
   748  		if err == nil || !strings.Contains(err.Error(), "unknown error") {
   749  			t.Fatal("expected different error")
   750  		}
   751  	})
   752  }
   753  
   754  func TestGetCommittedStake(t *testing.T) {
   755  	t.Parallel()
   756  
   757  	ctx := context.Background()
   758  	owner := common.HexToAddress("abcd")
   759  	stakingAddress := common.HexToAddress("ffff")
   760  	bzzTokenAddress := common.HexToAddress("eeee")
   761  	nonce := common.BytesToHash(make([]byte, 32))
   762  
   763  	expectedCallData, err := stakingContractABI.Pack("stakes", owner)
   764  	if err != nil {
   765  		t.Fatal(err)
   766  	}
   767  
   768  	t.Run("ok", func(t *testing.T) {
   769  		t.Parallel()
   770  
   771  		prevStake := big.NewInt(100000000000000000)
   772  
   773  		contract := staking.New(
   774  			owner,
   775  			stakingAddress,
   776  			stakingContractABI,
   777  			bzzTokenAddress,
   778  			transactionMock.New(
   779  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
   780  					if *request.To == stakingAddress {
   781  						if !bytes.Equal(expectedCallData[:64], request.Data[:64]) {
   782  							return nil, fmt.Errorf("got wrong call data. wanted %x, got %x", expectedCallData, request.Data)
   783  						}
   784  						return getPotentialStakeResponse(t, prevStake), nil
   785  					}
   786  					return nil, errors.New("unexpected call")
   787  				}),
   788  			),
   789  			nonce,
   790  			false,
   791  		)
   792  
   793  		stakedAmount, err := contract.GetPotentialStake(ctx)
   794  		if err != nil {
   795  			t.Fatal(err)
   796  		}
   797  
   798  		if stakedAmount.Cmp(prevStake) != 0 {
   799  			t.Fatalf("expected %v got %v", prevStake, stakedAmount)
   800  		}
   801  	})
   802  
   803  	t.Run("error with unpacking", func(t *testing.T) {
   804  		t.Parallel()
   805  		expectedCallData, err := stakingContractABI.Pack("stakes", owner)
   806  		if err != nil {
   807  			t.Fatal(err)
   808  		}
   809  
   810  		contract := staking.New(
   811  			owner,
   812  			stakingAddress,
   813  			stakingContractABI,
   814  			bzzTokenAddress,
   815  			transactionMock.New(
   816  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
   817  					if *request.To == stakingAddress {
   818  						if !bytes.Equal(expectedCallData[:64], request.Data[:64]) {
   819  							return nil, fmt.Errorf("got wrong call data. wanted %x, got %x", expectedCallData, request.Data)
   820  						}
   821  						return []byte{}, nil
   822  					}
   823  					return nil, errors.New("unexpected call")
   824  				}),
   825  			),
   826  			nonce,
   827  			false,
   828  		)
   829  
   830  		_, err = contract.GetPotentialStake(ctx)
   831  		if err == nil {
   832  			t.Fatal("expected error with unpacking")
   833  		}
   834  	})
   835  
   836  	t.Run("with invalid call data", func(t *testing.T) {
   837  		t.Parallel()
   838  
   839  		addr := swarm.MustParseHexAddress("f30c0aa7e9e2a0ef4c9b1b750ebfeaeb7c7c24da700bb089da19a46e3677824b")
   840  
   841  		prevStake := big.NewInt(0)
   842  		expectedCallData, err := stakingContractABI.Pack("stakes", common.BytesToHash(addr.Bytes()))
   843  		if err != nil {
   844  			t.Fatal(err)
   845  		}
   846  
   847  		contract := staking.New(
   848  			owner,
   849  			stakingAddress,
   850  			stakingContractABI,
   851  			bzzTokenAddress,
   852  			transactionMock.New(
   853  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
   854  					if *request.To == stakingAddress {
   855  						if !bytes.Equal(expectedCallData[:64], request.Data[:64]) {
   856  							return nil, fmt.Errorf("got wrong call data. wanted %x, got %x", expectedCallData, request.Data)
   857  						}
   858  						return prevStake.FillBytes(make([]byte, 32)), nil
   859  					}
   860  					return nil, errors.New("unexpected call")
   861  				}),
   862  			),
   863  			nonce,
   864  			false,
   865  		)
   866  
   867  		_, err = contract.GetPotentialStake(ctx)
   868  		if err == nil {
   869  			t.Fatal("expected error due to wrong call data")
   870  		}
   871  	})
   872  
   873  	t.Run("transaction error", func(t *testing.T) {
   874  		t.Parallel()
   875  
   876  		contract := staking.New(
   877  			owner,
   878  			stakingAddress,
   879  			stakingContractABI,
   880  			bzzTokenAddress,
   881  			transactionMock.New(
   882  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
   883  					return nil, errors.New("some error")
   884  				}),
   885  			),
   886  			nonce,
   887  			false,
   888  		)
   889  
   890  		_, err := contract.GetPotentialStake(ctx)
   891  		if err == nil {
   892  			t.Fatal("expected error")
   893  		}
   894  	})
   895  }
   896  
   897  func TestGetWithdrawableStake(t *testing.T) {
   898  	t.Parallel()
   899  
   900  	ctx := context.Background()
   901  	owner := common.HexToAddress("abcd")
   902  	stakingAddress := common.HexToAddress("ffff")
   903  	bzzTokenAddress := common.HexToAddress("eeee")
   904  	nonce := common.BytesToHash(make([]byte, 32))
   905  
   906  	expectedCallData, err := stakingContractABI.Pack("withdrawableStake")
   907  	if err != nil {
   908  		t.Fatal(err)
   909  	}
   910  
   911  	t.Run("ok", func(t *testing.T) {
   912  		t.Parallel()
   913  
   914  		prevStake := big.NewInt(100000000000000000)
   915  
   916  		contract := staking.New(
   917  			owner,
   918  			stakingAddress,
   919  			stakingContractABI,
   920  			bzzTokenAddress,
   921  			transactionMock.New(
   922  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
   923  					if *request.To == stakingAddress {
   924  						if !bytes.Equal(expectedCallData[:32], request.Data[:32]) {
   925  							return nil, fmt.Errorf("got wrong call data. wanted %x, got %x", expectedCallData, request.Data)
   926  						}
   927  						return prevStake.FillBytes(make([]byte, 32)), nil
   928  					}
   929  					return nil, errors.New("unexpected call")
   930  				}),
   931  			),
   932  			nonce,
   933  			false,
   934  		)
   935  
   936  		withdrawableStake, err := contract.GetWithdrawableStake(ctx)
   937  		if err != nil {
   938  			t.Fatal(err)
   939  		}
   940  
   941  		if withdrawableStake.Cmp(prevStake) != 0 {
   942  			t.Fatalf("expected %v got %v", prevStake, withdrawableStake)
   943  		}
   944  	})
   945  
   946  	t.Run("error with unpacking", func(t *testing.T) {
   947  		t.Parallel()
   948  		expectedCallData, err := stakingContractABI.Pack("withdrawableStake")
   949  		if err != nil {
   950  			t.Fatal(err)
   951  		}
   952  
   953  		contract := staking.New(
   954  			owner,
   955  			stakingAddress,
   956  			stakingContractABI,
   957  			bzzTokenAddress,
   958  			transactionMock.New(
   959  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
   960  					if *request.To == stakingAddress {
   961  						if !bytes.Equal(expectedCallData[:32], request.Data[:32]) {
   962  							return nil, fmt.Errorf("got wrong call data. wanted %x, got %x", expectedCallData, request.Data)
   963  						}
   964  						return []byte{}, nil
   965  					}
   966  					return nil, errors.New("unexpected call")
   967  				}),
   968  			),
   969  			nonce,
   970  			false,
   971  		)
   972  
   973  		_, err = contract.GetPotentialStake(ctx)
   974  		if err == nil {
   975  			t.Fatal("expected error with unpacking")
   976  		}
   977  	})
   978  
   979  	t.Run("transaction error", func(t *testing.T) {
   980  		t.Parallel()
   981  
   982  		contract := staking.New(
   983  			owner,
   984  			stakingAddress,
   985  			stakingContractABI,
   986  			bzzTokenAddress,
   987  			transactionMock.New(
   988  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
   989  					return nil, errors.New("some error")
   990  				}),
   991  			),
   992  			nonce,
   993  			false,
   994  		)
   995  
   996  		_, err := contract.GetPotentialStake(ctx)
   997  		if err == nil {
   998  			t.Fatal("expected error")
   999  		}
  1000  	})
  1001  }
  1002  
  1003  func TestWithdrawStake(t *testing.T) {
  1004  	t.Parallel()
  1005  
  1006  	ctx := context.Background()
  1007  	owner := common.HexToAddress("abcd")
  1008  	stakingContractAddress := common.HexToAddress("ffff")
  1009  	bzzTokenAddress := common.HexToAddress("eeee")
  1010  	nonce := common.BytesToHash(make([]byte, 32))
  1011  	withdrawableStake := big.NewInt(100000000000000000)
  1012  
  1013  	t.Run("ok", func(t *testing.T) {
  1014  		t.Parallel()
  1015  		txHashWithdrawn := common.HexToHash("c3a1")
  1016  
  1017  		expectedCallDataForWithdraw, err := stakingContractABI.Pack("withdrawFromStake")
  1018  		if err != nil {
  1019  			t.Fatal(err)
  1020  		}
  1021  		expectedCallDataForGetStake, err := stakingContractABI.Pack("withdrawableStake")
  1022  		if err != nil {
  1023  			t.Fatal(err)
  1024  		}
  1025  
  1026  		contract := staking.New(
  1027  			owner,
  1028  			stakingContractAddress,
  1029  			stakingContractABI,
  1030  			bzzTokenAddress,
  1031  			transactionMock.New(
  1032  				transactionMock.WithSendFunc(func(ctx context.Context, request *transaction.TxRequest, boost int) (txHash common.Hash, err error) {
  1033  					if *request.To == stakingContractAddress {
  1034  						if !bytes.Equal(expectedCallDataForWithdraw[:], request.Data[:]) {
  1035  							return common.Hash{}, fmt.Errorf("got wrong call data. wanted %x, got %x", expectedCallDataForWithdraw, request.Data)
  1036  						}
  1037  						return txHashWithdrawn, nil
  1038  					}
  1039  					return common.Hash{}, errors.New("sent to wrong contract")
  1040  				}),
  1041  				transactionMock.WithWaitForReceiptFunc(func(ctx context.Context, txHash common.Hash) (receipt *types.Receipt, err error) {
  1042  					if txHash == txHashWithdrawn {
  1043  						return &types.Receipt{
  1044  							Status: 1,
  1045  						}, nil
  1046  					}
  1047  					return nil, errors.New("unknown tx hash")
  1048  				}),
  1049  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
  1050  					if *request.To == stakingContractAddress {
  1051  						if bytes.Equal(expectedCallDataForGetStake[:32], request.Data[:32]) {
  1052  							return withdrawableStake.FillBytes(make([]byte, 32)), nil
  1053  						}
  1054  					}
  1055  					return nil, errors.New("unexpected call")
  1056  				}),
  1057  			),
  1058  			nonce,
  1059  			false,
  1060  		)
  1061  
  1062  		_, err = contract.WithdrawStake(ctx)
  1063  		if err != nil {
  1064  			t.Fatal(err)
  1065  		}
  1066  	})
  1067  
  1068  	t.Run("has no stake", func(t *testing.T) {
  1069  		t.Parallel()
  1070  
  1071  		invalidStakedAmount := big.NewInt(0)
  1072  
  1073  		expectedCallDataForGetStake, err := stakingContractABI.Pack("withdrawableStake")
  1074  		if err != nil {
  1075  			t.Fatal(err)
  1076  		}
  1077  
  1078  		contract := staking.New(
  1079  			owner,
  1080  			stakingContractAddress,
  1081  			stakingContractABI,
  1082  			bzzTokenAddress,
  1083  			transactionMock.New(
  1084  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
  1085  					if *request.To == stakingContractAddress {
  1086  						if bytes.Equal(expectedCallDataForGetStake[:32], request.Data[:32]) {
  1087  							return invalidStakedAmount.FillBytes(make([]byte, 32)), nil
  1088  						}
  1089  					}
  1090  					return nil, errors.New("unexpected call")
  1091  				}),
  1092  			),
  1093  			nonce,
  1094  			false,
  1095  		)
  1096  
  1097  		_, err = contract.WithdrawStake(ctx)
  1098  		if !errors.Is(err, staking.ErrInsufficientStake) {
  1099  			t.Fatal(err)
  1100  		}
  1101  	})
  1102  
  1103  	t.Run("send tx failed", func(t *testing.T) {
  1104  		t.Parallel()
  1105  		txHashWithdrawn := common.HexToHash("c3a1")
  1106  
  1107  		expectedCallDataForWithdraw, err := stakingContractABI.Pack("withdrawFromStake")
  1108  		if err != nil {
  1109  			t.Fatal(err)
  1110  		}
  1111  		expectedCallDataForGetStake, err := stakingContractABI.Pack("withdrawableStake")
  1112  		if err != nil {
  1113  			t.Fatal(err)
  1114  		}
  1115  
  1116  		expectedErr := errors.New("tx err")
  1117  
  1118  		contract := staking.New(
  1119  			owner,
  1120  			stakingContractAddress,
  1121  			stakingContractABI,
  1122  			bzzTokenAddress,
  1123  			transactionMock.New(
  1124  				transactionMock.WithSendFunc(func(ctx context.Context, request *transaction.TxRequest, boost int) (txHash common.Hash, err error) {
  1125  					if *request.To == stakingContractAddress {
  1126  						if !bytes.Equal(expectedCallDataForWithdraw[:], request.Data[:]) {
  1127  							return common.Hash{}, fmt.Errorf("got wrong call data. wanted %x, got %x", expectedCallDataForWithdraw, request.Data)
  1128  						}
  1129  						return common.Hash{}, fmt.Errorf("send tx failed: %w", expectedErr)
  1130  					}
  1131  					return common.Hash{}, errors.New("sent to wrong contract")
  1132  				}),
  1133  				transactionMock.WithWaitForReceiptFunc(func(ctx context.Context, txHash common.Hash) (receipt *types.Receipt, err error) {
  1134  					if txHash == txHashWithdrawn {
  1135  						return &types.Receipt{
  1136  							Status: 1,
  1137  						}, nil
  1138  					}
  1139  					return nil, errors.New("unknown tx hash")
  1140  				}),
  1141  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
  1142  					if *request.To == stakingContractAddress {
  1143  						if bytes.Equal(expectedCallDataForGetStake[:32], request.Data[:32]) {
  1144  							return withdrawableStake.FillBytes(make([]byte, 32)), nil
  1145  						}
  1146  					}
  1147  					return nil, errors.New("unexpected call")
  1148  				}),
  1149  			),
  1150  			nonce,
  1151  			false,
  1152  		)
  1153  
  1154  		_, err = contract.WithdrawStake(ctx)
  1155  		if !errors.Is(err, expectedErr) {
  1156  			t.Fatalf("expected err %v, got %v", expectedErr, err)
  1157  		}
  1158  	})
  1159  
  1160  	t.Run("tx reverted", func(t *testing.T) {
  1161  		t.Parallel()
  1162  		txHashWithdrawn := common.HexToHash("c3a1")
  1163  
  1164  		expectedCallDataForWithdraw, err := stakingContractABI.Pack("withdrawFromStake")
  1165  		if err != nil {
  1166  			t.Fatal(err)
  1167  		}
  1168  		expectedCallDataForGetStake, err := stakingContractABI.Pack("withdrawableStake")
  1169  		if err != nil {
  1170  			t.Fatal(err)
  1171  		}
  1172  
  1173  		contract := staking.New(
  1174  			owner,
  1175  			stakingContractAddress,
  1176  			stakingContractABI,
  1177  			bzzTokenAddress,
  1178  			transactionMock.New(
  1179  				transactionMock.WithSendFunc(func(ctx context.Context, request *transaction.TxRequest, boost int) (txHash common.Hash, err error) {
  1180  					if *request.To == stakingContractAddress {
  1181  						if !bytes.Equal(expectedCallDataForWithdraw[:], request.Data[:]) {
  1182  							return common.Hash{}, fmt.Errorf("got wrong call data. wanted %x, got %x", expectedCallDataForWithdraw, request.Data)
  1183  						}
  1184  						return txHashWithdrawn, nil
  1185  					}
  1186  					return common.Hash{}, errors.New("sent to wrong contract")
  1187  				}),
  1188  				transactionMock.WithWaitForReceiptFunc(func(ctx context.Context, txHash common.Hash) (receipt *types.Receipt, err error) {
  1189  					if txHash == txHashWithdrawn {
  1190  						return &types.Receipt{
  1191  							Status: 0,
  1192  						}, nil
  1193  					}
  1194  					return nil, errors.New("unknown tx hash")
  1195  				}),
  1196  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
  1197  					if *request.To == stakingContractAddress {
  1198  						if bytes.Equal(expectedCallDataForGetStake[:32], request.Data[:32]) {
  1199  							return withdrawableStake.FillBytes(make([]byte, 32)), nil
  1200  						}
  1201  					}
  1202  					return nil, errors.New("unexpected call")
  1203  				}),
  1204  			),
  1205  			nonce,
  1206  			false,
  1207  		)
  1208  
  1209  		_, err = contract.WithdrawStake(ctx)
  1210  		if err == nil {
  1211  			t.Fatalf("expected non nil error, got nil")
  1212  		}
  1213  	})
  1214  
  1215  	t.Run("get stake with err", func(t *testing.T) {
  1216  		t.Parallel()
  1217  
  1218  		expectedCallDataForGetStake, err := stakingContractABI.Pack("withdrawableStake")
  1219  		if err != nil {
  1220  			t.Fatal(err)
  1221  		}
  1222  
  1223  		contract := staking.New(
  1224  			owner,
  1225  			stakingContractAddress,
  1226  			stakingContractABI,
  1227  			bzzTokenAddress,
  1228  			transactionMock.New(
  1229  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
  1230  					if *request.To == stakingContractAddress {
  1231  						if bytes.Equal(expectedCallDataForGetStake[:32], request.Data[:32]) {
  1232  							return nil, fmt.Errorf("some error")
  1233  						}
  1234  					}
  1235  					return nil, errors.New("unexpected call")
  1236  				}),
  1237  			),
  1238  			nonce,
  1239  			false,
  1240  		)
  1241  
  1242  		_, err = contract.WithdrawStake(ctx)
  1243  		if err == nil {
  1244  			t.Fatalf("expected non nil error, got nil")
  1245  		}
  1246  	})
  1247  }
  1248  
  1249  func TestMigrateStake(t *testing.T) {
  1250  	t.Parallel()
  1251  
  1252  	ctx := context.Background()
  1253  	owner := common.HexToAddress("abcd")
  1254  	stakingContractAddress := common.HexToAddress("ffff")
  1255  	bzzTokenAddress := common.HexToAddress("eeee")
  1256  	nonce := common.BytesToHash(make([]byte, 32))
  1257  	stakedAmount := big.NewInt(100000000000000000)
  1258  
  1259  	t.Run("ok", func(t *testing.T) {
  1260  
  1261  		expectedCallDataForPaused, err := stakingContractABI.Pack("paused")
  1262  		if err != nil {
  1263  			t.Fatal(err)
  1264  		}
  1265  		expectedCallDataForWithdraw, err := stakingContractABI.Pack("migrateStake")
  1266  		if err != nil {
  1267  			t.Fatal(err)
  1268  		}
  1269  		expectedCallDataForGetStake, err := stakingContractABI.Pack("nodeEffectiveStake", owner)
  1270  		if err != nil {
  1271  			t.Fatal(err)
  1272  		}
  1273  
  1274  		t.Parallel()
  1275  		txHashWithdrawn := common.HexToHash("c3a1")
  1276  		expected := big.NewInt(1)
  1277  
  1278  		contract := staking.New(
  1279  			owner,
  1280  			stakingContractAddress,
  1281  			stakingContractABI,
  1282  			bzzTokenAddress,
  1283  			transactionMock.New(
  1284  				transactionMock.WithSendFunc(func(ctx context.Context, request *transaction.TxRequest, boost int) (txHash common.Hash, err error) {
  1285  					if *request.To == stakingContractAddress {
  1286  						if !bytes.Equal(expectedCallDataForWithdraw[:], request.Data[:]) {
  1287  							return common.Hash{}, fmt.Errorf("got wrong call data. wanted %x, got %x", expectedCallDataForWithdraw, request.Data)
  1288  						}
  1289  						return txHashWithdrawn, nil
  1290  					}
  1291  					return common.Hash{}, errors.New("sent to wrong contract")
  1292  				}),
  1293  				transactionMock.WithWaitForReceiptFunc(func(ctx context.Context, txHash common.Hash) (receipt *types.Receipt, err error) {
  1294  					if txHash == txHashWithdrawn {
  1295  						return &types.Receipt{
  1296  							Status: 1,
  1297  						}, nil
  1298  					}
  1299  					return nil, errors.New("unknown tx hash")
  1300  				}),
  1301  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
  1302  					if *request.To == stakingContractAddress {
  1303  						if bytes.Equal(expectedCallDataForPaused[:], request.Data[:]) {
  1304  							return expected.FillBytes(make([]byte, 32)), nil
  1305  						}
  1306  						if bytes.Equal(expectedCallDataForGetStake[:64], request.Data[:64]) {
  1307  							return stakedAmount.FillBytes(make([]byte, 32)), nil
  1308  						}
  1309  					}
  1310  					return nil, errors.New("unexpected call")
  1311  				}),
  1312  			),
  1313  			nonce,
  1314  			false,
  1315  		)
  1316  
  1317  		_, err = contract.MigrateStake(ctx)
  1318  		if err != nil {
  1319  			t.Fatal(err)
  1320  		}
  1321  	})
  1322  
  1323  	t.Run("is paused", func(t *testing.T) {
  1324  		t.Parallel()
  1325  		expected := big.NewInt(0)
  1326  
  1327  		expectedCallDataForPaused, err := stakingContractABI.Pack("paused")
  1328  		if err != nil {
  1329  			t.Fatal(err)
  1330  		}
  1331  
  1332  		contract := staking.New(
  1333  			owner,
  1334  			stakingContractAddress,
  1335  			stakingContractABI,
  1336  			bzzTokenAddress,
  1337  			transactionMock.New(
  1338  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
  1339  					if *request.To == stakingContractAddress {
  1340  						if bytes.Equal(expectedCallDataForPaused[:], request.Data[:]) {
  1341  							return expected.FillBytes(make([]byte, 32)), nil
  1342  						}
  1343  					}
  1344  					return nil, errors.New("unexpected call")
  1345  				}),
  1346  			),
  1347  			nonce,
  1348  			false,
  1349  		)
  1350  
  1351  		_, err = contract.MigrateStake(ctx)
  1352  		if !errors.Is(err, staking.ErrNotPaused) {
  1353  			t.Fatal(err)
  1354  		}
  1355  	})
  1356  
  1357  	t.Run("invalid call data", func(t *testing.T) {
  1358  		t.Parallel()
  1359  		_, err := stakingContractABI.Pack("paused", owner)
  1360  		if err == nil {
  1361  			t.Fatalf("expected non nil error, got nil")
  1362  		}
  1363  		_, err = stakingContractABI.Pack("migrateStake", owner)
  1364  		if err == nil {
  1365  			t.Fatalf("expected non nil error, got nil")
  1366  		}
  1367  
  1368  		_, err = stakingContractABI.Pack("nodeEffectiveStake", stakedAmount)
  1369  		if err == nil {
  1370  			t.Fatalf("expected non nil error, got nil")
  1371  		}
  1372  	})
  1373  
  1374  	t.Run("send tx failed", func(t *testing.T) {
  1375  		t.Parallel()
  1376  		txHashWithdrawn := common.HexToHash("c3a1")
  1377  		expected := big.NewInt(1)
  1378  
  1379  		expectedCallDataForPaused, err := stakingContractABI.Pack("paused")
  1380  		if err != nil {
  1381  			t.Fatal(err)
  1382  		}
  1383  		expectedCallDataForWithdraw, err := stakingContractABI.Pack("migrateStake")
  1384  		if err != nil {
  1385  			t.Fatal(err)
  1386  		}
  1387  		expectedCallDataForGetStake, err := stakingContractABI.Pack("nodeEffectiveStake", owner)
  1388  		if err != nil {
  1389  			t.Fatal(err)
  1390  		}
  1391  
  1392  		contract := staking.New(
  1393  			owner,
  1394  			stakingContractAddress,
  1395  			stakingContractABI,
  1396  			bzzTokenAddress,
  1397  			transactionMock.New(
  1398  				transactionMock.WithSendFunc(func(ctx context.Context, request *transaction.TxRequest, boost int) (txHash common.Hash, err error) {
  1399  					if *request.To == stakingContractAddress {
  1400  						if !bytes.Equal(expectedCallDataForWithdraw[:], request.Data[:]) {
  1401  							return common.Hash{}, fmt.Errorf("got wrong call data. wanted %x, got %x", expectedCallDataForWithdraw, request.Data)
  1402  						}
  1403  						return common.Hash{}, errors.New("send tx failed")
  1404  					}
  1405  					return common.Hash{}, errors.New("sent to wrong contract")
  1406  				}),
  1407  				transactionMock.WithWaitForReceiptFunc(func(ctx context.Context, txHash common.Hash) (receipt *types.Receipt, err error) {
  1408  					if txHash == txHashWithdrawn {
  1409  						return &types.Receipt{
  1410  							Status: 1,
  1411  						}, nil
  1412  					}
  1413  					return nil, errors.New("unknown tx hash")
  1414  				}),
  1415  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
  1416  					if *request.To == stakingContractAddress {
  1417  						if bytes.Equal(expectedCallDataForPaused[:], request.Data[:]) {
  1418  							return expected.FillBytes(make([]byte, 32)), nil
  1419  						}
  1420  						if bytes.Equal(expectedCallDataForGetStake[:64], request.Data[:64]) {
  1421  							return stakedAmount.FillBytes(make([]byte, 32)), nil
  1422  						}
  1423  					}
  1424  					return nil, errors.New("unexpected call")
  1425  				}),
  1426  			),
  1427  			nonce,
  1428  			false,
  1429  		)
  1430  
  1431  		_, err = contract.MigrateStake(ctx)
  1432  		if err == nil {
  1433  			t.Fatalf("expected non nil error, got nil")
  1434  		}
  1435  	})
  1436  
  1437  	t.Run("tx reverted", func(t *testing.T) {
  1438  
  1439  		expectedCallDataForPaused, err := stakingContractABI.Pack("paused")
  1440  		if err != nil {
  1441  			t.Fatal(err)
  1442  		}
  1443  		expectedCallDataForWithdraw, err := stakingContractABI.Pack("migrateStake")
  1444  		if err != nil {
  1445  			t.Fatal(err)
  1446  		}
  1447  		expectedCallDataForGetStake, err := stakingContractABI.Pack("nodeEffectiveStake", owner)
  1448  		if err != nil {
  1449  			t.Fatal(err)
  1450  		}
  1451  
  1452  		t.Parallel()
  1453  		txHashWithdrawn := common.HexToHash("c3a1")
  1454  		expected := big.NewInt(1)
  1455  
  1456  		contract := staking.New(
  1457  			owner,
  1458  			stakingContractAddress,
  1459  			stakingContractABI,
  1460  			bzzTokenAddress,
  1461  			transactionMock.New(
  1462  				transactionMock.WithSendFunc(func(ctx context.Context, request *transaction.TxRequest, boost int) (txHash common.Hash, err error) {
  1463  					if *request.To == stakingContractAddress {
  1464  						if !bytes.Equal(expectedCallDataForWithdraw[:], request.Data[:]) {
  1465  							return common.Hash{}, fmt.Errorf("got wrong call data. wanted %x, got %x", expectedCallDataForWithdraw, request.Data)
  1466  						}
  1467  						return txHashWithdrawn, nil
  1468  					}
  1469  					return common.Hash{}, errors.New("sent to wrong contract")
  1470  				}),
  1471  				transactionMock.WithWaitForReceiptFunc(func(ctx context.Context, txHash common.Hash) (receipt *types.Receipt, err error) {
  1472  					if txHash == txHashWithdrawn {
  1473  						return &types.Receipt{
  1474  							Status: 0,
  1475  						}, nil
  1476  					}
  1477  					return nil, errors.New("unknown tx hash")
  1478  				}),
  1479  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
  1480  					if *request.To == stakingContractAddress {
  1481  						if bytes.Equal(expectedCallDataForPaused[:], request.Data[:]) {
  1482  							return expected.FillBytes(make([]byte, 32)), nil
  1483  						}
  1484  						if bytes.Equal(expectedCallDataForGetStake[:64], request.Data[:64]) {
  1485  							return stakedAmount.FillBytes(make([]byte, 32)), nil
  1486  						}
  1487  					}
  1488  					return nil, errors.New("unexpected call")
  1489  				}),
  1490  			),
  1491  			nonce,
  1492  			false,
  1493  		)
  1494  
  1495  		_, err = contract.MigrateStake(ctx)
  1496  		if err == nil {
  1497  			t.Fatalf("expected non nil error, got nil")
  1498  		}
  1499  	})
  1500  
  1501  	t.Run("is paused with err", func(t *testing.T) {
  1502  
  1503  		expectedCallDataForPaused, err := stakingContractABI.Pack("paused")
  1504  		if err != nil {
  1505  			t.Fatal(err)
  1506  		}
  1507  
  1508  		t.Parallel()
  1509  
  1510  		contract := staking.New(
  1511  			owner,
  1512  			stakingContractAddress,
  1513  			stakingContractABI,
  1514  			bzzTokenAddress,
  1515  			transactionMock.New(
  1516  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
  1517  					if *request.To == stakingContractAddress {
  1518  						if bytes.Equal(expectedCallDataForPaused[:], request.Data[:]) {
  1519  							return nil, fmt.Errorf("some error")
  1520  						}
  1521  					}
  1522  					return nil, errors.New("unexpected call")
  1523  				}),
  1524  			),
  1525  			nonce,
  1526  			false,
  1527  		)
  1528  
  1529  		_, err = contract.WithdrawStake(ctx)
  1530  		if err == nil {
  1531  			t.Fatalf("expected non nil error, got nil")
  1532  		}
  1533  	})
  1534  
  1535  	t.Run("get stake with err", func(t *testing.T) {
  1536  
  1537  		expectedCallDataForPaused, err := stakingContractABI.Pack("paused")
  1538  		if err != nil {
  1539  			t.Fatal(err)
  1540  		}
  1541  		expectedCallDataForGetStake, err := stakingContractABI.Pack("nodeEffectiveStake", owner)
  1542  		if err != nil {
  1543  			t.Fatal(err)
  1544  		}
  1545  
  1546  		t.Parallel()
  1547  		expected := big.NewInt(1)
  1548  
  1549  		contract := staking.New(
  1550  			owner,
  1551  			stakingContractAddress,
  1552  			stakingContractABI,
  1553  			bzzTokenAddress,
  1554  			transactionMock.New(
  1555  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
  1556  					if *request.To == stakingContractAddress {
  1557  						if bytes.Equal(expectedCallDataForPaused[:], request.Data[:]) {
  1558  							return expected.FillBytes(make([]byte, 32)), nil
  1559  						}
  1560  						if bytes.Equal(expectedCallDataForGetStake[:64], request.Data[:64]) {
  1561  							return nil, fmt.Errorf("some error")
  1562  						}
  1563  					}
  1564  					return nil, errors.New("unexpected call")
  1565  				}),
  1566  			),
  1567  			nonce,
  1568  			false,
  1569  		)
  1570  
  1571  		_, err = contract.MigrateStake(ctx)
  1572  		if err == nil {
  1573  			t.Fatalf("expected non nil error, got nil")
  1574  		}
  1575  	})
  1576  }
  1577  
  1578  func getPotentialStakeResponse(t *testing.T, amount *big.Int) []byte {
  1579  	t.Helper()
  1580  
  1581  	ret := make([]byte, 32+32+32+32+32+32)
  1582  	copy(ret, swarm.RandAddress(t).Bytes())
  1583  	copy(ret[64:], amount.FillBytes(make([]byte, 32)))
  1584  
  1585  	return ret
  1586  }