github.com/status-im/status-go@v1.1.0/services/wallet/activity/activity_test.go (about)

     1  package activity
     2  
     3  import (
     4  	"context"
     5  	"database/sql"
     6  	"encoding/hex"
     7  	"math/big"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/status-im/status-go/services/wallet/common"
    12  	"github.com/status-im/status-go/services/wallet/testutils"
    13  	"github.com/status-im/status-go/services/wallet/transfer"
    14  	"github.com/status-im/status-go/t/helpers"
    15  	"github.com/status-im/status-go/walletdatabase"
    16  
    17  	eth "github.com/ethereum/go-ethereum/common"
    18  	"github.com/ethereum/go-ethereum/common/hexutil"
    19  	"github.com/ethereum/go-ethereum/core/types"
    20  
    21  	"github.com/stretchr/testify/require"
    22  )
    23  
    24  var mockupTime = time.Unix(946724400, 0) // 2000-01-01 12:00:00
    25  
    26  func tokenFromSymbol(chainID *common.ChainID, symbol string) *Token {
    27  	for i, t := range transfer.TestTokens {
    28  		if (chainID == nil || t.ChainID == uint64(*chainID)) && t.Symbol == symbol {
    29  			tokenType := Erc20
    30  			if testutils.SliceContains(transfer.NativeTokenIndices, i) {
    31  				tokenType = Native
    32  			}
    33  			return &Token{
    34  				TokenType: tokenType,
    35  				ChainID:   common.ChainID(t.ChainID),
    36  				Address:   t.Address,
    37  			}
    38  		}
    39  	}
    40  	return nil
    41  }
    42  
    43  func tokenFromCollectible(c *transfer.TestCollectible) Token {
    44  	return Token{
    45  		TokenType: Erc721,
    46  		ChainID:   c.ChainID,
    47  		Address:   c.TokenAddress,
    48  		TokenID:   (*hexutil.Big)(c.TokenID),
    49  	}
    50  }
    51  
    52  func setupTestActivityDBStorageChoice(tb testing.TB, inMemory bool) (deps FilterDependencies, close func()) {
    53  	var db *sql.DB
    54  	var err error
    55  	cleanupDB := func() error { return nil }
    56  	cleanupWalletDB := func() error { return nil }
    57  	if inMemory {
    58  		db, err = helpers.SetupTestMemorySQLDB(walletdatabase.DbInitializer{})
    59  		require.NoError(tb, err)
    60  	} else {
    61  		db, cleanupWalletDB, err = helpers.SetupTestSQLDB(walletdatabase.DbInitializer{}, "wallet-activity-tests")
    62  		require.NoError(tb, err)
    63  	}
    64  
    65  	deps = FilterDependencies{
    66  		db: db,
    67  		tokenSymbol: func(token Token) string {
    68  			switch token.TokenType {
    69  			case Native:
    70  				for i, t := range transfer.TestTokens {
    71  					if t.ChainID == uint64(token.ChainID) && testutils.SliceContains(transfer.NativeTokenIndices, i) {
    72  						return t.Symbol
    73  					}
    74  				}
    75  			case Erc20:
    76  				for _, t := range transfer.TestTokens {
    77  					if t.ChainID == uint64(token.ChainID) && t.Address == token.Address {
    78  						return t.Symbol
    79  					}
    80  				}
    81  			}
    82  			// In case of ERC721 and ERC1155 we don't have a symbol and they are not yet handled
    83  			return ""
    84  		},
    85  		// tokenFromSymbol nil chainID accepts first symbol found
    86  		tokenFromSymbol: tokenFromSymbol,
    87  		currentTimestamp: func() int64 {
    88  			return mockupTime.Unix()
    89  		},
    90  	}
    91  
    92  	return deps, func() {
    93  		require.NoError(tb, cleanupDB())
    94  		require.NoError(tb, cleanupWalletDB())
    95  	}
    96  }
    97  
    98  func setupTestActivityDB(tb testing.TB) (deps FilterDependencies, close func()) {
    99  	transfer.SetMultiTransactionIDGenerator(transfer.StaticIDCounter()) // to have different multi-transaction IDs even with fast execution
   100  	return setupTestActivityDBStorageChoice(tb, true)
   101  }
   102  
   103  type testData struct {
   104  	tr1               transfer.TestTransfer // index 1, ETH/Goerli
   105  	pendingTr         transfer.TestTransfer // index 2, ETH/Optimism
   106  	multiTx1Tr1       transfer.TestTransfer // index 3, USDC/Mainnet
   107  	multiTx2Tr1       transfer.TestTransfer // index 4, USDC/Goerli
   108  	multiTx1Tr2       transfer.TestTransfer // index 5, USDC/Optimism
   109  	multiTx2Tr2       transfer.TestTransfer // index 6, SNT/Mainnet
   110  	multiTx2PendingTr transfer.TestTransfer // index 7, DAI/Mainnet
   111  	multiTx3Tr1       transfer.TestTransfer // index 8, DAI/Goerli
   112  
   113  	multiTx1   transfer.MultiTransaction
   114  	multiTx1ID common.MultiTransactionIDType
   115  
   116  	multiTx2   transfer.MultiTransaction
   117  	multiTx2ID common.MultiTransactionIDType
   118  
   119  	multiTx3   transfer.MultiTransaction
   120  	multiTx3ID common.MultiTransactionIDType
   121  
   122  	nextIndex int
   123  }
   124  
   125  // Generates and adds to the DB 8 transfers and 3 multitransactions.
   126  // There are only 5 extractable activity entries (transactions + multi-transactions) with timestamps 1-5. The others are associated with a multi-transaction
   127  func fillTestData(t *testing.T, db *sql.DB) (td testData, fromAddresses, toAddresses []eth.Address) {
   128  	// Generates ETH/Goerli, ETH/Optimism, USDC/Mainnet, USDC/Goerli, USDC/Optimism, SNT/Mainnet, DAI/Mainnet, DAI/Goerli
   129  	trs, fromAddresses, toAddresses := transfer.GenerateTestTransfers(t, db, 1, 8)
   130  
   131  	// Plain transfer
   132  	td.tr1 = trs[0]
   133  	transfer.InsertTestTransfer(t, db, td.tr1.To, &td.tr1)
   134  
   135  	// Pending transfer
   136  	td.pendingTr = trs[1]
   137  	transfer.InsertTestPendingTransaction(t, db, &td.pendingTr)
   138  
   139  	// Send Multitransaction containing 2 x Plain transfers
   140  	td.multiTx1Tr1 = trs[2]
   141  	td.multiTx1Tr2 = trs[7]
   142  
   143  	td.multiTx1 = transfer.GenerateTestSendMultiTransaction(td.multiTx1Tr1)
   144  	td.multiTx1.ToAsset = testutils.DaiSymbol
   145  	td.multiTx1ID = transfer.InsertTestMultiTransaction(t, db, &td.multiTx1)
   146  
   147  	td.multiTx1Tr1.MultiTransactionID = td.multiTx1ID
   148  	transfer.InsertTestTransfer(t, db, td.multiTx1Tr1.To, &td.multiTx1Tr1)
   149  
   150  	td.multiTx1Tr2.MultiTransactionID = td.multiTx1ID
   151  	transfer.InsertTestTransfer(t, db, td.multiTx1Tr2.To, &td.multiTx1Tr2)
   152  
   153  	// Send Multitransaction containing 2 x Plain transfers + 1 x Pending transfer
   154  	td.multiTx2Tr1 = trs[3]
   155  	td.multiTx2Tr2 = trs[5]
   156  	td.multiTx2PendingTr = trs[6]
   157  
   158  	td.multiTx2 = transfer.GenerateTestSendMultiTransaction(td.multiTx2Tr1)
   159  	td.multiTx2.ToAsset = testutils.SntSymbol
   160  
   161  	td.multiTx2ID = transfer.InsertTestMultiTransaction(t, db, &td.multiTx2)
   162  
   163  	td.multiTx2Tr1.MultiTransactionID = td.multiTx2ID
   164  	transfer.InsertTestTransfer(t, db, td.multiTx2Tr1.To, &td.multiTx2Tr1)
   165  
   166  	td.multiTx2Tr2.MultiTransactionID = td.multiTx2ID
   167  	transfer.InsertTestTransfer(t, db, td.multiTx2Tr2.To, &td.multiTx2Tr2)
   168  
   169  	td.multiTx2PendingTr.MultiTransactionID = td.multiTx2ID
   170  	transfer.InsertTestPendingTransaction(t, db, &td.multiTx2PendingTr)
   171  
   172  	// Approve Multitransaction containing 1 x Plain transfer
   173  	td.multiTx3Tr1 = trs[4]
   174  
   175  	td.multiTx3 = transfer.GenerateTestApproveMultiTransaction(td.multiTx3Tr1)
   176  
   177  	td.multiTx3ID = transfer.InsertTestMultiTransaction(t, db, &td.multiTx3)
   178  
   179  	td.multiTx3Tr1.MultiTransactionID = td.multiTx3ID
   180  	transfer.InsertTestTransfer(t, db, td.multiTx3Tr1.From, &td.multiTx3Tr1)
   181  
   182  	td.nextIndex = 9
   183  	return td, fromAddresses, toAddresses
   184  }
   185  
   186  func TTrToToken(t *testing.T, tt *transfer.TestTransaction) *Token {
   187  	token, isNative := transfer.TestTrToToken(t, tt)
   188  	tokenType := Erc20
   189  	if isNative {
   190  		tokenType = Native
   191  	}
   192  	return &Token{
   193  		TokenType: tokenType,
   194  		ChainID:   common.ChainID(token.ChainID),
   195  		Address:   token.Address,
   196  	}
   197  }
   198  
   199  func expectedTokenType(tokenAddress eth.Address) *TransferType {
   200  	transferType := new(TransferType)
   201  	if (tokenAddress != eth.Address{}) {
   202  		*transferType = TransferTypeErc20
   203  	} else {
   204  		*transferType = TransferTypeEth
   205  	}
   206  	return transferType
   207  }
   208  
   209  func TestGetActivityEntriesAll(t *testing.T) {
   210  	deps, close := setupTestActivityDB(t)
   211  	defer close()
   212  
   213  	td, fromAddresses, toAddresses := fillTestData(t, deps.db)
   214  
   215  	var filter Filter
   216  	entries, err := getActivityEntries(context.Background(), deps, append(toAddresses, fromAddresses...), true, []common.ChainID{}, filter, 0, 10)
   217  	require.NoError(t, err)
   218  	require.Equal(t, 5, len(entries))
   219  
   220  	// Ensure we have the correct order
   221  	var curTimestamp int64 = 5
   222  	for _, entry := range entries {
   223  		require.Equal(t, curTimestamp, entry.timestamp, "entries are sorted by timestamp; expected %d, got %d", curTimestamp, entry.timestamp)
   224  		curTimestamp--
   225  	}
   226  
   227  	expectedEntries := []Entry{
   228  		Entry{
   229  			payloadType:    MultiTransactionPT,
   230  			transaction:    nil,
   231  			id:             td.multiTx3ID,
   232  			timestamp:      int64(td.multiTx3.Timestamp),
   233  			activityType:   ApproveAT,
   234  			activityStatus: FinalizedAS,
   235  			amountOut:      td.multiTx3.FromAmount,
   236  			amountIn:       td.multiTx3.ToAmount,
   237  			tokenOut:       tokenFromSymbol(nil, td.multiTx3.FromAsset),
   238  			tokenIn:        tokenFromSymbol(nil, td.multiTx3.ToAsset),
   239  			symbolOut:      common.NewAndSet("USDC"),
   240  			symbolIn:       common.NewAndSet("USDC"),
   241  			sender:         &td.multiTx3.FromAddress,
   242  			recipient:      &td.multiTx3.ToAddress,
   243  		},
   244  		Entry{
   245  			payloadType:    MultiTransactionPT,
   246  			transaction:    nil,
   247  			id:             td.multiTx2ID,
   248  			timestamp:      int64(td.multiTx2.Timestamp),
   249  			activityType:   SendAT,
   250  			activityStatus: PendingAS,
   251  			amountOut:      td.multiTx2.FromAmount,
   252  			amountIn:       td.multiTx2.ToAmount,
   253  			symbolOut:      common.NewAndSet("USDC"),
   254  			symbolIn:       common.NewAndSet("SNT"),
   255  			tokenOut:       tokenFromSymbol(nil, td.multiTx2.FromAsset),
   256  			tokenIn:        tokenFromSymbol(nil, td.multiTx2.ToAsset),
   257  			sender:         &td.multiTx2.FromAddress,
   258  			recipient:      &td.multiTx2.ToAddress,
   259  		},
   260  		Entry{
   261  			payloadType:    MultiTransactionPT,
   262  			transaction:    nil,
   263  			id:             td.multiTx1ID,
   264  			timestamp:      int64(td.multiTx1.Timestamp),
   265  			activityType:   SendAT,
   266  			activityStatus: FinalizedAS,
   267  			amountOut:      td.multiTx1.FromAmount,
   268  			amountIn:       td.multiTx1.ToAmount,
   269  			tokenOut:       tokenFromSymbol(nil, td.multiTx1.FromAsset),
   270  			tokenIn:        tokenFromSymbol(nil, td.multiTx1.ToAsset),
   271  			symbolOut:      common.NewAndSet("USDC"),
   272  			symbolIn:       common.NewAndSet("DAI"),
   273  			sender:         &td.multiTx1.FromAddress,
   274  			recipient:      &td.multiTx1.ToAddress,
   275  		},
   276  		Entry{
   277  			payloadType:    PendingTransactionPT,
   278  			transaction:    &transfer.TransactionIdentity{ChainID: td.pendingTr.ChainID, Hash: td.pendingTr.Hash},
   279  			id:             td.pendingTr.MultiTransactionID,
   280  			timestamp:      td.pendingTr.Timestamp,
   281  			activityType:   SendAT,
   282  			activityStatus: PendingAS,
   283  			amountOut:      (*hexutil.Big)(big.NewInt(td.pendingTr.Value)),
   284  			amountIn:       (*hexutil.Big)(big.NewInt(0)),
   285  			tokenOut:       TTrToToken(t, &td.pendingTr.TestTransaction),
   286  			tokenIn:        nil,
   287  			symbolOut:      common.NewAndSet("ETH"),
   288  			symbolIn:       nil,
   289  			sender:         &td.pendingTr.From,
   290  			recipient:      &td.pendingTr.To,
   291  			chainIDOut:     &td.pendingTr.ChainID,
   292  			chainIDIn:      nil,
   293  			transferType:   expectedTokenType(eth.Address{}),
   294  		},
   295  		Entry{
   296  			payloadType:    SimpleTransactionPT,
   297  			transaction:    &transfer.TransactionIdentity{ChainID: td.tr1.ChainID, Hash: td.tr1.Hash, Address: td.tr1.To},
   298  			id:             td.tr1.MultiTransactionID,
   299  			timestamp:      td.tr1.Timestamp,
   300  			activityType:   ReceiveAT,
   301  			activityStatus: FinalizedAS,
   302  			amountOut:      (*hexutil.Big)(big.NewInt(0)),
   303  			amountIn:       (*hexutil.Big)(big.NewInt(td.tr1.Value)),
   304  			tokenOut:       nil,
   305  			tokenIn:        TTrToToken(t, &td.tr1.TestTransaction),
   306  			symbolOut:      nil,
   307  			symbolIn:       common.NewAndSet("ETH"),
   308  			sender:         &td.tr1.From,
   309  			recipient:      &td.tr1.To,
   310  			chainIDOut:     nil,
   311  			chainIDIn:      &td.tr1.ChainID,
   312  			transferType:   expectedTokenType(td.tr1.Token.Address),
   313  		},
   314  	}
   315  
   316  	for idx, expectedEntry := range expectedEntries {
   317  		require.Equal(t, expectedEntry, entries[idx], "entry %d", idx)
   318  	}
   319  }
   320  
   321  // TestGetActivityEntriesWithSenderFilter covers the corner-case of having both sender and receiver in the filter.
   322  // In this specific case we expect that there will be two transactions (one probably backed by a multi-transaction)
   323  // In case of both sender and receiver are included we validate we receive both entries otherwise only the "owned"
   324  // transactions should be retrieved by the filter
   325  func TestGetActivityEntriesWithSameTransactionForSenderAndReceiverInDB(t *testing.T) {
   326  	deps, close := setupTestActivityDB(t)
   327  	defer close()
   328  
   329  	// Add 4 extractable transactions with timestamps 1-4
   330  	td, _, _ := fillTestData(t, deps.db)
   331  
   332  	// Add another transaction with owner reversed
   333  	senderTr := td.tr1
   334  	// Ensure we have a consistent order
   335  	senderTr.Timestamp++
   336  	// add sender as owner, fillTestData adds receiver as owner
   337  	transfer.InsertTestTransfer(t, deps.db, senderTr.From, &senderTr)
   338  
   339  	var filter Filter
   340  	entries, err := getActivityEntries(context.Background(), deps, []eth.Address{td.tr1.To, senderTr.From}, false, []common.ChainID{}, filter, 0, 10)
   341  	require.NoError(t, err)
   342  	require.Equal(t, 2, len(entries))
   343  
   344  	// Check that the transaction are labeled alternatively as send and receive
   345  	require.Equal(t, SendAT, entries[0].activityType)
   346  	require.Equal(t, senderTr.From, entries[0].transaction.Address)
   347  	require.Equal(t, senderTr.From, *entries[0].sender)
   348  	require.Equal(t, senderTr.To, *entries[0].recipient)
   349  
   350  	require.Equal(t, ReceiveAT, entries[1].activityType)
   351  	require.Equal(t, td.tr1.To, *entries[1].recipient)
   352  	require.Equal(t, td.tr1.From, *entries[1].sender)
   353  	require.Equal(t, td.tr1.To, *entries[1].recipient)
   354  }
   355  
   356  func TestGetActivityEntriesFilterByTime(t *testing.T) {
   357  	deps, close := setupTestActivityDB(t)
   358  	defer close()
   359  
   360  	td, fromTds, toTds := fillTestData(t, deps.db)
   361  
   362  	// Add 6 extractable transactions with timestamps 7-13
   363  	trs, fromTrs, toTrs := transfer.GenerateTestTransfers(t, deps.db, td.nextIndex, 6)
   364  	for i := range trs {
   365  		transfer.InsertTestTransfer(t, deps.db, trs[i].To, &trs[i])
   366  	}
   367  
   368  	allAddresses := append(append(append(fromTds, toTds...), fromTrs...), toTrs...)
   369  
   370  	// Test start only
   371  	var filter Filter
   372  	filter.Period.StartTimestamp = int64(td.multiTx1.Timestamp)
   373  	filter.Period.EndTimestamp = NoLimitTimestampForPeriod
   374  	entries, err := getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
   375  	require.NoError(t, err)
   376  	require.Equal(t, 9, len(entries))
   377  
   378  	const simpleTrIndex = 5
   379  	// Check start and end content
   380  	require.Equal(t, Entry{
   381  		payloadType:    SimpleTransactionPT,
   382  		transaction:    &transfer.TransactionIdentity{ChainID: trs[simpleTrIndex].ChainID, Hash: trs[simpleTrIndex].Hash, Address: trs[simpleTrIndex].To},
   383  		id:             0,
   384  		timestamp:      trs[simpleTrIndex].Timestamp,
   385  		activityType:   ReceiveAT,
   386  		activityStatus: FinalizedAS,
   387  		amountOut:      (*hexutil.Big)(big.NewInt(0)),
   388  		amountIn:       (*hexutil.Big)(big.NewInt(trs[simpleTrIndex].Value)),
   389  		tokenOut:       nil,
   390  		tokenIn:        TTrToToken(t, &trs[simpleTrIndex].TestTransaction),
   391  		symbolOut:      nil,
   392  		symbolIn:       common.NewAndSet("USDC"),
   393  		sender:         &trs[simpleTrIndex].From,
   394  		recipient:      &trs[simpleTrIndex].To,
   395  		chainIDOut:     nil,
   396  		chainIDIn:      &trs[simpleTrIndex].ChainID,
   397  		transferType:   expectedTokenType(trs[simpleTrIndex].Token.Address),
   398  	}, entries[0])
   399  	require.Equal(t, Entry{
   400  		payloadType:    MultiTransactionPT,
   401  		transaction:    nil,
   402  		id:             td.multiTx1ID,
   403  		timestamp:      int64(td.multiTx1.Timestamp),
   404  		activityType:   SendAT,
   405  		activityStatus: FinalizedAS,
   406  		amountOut:      td.multiTx1.FromAmount,
   407  		amountIn:       td.multiTx1.ToAmount,
   408  		tokenOut:       tokenFromSymbol(nil, td.multiTx1.FromAsset),
   409  		tokenIn:        tokenFromSymbol(nil, td.multiTx1.ToAsset),
   410  		symbolOut:      common.NewAndSet("USDC"),
   411  		symbolIn:       common.NewAndSet("DAI"),
   412  		sender:         &td.multiTx1.FromAddress,
   413  		recipient:      &td.multiTx1.ToAddress,
   414  		chainIDOut:     nil,
   415  		chainIDIn:      nil,
   416  		transferType:   nil,
   417  	}, entries[8])
   418  
   419  	// Test complete interval
   420  	filter.Period.EndTimestamp = trs[2].Timestamp
   421  	entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
   422  	require.NoError(t, err)
   423  	require.Equal(t, 6, len(entries))
   424  
   425  	// Check start and end content
   426  	require.Equal(t, Entry{
   427  		payloadType:    SimpleTransactionPT,
   428  		transaction:    &transfer.TransactionIdentity{ChainID: trs[2].ChainID, Hash: trs[2].Hash, Address: trs[2].To},
   429  		id:             0,
   430  		timestamp:      trs[2].Timestamp,
   431  		activityType:   ReceiveAT,
   432  		activityStatus: FinalizedAS,
   433  		amountOut:      (*hexutil.Big)(big.NewInt(0)),
   434  		amountIn:       (*hexutil.Big)(big.NewInt(trs[2].Value)),
   435  		tokenOut:       nil,
   436  		tokenIn:        TTrToToken(t, &trs[2].TestTransaction),
   437  		symbolOut:      nil,
   438  		symbolIn:       common.NewAndSet("ETH"),
   439  		sender:         &trs[2].From,
   440  		recipient:      &trs[2].To,
   441  		chainIDOut:     nil,
   442  		chainIDIn:      &trs[2].ChainID,
   443  		transferType:   expectedTokenType(trs[2].Token.Address),
   444  	}, entries[0])
   445  	require.Equal(t, Entry{
   446  		payloadType:    MultiTransactionPT,
   447  		transaction:    nil,
   448  		id:             td.multiTx1ID,
   449  		timestamp:      int64(td.multiTx1.Timestamp),
   450  		activityType:   SendAT,
   451  		activityStatus: FinalizedAS,
   452  		amountOut:      td.multiTx1.FromAmount,
   453  		amountIn:       td.multiTx1.ToAmount,
   454  		tokenOut:       tokenFromSymbol(nil, td.multiTx1.FromAsset),
   455  		tokenIn:        tokenFromSymbol(nil, td.multiTx1.ToAsset),
   456  		symbolOut:      common.NewAndSet("USDC"),
   457  		symbolIn:       common.NewAndSet("DAI"),
   458  		sender:         &td.multiTx1.FromAddress,
   459  		recipient:      &td.multiTx1.ToAddress,
   460  		chainIDOut:     nil,
   461  		chainIDIn:      nil,
   462  		transferType:   nil,
   463  	}, entries[5])
   464  
   465  	// Test end only
   466  	filter.Period.StartTimestamp = NoLimitTimestampForPeriod
   467  	entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
   468  	require.NoError(t, err)
   469  	require.Equal(t, 8, len(entries))
   470  	// Check start and end content
   471  	require.Equal(t, Entry{
   472  		payloadType:    SimpleTransactionPT,
   473  		transaction:    &transfer.TransactionIdentity{ChainID: trs[2].ChainID, Hash: trs[2].Hash, Address: trs[2].To},
   474  		id:             0,
   475  		timestamp:      trs[2].Timestamp,
   476  		activityType:   ReceiveAT,
   477  		activityStatus: FinalizedAS,
   478  		amountOut:      (*hexutil.Big)(big.NewInt(0)),
   479  		amountIn:       (*hexutil.Big)(big.NewInt(trs[2].Value)),
   480  		tokenOut:       nil,
   481  		tokenIn:        TTrToToken(t, &trs[2].TestTransaction),
   482  		symbolOut:      nil,
   483  		symbolIn:       common.NewAndSet("ETH"),
   484  		sender:         &trs[2].From,
   485  		recipient:      &trs[2].To,
   486  		chainIDOut:     nil,
   487  		chainIDIn:      &trs[2].ChainID,
   488  		transferType:   expectedTokenType(trs[2].Token.Address),
   489  	}, entries[0])
   490  	require.Equal(t, Entry{
   491  		payloadType:    SimpleTransactionPT,
   492  		transaction:    &transfer.TransactionIdentity{ChainID: td.tr1.ChainID, Hash: td.tr1.Hash, Address: td.tr1.To},
   493  		id:             0,
   494  		timestamp:      td.tr1.Timestamp,
   495  		activityType:   ReceiveAT,
   496  		activityStatus: FinalizedAS,
   497  		amountOut:      (*hexutil.Big)(big.NewInt(0)),
   498  		amountIn:       (*hexutil.Big)(big.NewInt(td.tr1.Value)),
   499  		tokenOut:       nil,
   500  		tokenIn:        TTrToToken(t, &td.tr1.TestTransaction),
   501  		symbolOut:      nil,
   502  		symbolIn:       common.NewAndSet("ETH"),
   503  		sender:         &td.tr1.From,
   504  		recipient:      &td.tr1.To,
   505  		chainIDOut:     nil,
   506  		chainIDIn:      &td.tr1.ChainID,
   507  		transferType:   expectedTokenType(td.tr1.Token.Address),
   508  	}, entries[7])
   509  }
   510  
   511  func TestGetActivityEntriesCheckOffsetAndLimit(t *testing.T) {
   512  	deps, close := setupTestActivityDB(t)
   513  	defer close()
   514  
   515  	// Add 10 extractable transactions with timestamps 1-10
   516  	trs, fromTrs, toTrs := transfer.GenerateTestTransfers(t, deps.db, 1, 10)
   517  	for i := range trs {
   518  		transfer.InsertTestTransfer(t, deps.db, trs[i].To, &trs[i])
   519  	}
   520  
   521  	allAddresses := append(fromTrs, toTrs...)
   522  
   523  	var filter Filter
   524  	// Get all
   525  	entries, err := getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 5)
   526  	require.NoError(t, err)
   527  	require.Equal(t, 5, len(entries))
   528  
   529  	// Get time based interval
   530  	filter.Period.StartTimestamp = trs[2].Timestamp
   531  	filter.Period.EndTimestamp = trs[8].Timestamp
   532  	entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 3)
   533  	require.NoError(t, err)
   534  	require.Equal(t, 3, len(entries))
   535  	// Check start and end content
   536  	require.Equal(t, Entry{
   537  		payloadType:    SimpleTransactionPT,
   538  		transaction:    &transfer.TransactionIdentity{ChainID: trs[8].ChainID, Hash: trs[8].Hash, Address: trs[8].To},
   539  		id:             0,
   540  		timestamp:      trs[8].Timestamp,
   541  		activityType:   ReceiveAT,
   542  		activityStatus: FinalizedAS,
   543  		amountOut:      (*hexutil.Big)(big.NewInt(0)),
   544  		amountIn:       (*hexutil.Big)(big.NewInt(trs[8].Value)),
   545  		tokenOut:       nil,
   546  		tokenIn:        TTrToToken(t, &trs[8].TestTransaction),
   547  		symbolOut:      nil,
   548  		symbolIn:       common.NewAndSet("ETH"),
   549  		sender:         &trs[8].From,
   550  		recipient:      &trs[8].To,
   551  		chainIDOut:     nil,
   552  		chainIDIn:      &trs[8].ChainID,
   553  		transferType:   expectedTokenType(trs[8].Token.Address),
   554  	}, entries[0])
   555  	require.Equal(t, Entry{
   556  		payloadType:    SimpleTransactionPT,
   557  		transaction:    &transfer.TransactionIdentity{ChainID: trs[6].ChainID, Hash: trs[6].Hash, Address: trs[6].To},
   558  		id:             0,
   559  		timestamp:      trs[6].Timestamp,
   560  		activityType:   ReceiveAT,
   561  		activityStatus: FinalizedAS,
   562  		amountOut:      (*hexutil.Big)(big.NewInt(0)),
   563  		amountIn:       (*hexutil.Big)(big.NewInt(trs[6].Value)),
   564  		tokenOut:       nil,
   565  		tokenIn:        TTrToToken(t, &trs[6].TestTransaction),
   566  		symbolOut:      nil,
   567  		symbolIn:       common.NewAndSet("DAI"),
   568  		sender:         &trs[6].From,
   569  		recipient:      &trs[6].To,
   570  		chainIDOut:     nil,
   571  		chainIDIn:      &trs[6].ChainID,
   572  		transferType:   expectedTokenType(trs[6].Token.Address),
   573  	}, entries[2])
   574  
   575  	// Move window 2 entries forward
   576  	entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 2, 3)
   577  	require.NoError(t, err)
   578  	require.Equal(t, 3, len(entries))
   579  	// Check start and end content
   580  	require.Equal(t, Entry{
   581  		payloadType:    SimpleTransactionPT,
   582  		transaction:    &transfer.TransactionIdentity{ChainID: trs[6].ChainID, Hash: trs[6].Hash, Address: trs[6].To},
   583  		id:             0,
   584  		timestamp:      trs[6].Timestamp,
   585  		activityType:   ReceiveAT,
   586  		activityStatus: FinalizedAS,
   587  		amountOut:      (*hexutil.Big)(big.NewInt(0)),
   588  		amountIn:       (*hexutil.Big)(big.NewInt(trs[6].Value)),
   589  		tokenOut:       nil,
   590  		tokenIn:        TTrToToken(t, &trs[6].TestTransaction),
   591  		symbolOut:      nil,
   592  		symbolIn:       common.NewAndSet("DAI"),
   593  		sender:         &trs[6].From,
   594  		recipient:      &trs[6].To,
   595  		chainIDOut:     nil,
   596  		chainIDIn:      &trs[6].ChainID,
   597  		transferType:   expectedTokenType(trs[6].Token.Address),
   598  	}, entries[0])
   599  	require.Equal(t, Entry{
   600  		payloadType:    SimpleTransactionPT,
   601  		transaction:    &transfer.TransactionIdentity{ChainID: trs[4].ChainID, Hash: trs[4].Hash, Address: trs[4].To},
   602  		id:             0,
   603  		timestamp:      trs[4].Timestamp,
   604  		activityType:   ReceiveAT,
   605  		activityStatus: FinalizedAS,
   606  		amountOut:      (*hexutil.Big)(big.NewInt(0)),
   607  		amountIn:       (*hexutil.Big)(big.NewInt(trs[4].Value)),
   608  		tokenOut:       nil,
   609  		tokenIn:        TTrToToken(t, &trs[4].TestTransaction),
   610  		symbolOut:      nil,
   611  		symbolIn:       common.NewAndSet("USDC"),
   612  		sender:         &trs[4].From,
   613  		recipient:      &trs[4].To,
   614  		chainIDOut:     nil,
   615  		chainIDIn:      &trs[4].ChainID,
   616  		transferType:   expectedTokenType(trs[4].Token.Address),
   617  	}, entries[2])
   618  
   619  	// Move window 4 more entries to test filter cap
   620  	entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 6, 3)
   621  	require.NoError(t, err)
   622  	require.Equal(t, 1, len(entries))
   623  	// Check start and end content
   624  	require.Equal(t, Entry{
   625  		payloadType:    SimpleTransactionPT,
   626  		transaction:    &transfer.TransactionIdentity{ChainID: trs[2].ChainID, Hash: trs[2].Hash, Address: trs[2].To},
   627  		id:             0,
   628  		timestamp:      trs[2].Timestamp,
   629  		activityType:   ReceiveAT,
   630  		activityStatus: FinalizedAS,
   631  		amountOut:      (*hexutil.Big)(big.NewInt(0)),
   632  		amountIn:       (*hexutil.Big)(big.NewInt(trs[2].Value)),
   633  		tokenOut:       nil,
   634  		tokenIn:        TTrToToken(t, &trs[2].TestTransaction),
   635  		symbolOut:      nil,
   636  		symbolIn:       common.NewAndSet("USDC"),
   637  		sender:         &trs[2].From,
   638  		recipient:      &trs[2].To,
   639  		chainIDOut:     nil,
   640  		chainIDIn:      &trs[2].ChainID,
   641  		transferType:   expectedTokenType(trs[2].Token.Address),
   642  	}, entries[0])
   643  }
   644  
   645  func countTypes(entries []Entry) (sendCount, receiveCount, contractCount, mintCount, swapCount, buyCount, bridgeCount, approveCount int) {
   646  	for _, entry := range entries {
   647  		switch entry.activityType {
   648  		case SendAT:
   649  			sendCount++
   650  		case ReceiveAT:
   651  			receiveCount++
   652  		case SwapAT:
   653  			swapCount++
   654  		case BuyAT:
   655  			buyCount++
   656  		case BridgeAT:
   657  			bridgeCount++
   658  		case ContractDeploymentAT:
   659  			contractCount++
   660  		case MintAT:
   661  			mintCount++
   662  		case ApproveAT:
   663  			approveCount++
   664  		}
   665  	}
   666  	return
   667  }
   668  
   669  func TestGetActivityEntriesFilterByType(t *testing.T) {
   670  	deps, close := setupTestActivityDB(t)
   671  	defer close()
   672  
   673  	// Adds 4 extractable transactions
   674  	td, tdFromAdds, tdToAddrs := fillTestData(t, deps.db)
   675  	// Add 6 extractable transactions: one MultiTransactionSwap, two MultiTransactionBridge, two MultiTransactionSend and one MultiTransactionApprove
   676  	multiTxs := make([]transfer.MultiTransaction, 6)
   677  	trs, fromAddrs, toAddrs := transfer.GenerateTestTransfers(t, deps.db, td.nextIndex, len(multiTxs)*2)
   678  	multiTxs[0] = transfer.GenerateTestBridgeMultiTransaction(trs[0], trs[1])
   679  	multiTxs[1] = transfer.GenerateTestSwapMultiTransaction(trs[2], testutils.SntSymbol, 100) // trs[3]
   680  	multiTxs[2] = transfer.GenerateTestSendMultiTransaction(trs[4])                           // trs[5]
   681  	multiTxs[3] = transfer.GenerateTestBridgeMultiTransaction(trs[6], trs[7])
   682  	multiTxs[4] = transfer.GenerateTestSendMultiTransaction(trs[8])     // trs[9]
   683  	multiTxs[5] = transfer.GenerateTestApproveMultiTransaction(trs[10]) // trs[11]
   684  
   685  	var lastMT common.MultiTransactionIDType
   686  	for i := range trs {
   687  		if i%2 == 0 {
   688  			lastMT = transfer.InsertTestMultiTransaction(t, deps.db, &multiTxs[i/2])
   689  		}
   690  		trs[i].MultiTransactionID = lastMT
   691  		transfer.InsertTestTransfer(t, deps.db, trs[i].To, &trs[i])
   692  	}
   693  
   694  	trsSpecial, fromSpecial, toSpecial := transfer.GenerateTestTransfers(t, deps.db, 100, 3)
   695  
   696  	// Here not to include the modified To and From addresses
   697  	allAddresses := append(append(append(append(append(tdFromAdds, tdToAddrs...), fromAddrs...), toAddrs...), fromSpecial...), toSpecial...)
   698  
   699  	// Insert MintAT Collectible
   700  	trsSpecial[0].From = eth.HexToAddress("0x0")
   701  	transfer.InsertTestTransferWithOptions(t, deps.db, trsSpecial[0].To, &trsSpecial[0], &transfer.TestTransferOptions{
   702  		TokenAddress: eth.HexToAddress("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"),
   703  		TokenID:      (big.NewInt(1318)),
   704  	})
   705  
   706  	// Insert MintAT Token
   707  	trsSpecial[1].From = eth.HexToAddress("0x0")
   708  	inputMethod, err := hex.DecodeString("1b5ee6ae")
   709  	require.NoError(t, err)
   710  	transfer.InsertTestTransferWithOptions(t, deps.db, trsSpecial[1].To, &trsSpecial[1], &transfer.TestTransferOptions{
   711  		TokenAddress: eth.HexToAddress("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb49"),
   712  		Tx:           transfer.GenerateTxField(inputMethod),
   713  	})
   714  
   715  	// Insert ContractDeploymentAt
   716  	trsSpecial[2].To = eth.HexToAddress("0x0")
   717  	transfer.InsertTestTransferWithOptions(t, deps.db, trsSpecial[2].From, &trsSpecial[2], &transfer.TestTransferOptions{
   718  		NullifyAddresses: []eth.Address{trsSpecial[2].To},
   719  	})
   720  
   721  	// Test filtering out without address involved
   722  	var filter Filter
   723  
   724  	filter.Types = allActivityTypesFilter()
   725  	// Set tr1 to Receive and pendingTr to Send; rest of two MT remain default Send
   726  	addresses := []eth.Address{td.tr1.To, td.pendingTr.From, td.multiTx1.FromAddress, td.multiTx2.FromAddress, trs[0].From, trs[2].From, trs[4].From, trs[6].From, trs[8].From, trs[10].From, trsSpecial[0].To, trsSpecial[1].To, trsSpecial[2].From}
   727  	entries, err := getActivityEntries(context.Background(), deps, addresses, false, []common.ChainID{}, filter, 0, 15)
   728  	require.NoError(t, err)
   729  	require.Equal(t, 13, len(entries))
   730  
   731  	filter.Types = []Type{SendAT, SwapAT}
   732  	entries, err = getActivityEntries(context.Background(), deps, addresses, false, []common.ChainID{}, filter, 0, 15)
   733  	require.NoError(t, err)
   734  
   735  	// 3 from td Send + 2 trs MT Send + 1 (swap)
   736  	require.Equal(t, 6, len(entries))
   737  
   738  	sendCount, receiveCount, contractCount, mintCount, swapCount, _, bridgeCount, approveCount := countTypes(entries)
   739  
   740  	require.Equal(t, 5, sendCount)
   741  	require.Equal(t, 0, receiveCount)
   742  	require.Equal(t, 0, contractCount)
   743  	require.Equal(t, 0, mintCount)
   744  	require.Equal(t, 1, swapCount)
   745  	require.Equal(t, 0, bridgeCount)
   746  	require.Equal(t, 0, approveCount)
   747  
   748  	filter.Types = []Type{BridgeAT, ReceiveAT}
   749  	entries, err = getActivityEntries(context.Background(), deps, addresses, false, []common.ChainID{}, filter, 0, 15)
   750  	require.NoError(t, err)
   751  	require.Equal(t, 3, len(entries))
   752  
   753  	sendCount, receiveCount, contractCount, mintCount, swapCount, _, bridgeCount, approveCount = countTypes(entries)
   754  	require.Equal(t, 0, sendCount)
   755  	require.Equal(t, 1, receiveCount)
   756  	require.Equal(t, 0, contractCount)
   757  	require.Equal(t, 0, mintCount)
   758  	require.Equal(t, 0, swapCount)
   759  	require.Equal(t, 2, bridgeCount)
   760  	require.Equal(t, 0, approveCount)
   761  
   762  	filter.Types = []Type{MintAT}
   763  	entries, err = getActivityEntries(context.Background(), deps, addresses, false, []common.ChainID{}, filter, 0, 15)
   764  	require.NoError(t, err)
   765  	require.Equal(t, 2, len(entries))
   766  
   767  	sendCount, receiveCount, contractCount, mintCount, swapCount, _, bridgeCount, approveCount = countTypes(entries)
   768  	require.Equal(t, 0, sendCount)
   769  	require.Equal(t, 0, receiveCount)
   770  	require.Equal(t, 0, contractCount)
   771  	require.Equal(t, 2, mintCount)
   772  	require.Equal(t, 0, swapCount)
   773  	require.Equal(t, 0, bridgeCount)
   774  	require.Equal(t, 0, approveCount)
   775  
   776  	filter.Types = []Type{ContractDeploymentAT}
   777  	entries, err = getActivityEntries(context.Background(), deps, addresses, false, []common.ChainID{}, filter, 0, 15)
   778  	require.NoError(t, err)
   779  	require.Equal(t, 1, len(entries))
   780  
   781  	sendCount, receiveCount, contractCount, mintCount, swapCount, _, bridgeCount, approveCount = countTypes(entries)
   782  	require.Equal(t, 0, sendCount)
   783  	require.Equal(t, 0, receiveCount)
   784  	require.Equal(t, 1, contractCount)
   785  	require.Equal(t, 0, mintCount)
   786  	require.Equal(t, 0, swapCount)
   787  	require.Equal(t, 0, bridgeCount)
   788  	require.Equal(t, 0, approveCount)
   789  
   790  	filter.Types = []Type{ApproveAT}
   791  	entries, err = getActivityEntries(context.Background(), deps, addresses, false, []common.ChainID{}, filter, 0, 15)
   792  	require.NoError(t, err)
   793  	require.Equal(t, 1, len(entries))
   794  
   795  	sendCount, receiveCount, contractCount, mintCount, swapCount, _, bridgeCount, approveCount = countTypes(entries)
   796  	require.Equal(t, 0, sendCount)
   797  	require.Equal(t, 0, receiveCount)
   798  	require.Equal(t, 0, contractCount)
   799  	require.Equal(t, 0, mintCount)
   800  	require.Equal(t, 0, swapCount)
   801  	require.Equal(t, 0, bridgeCount)
   802  	require.Equal(t, 1, approveCount)
   803  
   804  	// Filter with all addresses regression
   805  	filter.Types = []Type{SendAT}
   806  	entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
   807  	require.NoError(t, err)
   808  	// We have 6 but one is not matched because is a receive, having owner the to address
   809  	require.Equal(t, 5, len(entries))
   810  }
   811  
   812  func TestStatusMintCustomEvent(t *testing.T) {
   813  	deps, close := setupTestActivityDB(t)
   814  	defer close()
   815  
   816  	td, fromTds, toTds := fillTestData(t, deps.db)
   817  	trs, fromTrs, toTrs := transfer.GenerateTestTransfers(t, deps.db, td.nextIndex, 3)
   818  
   819  	allAddresses := append(append(append(fromTds, toTds...), fromTrs...), toTrs...)
   820  
   821  	trs[0].From = eth.HexToAddress("0x0")
   822  	transfer.InsertTestTransferWithOptions(t, deps.db, trs[0].To, &trs[0], &transfer.TestTransferOptions{
   823  		TokenAddress: eth.HexToAddress("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"),
   824  		Receipt: &types.Receipt{
   825  			Logs: []*types.Log{
   826  				{Topics: []eth.Hash{eth.HexToHash("0xea667487ed28493de38fd2808b00affaee21d875a9e95aa01ef8352151292297")}},
   827  				{Topics: []eth.Hash{eth.HexToHash("0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925")}},
   828  			},
   829  		},
   830  	})
   831  	// StatusMint - 0x28c427b0611d99da5c4f7368abe57e86b045b483c4689ae93e90745802335b87
   832  	trs[1].From = eth.HexToAddress("0x0")
   833  	transfer.InsertTestTransferWithOptions(t, deps.db, trs[1].To, &trs[1], &transfer.TestTransferOptions{
   834  		TokenAddress: eth.HexToAddress("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb49"),
   835  		Receipt: &types.Receipt{
   836  			Logs: []*types.Log{
   837  				{Topics: []eth.Hash{eth.HexToHash("0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925")}},
   838  				{Topics: []eth.Hash{eth.HexToHash("0x28c427b0611d99da5c4f7368abe57e86b045b483c4689ae93e90745802335b87")}},
   839  			},
   840  		},
   841  	})
   842  
   843  	// Log order should not matter
   844  	trs[2].From = eth.HexToAddress("0x0")
   845  	transfer.InsertTestTransferWithOptions(t, deps.db, trs[2].To, &trs[2], &transfer.TestTransferOptions{
   846  		TokenAddress: eth.HexToAddress("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb49"),
   847  		Receipt: &types.Receipt{
   848  			Logs: []*types.Log{
   849  				{Topics: []eth.Hash{eth.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")}},
   850  				{Topics: []eth.Hash{eth.HexToHash("0x28c427b0611d99da5c4f7368abe57e86b045b483c4689ae93e90745802335b87")}},
   851  				{Topics: []eth.Hash{eth.HexToHash("0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925")}},
   852  			},
   853  		},
   854  	})
   855  
   856  	var filter Filter
   857  
   858  	entries, err := getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
   859  	require.NoError(t, err)
   860  	require.Equal(t, 8, len(entries))
   861  
   862  	filter.Types = []Type{MintAT}
   863  
   864  	entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
   865  	require.NoError(t, err)
   866  	require.Equal(t, 2, len(entries))
   867  	require.Equal(t, trs[2].Hash, entries[0].transaction.Hash)
   868  	require.Equal(t, trs[1].Hash, entries[1].transaction.Hash)
   869  }
   870  
   871  func TestGetActivityEntriesFilterByAddresses(t *testing.T) {
   872  	deps, close := setupTestActivityDB(t)
   873  	defer close()
   874  
   875  	// Adds 4 extractable transactions
   876  	td, fromTds, toTds := fillTestData(t, deps.db)
   877  	trs, fromTrs, toTrs := transfer.GenerateTestTransfers(t, deps.db, td.nextIndex, 6)
   878  	for i := range trs {
   879  		transfer.InsertTestTransfer(t, deps.db, trs[i].From, &trs[i])
   880  	}
   881  
   882  	allAddresses := append(append(append(fromTds, toTds...), fromTrs...), toTrs...)
   883  
   884  	var filter Filter
   885  
   886  	entries, err := getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
   887  	require.NoError(t, err)
   888  	require.Equal(t, 11, len(entries))
   889  
   890  	addressesFilter := []eth.Address{td.multiTx1.ToAddress, td.multiTx2.FromAddress, trs[1].From, trs[4].From, trs[3].To}
   891  	// The td.multiTx1.ToAddress and trs[3].To are missing not having them as owner address
   892  	entries, err = getActivityEntries(context.Background(), deps, addressesFilter, false, []common.ChainID{}, filter, 0, 15)
   893  	require.NoError(t, err)
   894  	require.Equal(t, 3, len(entries))
   895  	require.Equal(t, Entry{
   896  		payloadType:    SimpleTransactionPT,
   897  		transaction:    &transfer.TransactionIdentity{ChainID: trs[4].ChainID, Hash: trs[4].Hash, Address: trs[4].From},
   898  		id:             0,
   899  		timestamp:      trs[4].Timestamp,
   900  		activityType:   SendAT,
   901  		activityStatus: FinalizedAS,
   902  		amountOut:      (*hexutil.Big)(big.NewInt(trs[4].Value)),
   903  		amountIn:       (*hexutil.Big)(big.NewInt(0)),
   904  		tokenOut:       TTrToToken(t, &trs[4].TestTransaction),
   905  		tokenIn:        nil,
   906  		symbolOut:      common.NewAndSet("USDC"),
   907  		symbolIn:       nil,
   908  		sender:         &trs[4].From,
   909  		recipient:      &trs[4].To,
   910  		chainIDOut:     &trs[4].ChainID,
   911  		chainIDIn:      nil,
   912  		transferType:   expectedTokenType(trs[4].Token.Address),
   913  	}, entries[0])
   914  	require.Equal(t, Entry{
   915  		payloadType:    SimpleTransactionPT,
   916  		transaction:    &transfer.TransactionIdentity{ChainID: trs[1].ChainID, Hash: trs[1].Hash, Address: trs[1].From},
   917  		id:             0,
   918  		timestamp:      trs[1].Timestamp,
   919  		activityType:   SendAT,
   920  		activityStatus: FinalizedAS,
   921  		amountOut:      (*hexutil.Big)(big.NewInt(trs[1].Value)),
   922  		amountIn:       (*hexutil.Big)(big.NewInt(0)),
   923  		tokenOut:       TTrToToken(t, &trs[1].TestTransaction),
   924  		tokenIn:        nil,
   925  		symbolOut:      common.NewAndSet("ETH"),
   926  		symbolIn:       nil,
   927  		sender:         &trs[1].From,
   928  		recipient:      &trs[1].To,
   929  		chainIDOut:     &trs[1].ChainID,
   930  		chainIDIn:      nil,
   931  		transferType:   expectedTokenType(trs[1].Token.Address),
   932  	}, entries[1])
   933  	require.Equal(t, Entry{
   934  		payloadType:    MultiTransactionPT,
   935  		transaction:    nil,
   936  		id:             td.multiTx2ID,
   937  		timestamp:      int64(td.multiTx2.Timestamp),
   938  		activityType:   SendAT,
   939  		activityStatus: PendingAS,
   940  		amountOut:      td.multiTx2.FromAmount,
   941  		amountIn:       td.multiTx2.ToAmount,
   942  		tokenOut:       tokenFromSymbol(nil, td.multiTx2.FromAsset),
   943  		tokenIn:        tokenFromSymbol(nil, td.multiTx2.ToAsset),
   944  		symbolOut:      common.NewAndSet("USDC"),
   945  		symbolIn:       common.NewAndSet("SNT"),
   946  		sender:         &td.multiTx2.FromAddress,
   947  		recipient:      &td.multiTx2.ToAddress,
   948  		chainIDOut:     nil,
   949  		chainIDIn:      nil,
   950  	}, entries[2])
   951  }
   952  
   953  func TestGetActivityEntriesFilterByStatus(t *testing.T) {
   954  	deps, close := setupTestActivityDB(t)
   955  	defer close()
   956  
   957  	// Adds 4 extractable transactions: 1 T, 1 T pending, 1 MT pending, 1 MT with 2xT finalized
   958  	td, fromTds, toTds := fillTestData(t, deps.db)
   959  	// Add 7 extractable transactions: 1 pending, 1 Tr failed, 1 MT failed, 4 finalized
   960  	trs, fromTrs, toTrs := transfer.GenerateTestTransfers(t, deps.db, td.nextIndex, 7)
   961  	multiTx := transfer.GenerateTestSendMultiTransaction(trs[6])
   962  	failedMTID := transfer.InsertTestMultiTransaction(t, deps.db, &multiTx)
   963  	trs[6].MultiTransactionID = failedMTID
   964  	for i := range trs {
   965  		if i == 1 {
   966  			transfer.InsertTestPendingTransaction(t, deps.db, &trs[i])
   967  		} else {
   968  			trs[i].Success = i != 3 && i != 6
   969  			if trs[i].Success && (i == 2 || i == 5) {
   970  				// Finalize status depends on timestamp
   971  				trs[i].Timestamp = mockupTime.Unix() - 10
   972  			}
   973  			transfer.InsertTestTransfer(t, deps.db, trs[i].To, &trs[i])
   974  		}
   975  	}
   976  
   977  	allAddresses := append(append(append(fromTds, toTds...), fromTrs...), toTrs...)
   978  
   979  	var filter Filter
   980  	filter.Statuses = allActivityStatusesFilter()
   981  	entries, err := getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
   982  	require.NoError(t, err)
   983  	require.Equal(t, 12, len(entries))
   984  
   985  	filter.Statuses = []Status{PendingAS}
   986  	entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
   987  	require.NoError(t, err)
   988  	require.Equal(t, 3, len(entries))
   989  	require.Equal(t, td.pendingTr.Hash, entries[2].transaction.Hash)
   990  	require.Equal(t, td.multiTx2ID, entries[1].id)
   991  	require.Equal(t, trs[1].Hash, entries[0].transaction.Hash)
   992  
   993  	filter.Statuses = []Status{FailedAS}
   994  	entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
   995  	require.NoError(t, err)
   996  	require.Equal(t, 2, len(entries))
   997  
   998  	filter.Statuses = []Status{CompleteAS}
   999  	entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
  1000  	require.NoError(t, err)
  1001  	require.Equal(t, 2, len(entries))
  1002  
  1003  	filter.Statuses = []Status{FinalizedAS}
  1004  	entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
  1005  	require.NoError(t, err)
  1006  	require.Equal(t, 5, len(entries))
  1007  
  1008  	// Combined filter
  1009  	filter.Statuses = []Status{FailedAS, PendingAS}
  1010  	entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
  1011  	require.NoError(t, err)
  1012  	require.Equal(t, 5, len(entries))
  1013  }
  1014  
  1015  func TestGetActivityEntriesFilterByTokenType(t *testing.T) {
  1016  	deps, close := setupTestActivityDB(t)
  1017  	defer close()
  1018  
  1019  	// Adds 4 extractable transactions 2 transactions (ETH/Goerli, ETH/Optimism), one MT USDC to DAI and another MT USDC to SNT
  1020  	td, fromTds, toTds := fillTestData(t, deps.db)
  1021  	// Add 9 transactions DAI/Goerli, ETH/Mainnet, ETH/Goerli, ETH/Optimism, USDC/Mainnet, USDC/Goerli, USDC/Optimism, SNT/Mainnet, DAI/Mainnet
  1022  	trs, fromTrs, toTrs := transfer.GenerateTestTransfers(t, deps.db, td.nextIndex, 9)
  1023  	for i := range trs {
  1024  		tokenAddr := transfer.TestTokens[i].Address
  1025  		trs[i].ChainID = common.ChainID(transfer.TestTokens[i].ChainID)
  1026  		transfer.InsertTestTransferWithOptions(t, deps.db, trs[i].To, &trs[i], &transfer.TestTransferOptions{
  1027  			TokenAddress: tokenAddr,
  1028  		})
  1029  	}
  1030  
  1031  	allAddresses := append(append(append(fromTds, toTds...), fromTrs...), toTrs...)
  1032  
  1033  	var filter Filter
  1034  	filter.FilterOutAssets = true
  1035  	entries, err := getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
  1036  	require.NoError(t, err)
  1037  	require.Equal(t, 0, len(entries))
  1038  
  1039  	filter.FilterOutAssets = false
  1040  	filter.Assets = allTokensFilter()
  1041  	entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
  1042  	require.NoError(t, err)
  1043  	require.Equal(t, 14, len(entries))
  1044  
  1045  	// Native tokens are network agnostic, hence all are returned
  1046  	filter.Assets = []Token{{TokenType: Native, ChainID: common.ChainID(transfer.EthMainnet.ChainID)}}
  1047  	entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
  1048  	require.NoError(t, err)
  1049  	require.Equal(t, 5, len(entries))
  1050  
  1051  	// Test that it doesn't break the filter
  1052  	filter.Assets = []Token{{TokenType: Erc1155}}
  1053  	entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
  1054  	require.NoError(t, err)
  1055  	require.Equal(t, 0, len(entries))
  1056  
  1057  	filter.Assets = []Token{{
  1058  		TokenType: Erc20,
  1059  		ChainID:   common.ChainID(transfer.UsdcMainnet.ChainID),
  1060  		Address:   transfer.UsdcMainnet.Address,
  1061  	}}
  1062  	entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
  1063  	require.NoError(t, err)
  1064  	// Three MT for which ChainID is ignored and one transfer on the main net and the Goerli is ignored
  1065  	require.Equal(t, 4, len(entries))
  1066  	require.Equal(t, Erc20, entries[0].tokenIn.TokenType)
  1067  	require.Equal(t, transfer.UsdcMainnet.Address, entries[0].tokenIn.Address)
  1068  	require.Nil(t, entries[0].tokenOut)
  1069  	// MT has only symbol, the first token is lookup by symbol for both entries
  1070  	require.Equal(t, Erc20, entries[1].tokenOut.TokenType)
  1071  	require.Equal(t, transfer.UsdcMainnet.Address, entries[1].tokenOut.Address)
  1072  	require.Equal(t, Erc20, entries[1].tokenIn.TokenType)
  1073  	require.Equal(t, transfer.UsdcMainnet.Address, entries[1].tokenIn.Address)
  1074  	require.Equal(t, Erc20, entries[2].tokenOut.TokenType)
  1075  	require.Equal(t, transfer.UsdcMainnet.Address, entries[2].tokenOut.Address)
  1076  	require.Equal(t, Erc20, entries[2].tokenIn.TokenType)
  1077  	require.Equal(t, transfer.SntMainnet.Address, entries[2].tokenIn.Address)
  1078  	require.Equal(t, Erc20, entries[3].tokenOut.TokenType)
  1079  	require.Equal(t, transfer.UsdcMainnet.Address, entries[3].tokenOut.Address)
  1080  
  1081  	filter.Assets = []Token{{
  1082  		TokenType: Erc20,
  1083  		ChainID:   common.ChainID(transfer.UsdcMainnet.ChainID),
  1084  		Address:   transfer.UsdcMainnet.Address,
  1085  	}, {
  1086  		TokenType: Erc20,
  1087  		ChainID:   common.ChainID(transfer.UsdcGoerli.ChainID),
  1088  		Address:   transfer.UsdcGoerli.Address,
  1089  	}}
  1090  	entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
  1091  	require.NoError(t, err)
  1092  	// Three MT for which ChainID is ignored and two transfers on the main net and Goerli
  1093  	require.Equal(t, 5, len(entries))
  1094  	require.Equal(t, Erc20, entries[0].tokenIn.TokenType)
  1095  	require.Equal(t, transfer.UsdcGoerli.Address, entries[0].tokenIn.Address)
  1096  	require.Nil(t, entries[0].tokenOut)
  1097  }
  1098  
  1099  func TestGetActivityEntriesFilterByCollectibles(t *testing.T) {
  1100  	deps, close := setupTestActivityDB(t)
  1101  	defer close()
  1102  
  1103  	// Adds 4 extractable transactions 2 transactions (ETH/Goerli, ETH/Optimism), one MT USDC to DAI and another MT USDC to SNT
  1104  	td, fromTds, toTds := fillTestData(t, deps.db)
  1105  	// Add 4 transactions with collectibles
  1106  	trs, fromTrs, toTrs := transfer.GenerateTestTransfers(t, deps.db, td.nextIndex, 4)
  1107  	for i := range trs {
  1108  		collectibleData := transfer.TestCollectibles[i]
  1109  		trs[i].ChainID = collectibleData.ChainID
  1110  		transfer.InsertTestTransferWithOptions(t, deps.db, trs[i].To, &trs[i], &transfer.TestTransferOptions{
  1111  			TokenAddress: collectibleData.TokenAddress,
  1112  			TokenID:      collectibleData.TokenID,
  1113  		})
  1114  	}
  1115  
  1116  	allAddresses := append(append(append(fromTds, toTds...), fromTrs...), toTrs...)
  1117  
  1118  	var filter Filter
  1119  	filter.FilterOutCollectibles = true
  1120  	entries, err := getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
  1121  	require.NoError(t, err)
  1122  	require.Equal(t, 0, len(entries))
  1123  
  1124  	filter.FilterOutCollectibles = false
  1125  	filter.Collectibles = allTokensFilter()
  1126  	entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
  1127  	require.NoError(t, err)
  1128  	require.Equal(t, 9, len(entries))
  1129  
  1130  	// Search for a specific collectible
  1131  	filter.Collectibles = []Token{tokenFromCollectible(&transfer.TestCollectibles[0])}
  1132  	entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
  1133  	require.NoError(t, err)
  1134  	require.Equal(t, 1, len(entries))
  1135  	require.Equal(t, entries[0].tokenIn.Address, transfer.TestCollectibles[0].TokenAddress)
  1136  	require.Equal(t, entries[0].tokenIn.TokenID, (*hexutil.Big)(transfer.TestCollectibles[0].TokenID))
  1137  
  1138  	// Search for a specific collectible
  1139  	filter.Collectibles = []Token{tokenFromCollectible(&transfer.TestCollectibles[3])}
  1140  	entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
  1141  	require.NoError(t, err)
  1142  	require.Equal(t, 1, len(entries))
  1143  	require.Equal(t, entries[0].tokenIn.Address, transfer.TestCollectibles[3].TokenAddress)
  1144  	require.Equal(t, entries[0].tokenIn.TokenID, (*hexutil.Big)(transfer.TestCollectibles[3].TokenID))
  1145  
  1146  	// Search for a multiple collectibles
  1147  	filter.Collectibles = []Token{tokenFromCollectible(&transfer.TestCollectibles[1]), tokenFromCollectible(&transfer.TestCollectibles[2])}
  1148  	entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
  1149  	require.NoError(t, err)
  1150  	require.Equal(t, 2, len(entries))
  1151  	require.Equal(t, entries[0].tokenIn.Address, transfer.TestCollectibles[2].TokenAddress)
  1152  	require.True(t, (*big.Int)(entries[0].tokenIn.TokenID).Cmp(transfer.TestCollectibles[2].TokenID) == 0)
  1153  	require.Equal(t, entries[1].tokenIn.Address, transfer.TestCollectibles[1].TokenAddress)
  1154  	require.True(t, (*big.Int)(entries[1].tokenIn.TokenID).Cmp(transfer.TestCollectibles[1].TokenID) == 0)
  1155  }
  1156  
  1157  func TestGetActivityEntriesFilterByToAddresses(t *testing.T) {
  1158  	deps, close := setupTestActivityDB(t)
  1159  	defer close()
  1160  
  1161  	// Adds 4 extractable transactions
  1162  	td, fromTds, toTds := fillTestData(t, deps.db)
  1163  	// Add 6 extractable transactions
  1164  	trs, fromTrs, toTrs := transfer.GenerateTestTransfers(t, deps.db, td.nextIndex, 6)
  1165  	for i := range trs {
  1166  		transfer.InsertTestTransfer(t, deps.db, trs[i].To, &trs[i])
  1167  	}
  1168  
  1169  	allAddresses := append(append(append(fromTds, toTds...), fromTrs...), toTrs...)
  1170  
  1171  	var filter Filter
  1172  	filter.CounterpartyAddresses = allAddresses
  1173  	entries, err := getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
  1174  	require.NoError(t, err)
  1175  	require.Equal(t, 11, len(entries))
  1176  
  1177  	filter.CounterpartyAddresses = []eth.Address{eth.HexToAddress("0x567890")}
  1178  	entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
  1179  	require.NoError(t, err)
  1180  	require.Equal(t, 0, len(entries))
  1181  
  1182  	filter.CounterpartyAddresses = []eth.Address{td.pendingTr.To, td.multiTx2.ToAddress, trs[3].To}
  1183  	entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
  1184  	require.NoError(t, err)
  1185  	require.Equal(t, 3, len(entries))
  1186  
  1187  	filter.CounterpartyAddresses = []eth.Address{td.tr1.To, td.pendingTr.From, trs[3].From, trs[5].To}
  1188  	entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
  1189  	require.NoError(t, err)
  1190  	require.Equal(t, 2, len(entries))
  1191  }
  1192  
  1193  func TestGetActivityEntriesFilterByNetworks(t *testing.T) {
  1194  	deps, close := setupTestActivityDB(t)
  1195  	defer close()
  1196  
  1197  	// Adds 4 extractable transactions
  1198  	td, fromTds, toTds := fillTestData(t, deps.db)
  1199  
  1200  	chainToEntryCount := make(map[common.ChainID]map[int]int)
  1201  	recordPresence := func(chainID common.ChainID, entry int) {
  1202  		if _, ok := chainToEntryCount[chainID]; !ok {
  1203  			chainToEntryCount[chainID] = make(map[int]int)
  1204  			chainToEntryCount[chainID][entry] = 1
  1205  		} else {
  1206  			if _, ok := chainToEntryCount[chainID][entry]; !ok {
  1207  				chainToEntryCount[chainID][entry] = 1
  1208  			} else {
  1209  				chainToEntryCount[chainID][entry]++
  1210  			}
  1211  		}
  1212  	}
  1213  	recordPresence(td.tr1.ChainID, 0)
  1214  	recordPresence(td.pendingTr.ChainID, 1)
  1215  	recordPresence(td.multiTx1Tr1.ChainID, 2)
  1216  	if td.multiTx1Tr2.ChainID != td.multiTx1Tr1.ChainID {
  1217  		recordPresence(td.multiTx1Tr2.ChainID, 2)
  1218  	}
  1219  	recordPresence(td.multiTx2Tr1.ChainID, 3)
  1220  	if td.multiTx2Tr2.ChainID != td.multiTx2Tr1.ChainID {
  1221  		recordPresence(td.multiTx2Tr2.ChainID, 3)
  1222  	}
  1223  	if td.multiTx2PendingTr.ChainID != td.multiTx2Tr1.ChainID && td.multiTx2PendingTr.ChainID != td.multiTx2Tr2.ChainID {
  1224  		recordPresence(td.multiTx2PendingTr.ChainID, 3)
  1225  	}
  1226  	recordPresence(td.multiTx3Tr1.ChainID, 4)
  1227  
  1228  	// Add 6 extractable transactions
  1229  	trs, fromTrs, toTrs := transfer.GenerateTestTransfers(t, deps.db, td.nextIndex, 6)
  1230  	for i := range trs {
  1231  		recordPresence(trs[i].ChainID, 5+i)
  1232  		transfer.InsertTestTransfer(t, deps.db, trs[i].To, &trs[i])
  1233  	}
  1234  	allAddresses := append(append(append(fromTds, toTds...), fromTrs...), toTrs...)
  1235  
  1236  	var filter Filter
  1237  	chainIDs := allNetworksFilter()
  1238  	entries, err := getActivityEntries(context.Background(), deps, allAddresses, true, chainIDs, filter, 0, 15)
  1239  	require.NoError(t, err)
  1240  	require.Equal(t, 11, len(entries))
  1241  
  1242  	chainIDs = []common.ChainID{5674839210}
  1243  	entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, chainIDs, filter, 0, 15)
  1244  	require.NoError(t, err)
  1245  	require.Equal(t, 0, len(entries))
  1246  
  1247  	chainIDs = []common.ChainID{td.pendingTr.ChainID, td.multiTx2Tr1.ChainID, trs[3].ChainID, td.multiTx3Tr1.ChainID}
  1248  	entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, chainIDs, filter, 0, 15)
  1249  	require.NoError(t, err)
  1250  	expectedResults := make(map[int]int)
  1251  	for _, chainID := range chainIDs {
  1252  		for entry := range chainToEntryCount[chainID] {
  1253  			if _, ok := expectedResults[entry]; !ok {
  1254  				expectedResults[entry]++
  1255  			}
  1256  		}
  1257  	}
  1258  	require.Equal(t, len(expectedResults), len(entries))
  1259  }
  1260  
  1261  func TestGetActivityEntriesFilterByNetworksOfSubTransactions(t *testing.T) {
  1262  	deps, close := setupTestActivityDB(t)
  1263  	defer close()
  1264  
  1265  	// Add 6 extractable transactions
  1266  	trs, _, toTrs := transfer.GenerateTestTransfers(t, deps.db, 0, 5)
  1267  	trs[0].ChainID = 1231
  1268  	trs[1].ChainID = 1232
  1269  	trs[2].ChainID = 1233
  1270  	mt1 := transfer.GenerateTestBridgeMultiTransaction(trs[0], trs[1])
  1271  	trs[0].MultiTransactionID = transfer.InsertTestMultiTransaction(t, deps.db, &mt1)
  1272  	trs[1].MultiTransactionID = mt1.ID
  1273  	trs[2].MultiTransactionID = mt1.ID
  1274  
  1275  	trs[3].ChainID = 1234
  1276  	mt2 := transfer.GenerateTestSwapMultiTransaction(trs[3], testutils.SntSymbol, 100)
  1277  	// insertMultiTransaction will insert 0 instead of NULL
  1278  	mt2.FromNetworkID = 0
  1279  	mt2.ToNetworkID = 0
  1280  	trs[3].MultiTransactionID = transfer.InsertTestMultiTransaction(t, deps.db, &mt2)
  1281  
  1282  	for i := range trs {
  1283  		if i == 2 {
  1284  			transfer.InsertTestPendingTransaction(t, deps.db, &trs[i])
  1285  		} else {
  1286  			transfer.InsertTestTransfer(t, deps.db, trs[i].To, &trs[i])
  1287  		}
  1288  	}
  1289  
  1290  	var filter Filter
  1291  	chainIDs := allNetworksFilter()
  1292  	entries, err := getActivityEntries(context.Background(), deps, toTrs, false, chainIDs, filter, 0, 15)
  1293  	require.NoError(t, err)
  1294  	require.Equal(t, 3, len(entries))
  1295  
  1296  	chainIDs = []common.ChainID{trs[0].ChainID, trs[1].ChainID}
  1297  	entries, err = getActivityEntries(context.Background(), deps, toTrs, false, chainIDs, filter, 0, 15)
  1298  	require.NoError(t, err)
  1299  	require.Equal(t, 1, len(entries))
  1300  	require.Equal(t, entries[0].id, mt1.ID)
  1301  
  1302  	// Filter by pending_transactions sub-transacitons
  1303  	chainIDs = []common.ChainID{trs[2].ChainID}
  1304  	entries, err = getActivityEntries(context.Background(), deps, toTrs, false, chainIDs, filter, 0, 15)
  1305  	require.NoError(t, err)
  1306  	require.Equal(t, 1, len(entries))
  1307  	require.Equal(t, entries[0].id, mt1.ID)
  1308  
  1309  	chainIDs = []common.ChainID{trs[3].ChainID}
  1310  	entries, err = getActivityEntries(context.Background(), deps, toTrs, false, chainIDs, filter, 0, 15)
  1311  	require.NoError(t, err)
  1312  	require.Equal(t, 1, len(entries))
  1313  	require.Equal(t, entries[0].id, mt2.ID)
  1314  }
  1315  
  1316  func TestGetActivityEntriesCheckToAndFrom(t *testing.T) {
  1317  	deps, close := setupTestActivityDB(t)
  1318  	defer close()
  1319  
  1320  	// Adds 6 transactions from which 4 are filtered out
  1321  	td, _, _ := fillTestData(t, deps.db)
  1322  
  1323  	// Add extra transactions to test To address
  1324  	trs, _, _ := transfer.GenerateTestTransfers(t, deps.db, td.nextIndex, 2)
  1325  	transfer.InsertTestTransfer(t, deps.db, trs[0].To, &trs[0])
  1326  	transfer.InsertTestPendingTransaction(t, deps.db, &trs[1])
  1327  
  1328  	addresses := []eth.Address{td.tr1.To, td.pendingTr.To,
  1329  		td.multiTx1.FromAddress, td.multiTx2.FromAddress, trs[0].To, trs[1].To}
  1330  
  1331  	var filter Filter
  1332  	entries, err := getActivityEntries(context.Background(), deps, addresses, false, []common.ChainID{}, filter, 0, 15)
  1333  	require.NoError(t, err)
  1334  	require.Equal(t, 6, len(entries))
  1335  
  1336  	require.Equal(t, ReceiveAT, entries[5].activityType)               // td.tr1
  1337  	require.NotEqual(t, eth.Address{}, entries[5].transaction.Address) // td.tr1
  1338  	require.Equal(t, td.tr1.To, *entries[5].recipient)                 // td.tr1
  1339  
  1340  	require.Equal(t, ReceiveAT, entries[4].activityType) // td.pendingTr
  1341  
  1342  	// Multi-transactions are always considered as SendAT
  1343  	require.Equal(t, SendAT, entries[3].activityType) // td.multiTx1
  1344  	require.Equal(t, SendAT, entries[2].activityType) // td.multiTx2
  1345  
  1346  	require.Equal(t, ReceiveAT, entries[1].activityType)               // trs[0]
  1347  	require.NotEqual(t, eth.Address{}, entries[1].transaction.Address) // trs[0]
  1348  	require.Equal(t, trs[0].To, entries[1].transaction.Address)        // trs[0]
  1349  
  1350  	require.Equal(t, ReceiveAT, entries[0].activityType) // trs[1] (pending)
  1351  }
  1352  
  1353  func TestGetActivityEntriesCheckContextCancellation(t *testing.T) {
  1354  	deps, close := setupTestActivityDB(t)
  1355  	defer close()
  1356  
  1357  	_, fromAddresses, toAddresses := fillTestData(t, deps.db)
  1358  
  1359  	cancellableCtx, cancelFn := context.WithCancel(context.Background())
  1360  	cancelFn()
  1361  
  1362  	activities, err := getActivityEntries(cancellableCtx, deps, append(fromAddresses, toAddresses...), true, []common.ChainID{}, Filter{}, 0, 10)
  1363  	require.ErrorIs(t, err, context.Canceled)
  1364  	require.Equal(t, 0, len(activities))
  1365  }
  1366  
  1367  func TestGetActivityEntriesNullAddresses(t *testing.T) {
  1368  	deps, close := setupTestActivityDB(t)
  1369  	defer close()
  1370  
  1371  	trs, _, _ := transfer.GenerateTestTransfers(t, deps.db, 0, 4)
  1372  	multiTx := transfer.GenerateTestBridgeMultiTransaction(trs[0], trs[1])
  1373  	multiTx.ToAddress = eth.Address{}
  1374  
  1375  	trs[0].MultiTransactionID = transfer.InsertTestMultiTransaction(t, deps.db, &multiTx)
  1376  	trs[1].MultiTransactionID = trs[0].MultiTransactionID
  1377  
  1378  	for i := 0; i < 3; i++ {
  1379  		transfer.InsertTestTransferWithOptions(t, deps.db, trs[i].From, &trs[i], &transfer.TestTransferOptions{
  1380  			NullifyAddresses: []eth.Address{trs[i].To},
  1381  		})
  1382  	}
  1383  
  1384  	trs[3].To = eth.Address{}
  1385  	transfer.InsertTestPendingTransaction(t, deps.db, &trs[3])
  1386  
  1387  	addresses := []eth.Address{trs[0].From, trs[1].From, trs[2].From, trs[3].From}
  1388  
  1389  	activities, err := getActivityEntries(context.Background(), deps, addresses, false, allNetworksFilter(), Filter{}, 0, 10)
  1390  	require.NoError(t, err)
  1391  	require.Equal(t, 3, len(activities))
  1392  }
  1393  
  1394  func TestGetActivityEntries_ErrorIfNoAddress(t *testing.T) {
  1395  	_, err := getActivityEntries(context.Background(), FilterDependencies{}, []eth.Address{}, true, []common.ChainID{}, Filter{}, 0, 10)
  1396  	require.EqualError(t, err, "no addresses provided")
  1397  }
  1398  
  1399  func TestGetTxDetails(t *testing.T) {
  1400  	deps, close := setupTestActivityDB(t)
  1401  	defer close()
  1402  
  1403  	// Adds 4 extractable transactions 2 transactions (ETH/Goerli, ETH/Optimism), one MT USDC to DAI and another MT USDC to SNT
  1404  	td, _, _ := fillTestData(t, deps.db)
  1405  
  1406  	_, err := getTxDetails(context.Background(), deps.db, "")
  1407  	require.EqualError(t, err, "invalid tx id")
  1408  
  1409  	details, err := getTxDetails(context.Background(), deps.db, td.tr1.Hash.String())
  1410  	require.NoError(t, err)
  1411  
  1412  	require.Equal(t, td.tr1.Hash.String(), details.ID)
  1413  	require.Equal(t, 0, details.MultiTxID)
  1414  	require.Equal(t, td.tr1.Nonce, details.Nonce)
  1415  	require.Equal(t, len(details.ChainDetails), 1)
  1416  	require.Equal(t, td.tr1.ChainID, common.ChainID(details.ChainDetails[0].ChainID))
  1417  	require.Equal(t, td.tr1.BlkNumber, details.ChainDetails[0].BlockNumber)
  1418  	require.Equal(t, td.tr1.Hash, details.ChainDetails[0].Hash)
  1419  	require.Equal(t, td.tr1.Contract, *details.ChainDetails[0].Contract)
  1420  }
  1421  
  1422  func TestGetMultiTxDetails(t *testing.T) {
  1423  	deps, close := setupTestActivityDB(t)
  1424  	defer close()
  1425  
  1426  	// Adds 4 extractable transactions 2 transactions (ETH/Goerli, ETH/Optimism), one MT USDC to DAI and another MT USDC to SNT
  1427  	td, _, _ := fillTestData(t, deps.db)
  1428  
  1429  	_, err := getMultiTxDetails(context.Background(), deps.db, 0)
  1430  	require.EqualError(t, err, "invalid tx id")
  1431  
  1432  	details, err := getMultiTxDetails(context.Background(), deps.db, int(td.multiTx1.ID))
  1433  	require.NoError(t, err)
  1434  
  1435  	require.Equal(t, "", details.ID)
  1436  	require.Equal(t, int(td.multiTx1.ID), details.MultiTxID)
  1437  	require.Equal(t, td.multiTx1Tr2.Nonce, details.Nonce)
  1438  	require.Equal(t, 2, len(details.ChainDetails))
  1439  	require.Equal(t, td.multiTx1Tr1.ChainID, common.ChainID(details.ChainDetails[0].ChainID))
  1440  	require.Equal(t, td.multiTx1Tr1.BlkNumber, details.ChainDetails[0].BlockNumber)
  1441  	require.Equal(t, td.multiTx1Tr1.Hash, details.ChainDetails[0].Hash)
  1442  	require.Equal(t, td.multiTx1Tr1.Contract, *details.ChainDetails[0].Contract)
  1443  	require.Equal(t, td.multiTx1Tr2.ChainID, common.ChainID(details.ChainDetails[1].ChainID))
  1444  	require.Equal(t, td.multiTx1Tr2.BlkNumber, details.ChainDetails[1].BlockNumber)
  1445  	require.Equal(t, td.multiTx1Tr2.Hash, details.ChainDetails[1].Hash)
  1446  	require.Equal(t, td.multiTx1Tr2.Contract, *details.ChainDetails[1].Contract)
  1447  }
  1448  
  1449  func TestGetActivityEntriesSkipEthGasFeeOnlyTransfers(t *testing.T) {
  1450  	deps, close := setupTestActivityDB(t)
  1451  	defer close()
  1452  
  1453  	to := eth.Address{0x1}
  1454  	from := eth.Address{0x2}
  1455  	hash := eth.Hash{0x3}
  1456  	blkNum := int64(1)
  1457  	chainID := common.ChainID(1)
  1458  	nonce := uint64(1)
  1459  
  1460  	// Insert 0-value gas-only ETH transfer as a result of token transfer's gas fee
  1461  	transfer.InsertTestTransfer(t, deps.db, to, &transfer.TestTransfer{
  1462  		TestTransaction: transfer.TestTransaction{
  1463  			ChainID:   chainID,
  1464  			From:      from,
  1465  			Hash:      hash,
  1466  			BlkNumber: blkNum,
  1467  			Nonce:     nonce,
  1468  		},
  1469  		To:    to,
  1470  		Value: 0,
  1471  	})
  1472  
  1473  	entries, err := getActivityEntries(context.Background(), deps, []eth.Address{to}, true, []common.ChainID{chainID}, Filter{}, 0, 10)
  1474  	require.NoError(t, err)
  1475  	require.Equal(t, 1, len(entries))
  1476  	require.Equal(t, hash, entries[0].transaction.Hash)
  1477  
  1478  	// Insert token transfer
  1479  	transfer.InsertTestTransferWithOptions(t, deps.db, to,
  1480  		&transfer.TestTransfer{
  1481  			TestTransaction: transfer.TestTransaction{
  1482  				ChainID:   chainID,
  1483  				From:      from,
  1484  				Hash:      hash,
  1485  				BlkNumber: blkNum,
  1486  				Nonce:     nonce,
  1487  			},
  1488  			To:    to,
  1489  			Value: 1,
  1490  		},
  1491  		&transfer.TestTransferOptions{
  1492  			TokenAddress: eth.Address{0x4},
  1493  		},
  1494  	)
  1495  
  1496  	// Gas-fee-only transfer should be removed, so we get only 1 transfer again
  1497  	entries, err = getActivityEntries(context.Background(), deps, []eth.Address{to}, true, []common.ChainID{chainID}, Filter{}, 0, 10)
  1498  	require.NoError(t, err)
  1499  	require.Equal(t, 1, len(entries))
  1500  	require.Equal(t, contractTypeFromDBType("erc20"), entries[0].transferType)
  1501  
  1502  	// Insert real 0-value ETH transfer
  1503  	transfer.InsertTestTransfer(t, deps.db, to, &transfer.TestTransfer{
  1504  		TestTransaction: transfer.TestTransaction{
  1505  			ChainID:   chainID,
  1506  			From:      from,
  1507  			Hash:      eth.Hash{0x5}, // another hash
  1508  			BlkNumber: blkNum,
  1509  			Nonce:     nonce + 1, // another nonce
  1510  		},
  1511  		To:    to,
  1512  		Value: 0, // 0-value as well
  1513  	})
  1514  
  1515  	entries, err = getActivityEntries(context.Background(), deps, []eth.Address{to}, true, []common.ChainID{chainID}, Filter{}, 0, 10)
  1516  	require.NoError(t, err)
  1517  	require.Equal(t, 2, len(entries))
  1518  }