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

     1  -- Query includes duplicates, will return multiple rows for the same transaction if both to and from addresses are in the address list.
     2  --
     3  -- The switch for tr_type is used to de-conflict the source for the two entries for the same transaction
     4  --
     5  -- UNION ALL is used to avoid the overhead of DISTINCT given that we don't expect to have duplicate entries outside the sender and receiver addresses being in the list which is handled separately
     6  --
     7  -- Only status FailedAS, PendingAS and CompleteAS are returned. FinalizedAS requires correlation with blockchain current state. As an optimization we approximate it by using timestamp information; see startTimestamp and endTimestamp
     8  --
     9  -- ContractDeploymentAT is subtype of SendAT and MintAT is subtype of ReceiveAT. It means query must prevent returning MintAT when filtering by ReceiveAT or ContractDeploymentAT when filtering by SendAT. That required duplicated code in filter by type query, to maintain performance.
    10  --
    11  -- Token filtering has two parts
    12  -- 1. Filtering by symbol (multi_transactions and pending_transactions tables) where the chain ID is ignored, basically the filter_networks will account for that
    13  -- 2. Filtering by token identity (chain and address for transfers table) where the symbol is ignored and all the token identities must be provided
    14  --
    15  WITH filter_conditions AS (
    16  	SELECT
    17  		? AS startFilterDisabled,
    18  		? AS startTimestamp,
    19  		? AS endFilterDisabled,
    20  		? AS endTimestamp,
    21  		? AS filterActivityTypeAll,
    22  		? AS filterActivityTypeSend,
    23  		? AS filterActivityTypeReceive,
    24  		? AS filterActivityTypeContractDeployment,
    25  		? AS filterActivityTypeMint,
    26  		? AS mTTypeSend,
    27  		? AS fromTrType,
    28  		? AS toTrType,
    29  		? AS filterAllAddresses,
    30  		? AS filterAllToAddresses,
    31  		? AS filterAllActivityStatus,
    32  		? AS filterStatusCompleted,
    33  		? AS filterStatusFailed,
    34  		? AS filterStatusFinalized,
    35  		? AS filterStatusPending,
    36  		? AS statusFailed,
    37  		? AS statusCompleted,
    38  		? AS statusFinalized,
    39  		? AS statusPending,
    40  		? AS includeAllTokenTypeAssets,
    41  		? AS includeAllCollectibles,
    42  		? AS includeAllNetworks,
    43  		? AS pendingStatus,
    44  		? AS nowTimestamp,
    45  		? AS layer2FinalisationDuration,
    46  		? AS layer1FinalisationDuration,
    47  		X'0000000000000000000000000000000000000000' AS zeroAddress,
    48  		'0x28c427b0611d99da5c4f7368abe57e86b045b483c4689ae93e90745802335b87' as communityMintEvent
    49  ),
    50  -- This UNION between CTE and TEMP TABLE acts as an optimization. As soon as we drop one or use them interchangeably the performance drops significantly.
    51  filter_addresses(address) AS (
    52  	SELECT
    53  		address
    54  	FROM
    55  		filter_addresses_table
    56  	WHERE
    57  		(
    58  			SELECT
    59  				filterAllAddresses
    60  			FROM
    61  				filter_conditions
    62  		) != 0
    63  	UNION
    64  	ALL
    65  	SELECT
    66  		*
    67  	FROM
    68  		(
    69  			VALUES
    70  				%s
    71  		)
    72  	WHERE
    73  		(
    74  			SELECT
    75  				filterAllAddresses
    76  			FROM
    77  				filter_conditions
    78  		) = 0
    79  ),
    80  filter_to_addresses(address) AS (
    81  	VALUES
    82  		%s
    83  ),
    84  assets_token_codes(token_code) AS (
    85  	VALUES
    86  		%s
    87  ),
    88  assets_erc20(chain_id, token_address) AS (
    89  	VALUES
    90  		%s
    91  ),
    92  assets_erc721(chain_id, token_id, token_address) AS (
    93  	VALUES
    94  		%s
    95  ),
    96  filter_networks(network_id) AS (
    97  	VALUES
    98  		%s
    99  ),
   100  tr_status AS (
   101  	SELECT
   102  		multi_transaction_id,
   103  		MIN(status) AS min_status,
   104  		COUNT(*) AS count,
   105  		network_id
   106  	FROM
   107  		transfers
   108  	WHERE
   109  		transfers.loaded == 1
   110  		AND transfers.multi_transaction_id != 0
   111  	GROUP BY
   112  		transfers.multi_transaction_id
   113  ),
   114  tr_network_ids AS (
   115  	SELECT
   116  		multi_transaction_id
   117  	FROM
   118  		transfers
   119  	WHERE
   120  		transfers.loaded == 1
   121  		AND transfers.multi_transaction_id != 0
   122  		AND network_id IN filter_networks
   123  	GROUP BY
   124  		transfers.multi_transaction_id
   125  ),
   126  pending_status AS (
   127  	SELECT
   128  		multi_transaction_id,
   129  		COUNT(*) AS count,
   130  		network_id
   131  	FROM
   132  		pending_transactions,
   133  		filter_conditions
   134  	WHERE
   135  		pending_transactions.multi_transaction_id != 0
   136  		AND pending_transactions.status = pendingStatus
   137  	GROUP BY
   138  		pending_transactions.multi_transaction_id
   139  ),
   140  pending_network_ids AS (
   141  	SELECT
   142  		multi_transaction_id
   143  	FROM
   144  		pending_transactions,
   145  		filter_conditions
   146  	WHERE
   147  		pending_transactions.multi_transaction_id != 0
   148  		AND pending_transactions.status = pendingStatus
   149  		AND pending_transactions.network_id IN filter_networks
   150  	GROUP BY
   151  		pending_transactions.multi_transaction_id
   152  ),
   153  layer2_networks(network_id) AS (
   154  	VALUES
   155  		%s
   156  ),
   157  mint_methods(method_hash) AS (
   158  	%s
   159  )
   160  
   161  SELECT
   162  	transfers.hash AS transfer_hash,
   163  	NULL AS pending_hash,
   164  	transfers.network_id AS network_id,
   165  	0 AS multi_tx_id,
   166  	transfers.timestamp AS timestamp,
   167  	NULL AS mt_type,
   168  	CASE
   169  		WHEN from_join.address IS NOT NULL AND to_join.address IS NULL THEN fromTrType
   170  		WHEN to_join.address IS NOT NULL AND from_join.address IS NULL THEN toTrType
   171  		WHEN from_join.address IS NOT NULL AND to_join.address IS NOT NULL THEN
   172  			CASE
   173  				WHEN transfers.address = transfers.tx_from_address THEN fromTrType
   174  				WHEN transfers.address = transfers.tx_to_address THEN toTrType
   175  				ELSE NULL
   176  			END
   177  		ELSE NULL
   178  	END as tr_type,
   179  	transfers.tx_from_address AS from_address,
   180  	transfers.tx_to_address AS to_address,
   181  	transfers.address AS owner_address,
   182  	transfers.amount_padded128hex AS tr_amount,
   183  	NULL AS ptr_amount,
   184  	NULL AS mt_from_amount,
   185  	NULL AS mt_to_amount,
   186  	CASE
   187  		WHEN transfers.status IS 1 THEN CASE
   188  			WHEN transfers.timestamp > 0
   189  			AND filter_conditions.nowTimestamp >= transfers.timestamp + (
   190  				CASE
   191  					WHEN transfers.network_id in layer2_networks THEN layer2FinalisationDuration
   192  					ELSE layer1FinalisationDuration
   193  				END
   194  			) THEN statusFinalized
   195  			ELSE statusCompleted
   196  		END
   197  		ELSE statusFailed
   198  	END AS agg_status,
   199  	1 AS agg_count,
   200  	transfers.token_address AS token_address,
   201  	CASE
   202  		WHEN LENGTH(transfers.token_id) = 0 THEN X'00'
   203  		ELSE transfers.token_id
   204  	END AS tmp_token_id,
   205  	NULL AS token_code,
   206  	NULL AS from_token_code,
   207  	NULL AS to_token_code,
   208  	NULL AS out_network_id,
   209  	NULL AS in_network_id,
   210  	transfers.type AS type,
   211  	transfers.contract_address AS contract_address,
   212  	CASE
   213  		WHEN transfers.tx_from_address = zeroAddress AND transfers.type = "erc20" THEN substr(json_extract(tx, '$.input'), 1, 10)
   214  		ELSE NULL
   215  	END AS method_hash,
   216  	CASE
   217  		WHEN transfers.tx_from_address = zeroAddress AND transfers.type = "erc20" THEN (SELECT 1 FROM json_each(transfers.receipt, '$.logs' ) WHERE json_extract( value, '$.topics[0]' ) = communityMintEvent)
   218  		ELSE NULL
   219  	END AS community_mint_event,
   220  	CASE 
   221  		WHEN transfers.type = 'erc20' THEN (SELECT community_id FROM tokens WHERE transfers.token_address = tokens.address AND transfers.network_id = tokens.network_id)
   222  		WHEN transfers.type = 'erc721' OR transfers.type = 'erc1155' THEN (SELECT community_id FROM collectible_data_cache WHERE transfers.token_address = collectible_data_cache.contract_address AND transfers.network_id = collectible_data_cache.chain_id)
   223  		ELSE NULL
   224  	END AS community_id
   225  FROM
   226  	transfers
   227  	CROSS JOIN filter_conditions
   228  	LEFT JOIN filter_addresses from_join ON transfers.tx_from_address = from_join.address
   229  	LEFT JOIN filter_addresses to_join ON transfers.tx_to_address = to_join.address
   230  WHERE
   231  	transfers.loaded == 1
   232  	AND transfers.multi_transaction_id = 0
   233  	AND (
   234  		(
   235  			startFilterDisabled
   236  			OR transfers.timestamp >= startTimestamp
   237  		)
   238  		AND (
   239  			endFilterDisabled
   240  			OR transfers.timestamp <= endTimestamp
   241  		)
   242  	)
   243  	AND (
   244  		-- Check description at the top of the file why code below is duplicated
   245  		filterActivityTypeAll
   246  		OR (
   247  			filterActivityTypeSend
   248  			AND tr_type = fromTrType -- Check NOT ContractDeploymentAT
   249  			AND NOT (
   250  				transfers.tx_to_address IS NULL
   251  				AND transfers.type = 'eth'
   252  				AND transfers.contract_address IS NOT NULL
   253  				AND transfers.contract_address != zeroAddress
   254  			)
   255  		)
   256  		OR (
   257  			filterActivityTypeReceive
   258  			AND tr_type = toTrType -- Check NOT MintAT
   259  			AND NOT (
   260  				(
   261  					transfers.tx_from_address IS NULL
   262  					OR transfers.tx_from_address = zeroAddress
   263  				)
   264  				AND (
   265  					transfers.type = 'erc721'
   266  					OR (
   267  						transfers.type = 'erc20'
   268  						AND (
   269  							(method_hash IS NOT NULL AND method_hash IN mint_methods)
   270  							OR community_mint_event IS NOT NULL
   271  						)
   272  					)
   273  				)
   274  			)
   275  		)
   276  		OR (
   277  			filterActivityTypeContractDeployment
   278  			AND tr_type = fromTrType
   279  			AND transfers.tx_to_address IS NULL
   280  			AND transfers.type = 'eth'
   281  			AND transfers.contract_address IS NOT NULL
   282  			AND transfers.contract_address != zeroAddress
   283  		)
   284  		OR (
   285  			filterActivityTypeMint
   286  			AND tr_type = toTrType
   287  			AND (
   288  				transfers.tx_from_address IS NULL
   289  				OR transfers.tx_from_address = zeroAddress
   290  			)
   291  			AND (
   292  				transfers.type = 'erc721'
   293  				OR (
   294  					transfers.type = 'erc20'
   295  					AND (
   296  						(method_hash IS NOT NULL AND method_hash IN mint_methods)
   297  						OR community_mint_event IS NOT NULL
   298  					)
   299  				)
   300  			)
   301  		)
   302  	)
   303  	AND (
   304  		filterAllAddresses -- Every account address has an "owned" entry either as to or from
   305  		OR (owner_address IN filter_addresses)
   306  	)
   307  	AND (
   308  		filterAllToAddresses
   309  		OR (transfers.tx_to_address IN filter_to_addresses)
   310  	)
   311  	AND (
   312  		includeAllTokenTypeAssets
   313  		OR (
   314  			transfers.type = 'eth'
   315  			AND ('ETH' IN assets_token_codes)
   316  		)
   317  		OR (
   318  			transfers.type = 'erc20'
   319  			AND (
   320  				(
   321  					transfers.network_id,
   322  					transfers.token_address
   323  				) IN assets_erc20
   324  			)
   325  		)
   326  	)
   327  	AND (
   328  		includeAllCollectibles
   329  		OR (
   330  			transfers.type = "erc721"
   331  			AND (
   332  				(
   333  					transfers.network_id,
   334  					tmp_token_id,
   335  					transfers.token_address
   336  				) IN assets_erc721
   337  			)
   338  		)
   339  	)
   340  	AND (
   341  		includeAllNetworks
   342  		OR (transfers.network_id IN filter_networks)
   343  	)
   344  	AND (
   345  		filterAllActivityStatus
   346  		OR (
   347  			filterStatusCompleted
   348  			AND agg_status = statusCompleted
   349  		)
   350  		OR (
   351  			filterStatusFinalized
   352  			AND agg_status = statusFinalized
   353  		)
   354  		OR (
   355  			filterStatusFailed
   356  			AND agg_status = statusFailed
   357  		)
   358  	)
   359  UNION
   360  ALL
   361  SELECT
   362  	NULL AS transfer_hash,
   363  	pending_transactions.hash AS pending_hash,
   364  	pending_transactions.network_id AS network_id,
   365  	0 AS multi_tx_id,
   366  	pending_transactions.timestamp AS timestamp,
   367  	NULL AS mt_type,
   368  	CASE
   369  		WHEN from_join.address IS NOT NULL AND to_join.address IS NULL THEN fromTrType
   370  		WHEN to_join.address IS NOT NULL AND from_join.address IS NULL THEN toTrType
   371  		WHEN from_join.address IS NOT NULL AND to_join.address IS NOT NULL THEN fromTrType
   372  		ELSE NULL
   373  	END as tr_type,
   374  	pending_transactions.from_address AS from_address,
   375  	pending_transactions.to_address AS to_address,
   376  	NULL AS owner_address,
   377  	NULL AS tr_amount,
   378  	pending_transactions.value AS ptr_amount,
   379  	NULL AS mt_from_amount,
   380  	NULL AS mt_to_amount,
   381  	statusPending AS agg_status,
   382  	1 AS agg_count,
   383  	NULL AS token_address,
   384  	NULL AS tmp_token_id,
   385  	pending_transactions.symbol AS token_code,
   386  	NULL AS from_token_code,
   387  	NULL AS to_token_code,
   388  	NULL AS out_network_id,
   389  	NULL AS in_network_id,
   390  	pending_transactions.type AS type,
   391  	NULL as contract_address,
   392  	NULL AS method_hash,
   393  	NULL AS community_mint_event,
   394  	NULL AS community_id
   395  FROM
   396  	pending_transactions
   397  	CROSS JOIN filter_conditions
   398  	LEFT JOIN filter_addresses from_join ON pending_transactions.from_address = from_join.address
   399  	LEFT JOIN filter_addresses to_join ON pending_transactions.to_address = to_join.address
   400  WHERE
   401  	pending_transactions.multi_transaction_id = 0
   402  	AND pending_transactions.status = pendingStatus
   403  	AND (
   404  		filterAllActivityStatus
   405  		OR filterStatusPending
   406  	)
   407  	AND includeAllCollectibles
   408  	AND (
   409  		(
   410  			startFilterDisabled
   411  			OR timestamp >= startTimestamp
   412  		)
   413  		AND (
   414  			endFilterDisabled
   415  			OR timestamp <= endTimestamp
   416  		)
   417  	)
   418  	AND (
   419  		filterActivityTypeAll
   420  		OR filterActivityTypeSend
   421  	)
   422  	AND (
   423  		filterAllAddresses
   424  		OR tr_type NOT NULL
   425  	)
   426  	AND (
   427  		filterAllToAddresses
   428  		OR (pending_transactions.to_address IN filter_to_addresses)
   429  	)
   430  	AND (
   431  		includeAllTokenTypeAssets
   432  		OR (
   433  			UPPER(pending_transactions.symbol) IN assets_token_codes
   434  		)
   435  	)
   436  	AND (
   437  		includeAllNetworks
   438  		OR (
   439  			pending_transactions.network_id IN filter_networks
   440  		)
   441  	)
   442  UNION
   443  ALL
   444  SELECT
   445  	NULL AS transfer_hash,
   446  	NULL AS pending_hash,
   447  	NULL AS network_id,
   448  	multi_transactions.id AS multi_tx_id,
   449  	multi_transactions.timestamp AS timestamp,
   450  	multi_transactions.type AS mt_type,
   451  	NULL as tr_type,
   452  	multi_transactions.from_address AS from_address,
   453  	multi_transactions.to_address AS to_address,
   454  	multi_transactions.from_address AS owner_address,
   455  	NULL AS tr_amount,
   456  	NULL AS ptr_amount,
   457  	multi_transactions.from_amount AS mt_from_amount,
   458  	multi_transactions.to_amount AS mt_to_amount,
   459  	CASE
   460  		WHEN tr_status.min_status = 1
   461  		AND COALESCE(pending_status.count, 0) = 0 THEN CASE
   462  			WHEN multi_transactions.timestamp > 0
   463  			AND filter_conditions.nowTimestamp >= multi_transactions.timestamp + (
   464  				CASE
   465  					WHEN multi_transactions.from_network_id in layer2_networks
   466  					OR multi_transactions.to_network_id in layer2_networks THEN layer2FinalisationDuration
   467  					ELSE layer1FinalisationDuration
   468  				END
   469  			) THEN statusFinalized
   470  			ELSE statusCompleted
   471  		END
   472  		WHEN tr_status.min_status = 0 THEN statusFailed
   473  		ELSE statusPending
   474  	END AS agg_status,
   475  	COALESCE(tr_status.count, 0) + COALESCE(pending_status.count, 0) AS agg_count,
   476  	NULL AS token_address,
   477  	NULL AS tmp_token_id,
   478  	NULL AS token_code,
   479  	multi_transactions.from_asset AS from_token_code,
   480  	multi_transactions.to_asset AS to_token_code,
   481  	multi_transactions.from_network_id AS out_network_id,
   482  	multi_transactions.to_network_id AS in_network_id,
   483  	NULL AS type,
   484  	NULL as contract_address,
   485  	NULL AS method_hash,
   486  	NULL AS community_mint_event,
   487  	NULL AS community_id
   488  FROM
   489  	multi_transactions
   490  	CROSS JOIN filter_conditions
   491  	LEFT JOIN tr_status ON multi_transactions.id = tr_status.multi_transaction_id
   492  	LEFT JOIN pending_status ON multi_transactions.id = pending_status.multi_transaction_id
   493  WHERE
   494  	(
   495  		(
   496  			startFilterDisabled
   497  			OR multi_transactions.timestamp >= startTimestamp
   498  		)
   499  		AND (
   500  			endFilterDisabled
   501  			OR multi_transactions.timestamp <= endTimestamp
   502  		)
   503  	)
   504  	AND includeAllCollectibles
   505  	AND (
   506  		filterActivityTypeAll
   507  		OR (multi_transactions.type IN (%s))
   508  	)
   509  	AND (
   510  		filterAllAddresses
   511  		OR (
   512  			-- Send multi-transaction types are exclusively for outbound transfers. The receiving end will have a corresponding entry as "owner_address" in the transfers table.
   513  			mt_type = mTTypeSend
   514  			AND owner_address IN filter_addresses
   515  		)
   516  		OR (
   517  			mt_type != mTTypeSend
   518  			AND (
   519  				multi_transactions.from_address IN filter_addresses
   520  				OR multi_transactions.to_address IN filter_addresses
   521  			)
   522  		)
   523  	)
   524  	AND (
   525  		filterAllToAddresses
   526  		OR (multi_transactions.to_address IN filter_to_addresses)
   527  	)
   528  	AND (
   529  		includeAllTokenTypeAssets
   530  		OR (
   531  			multi_transactions.from_asset != ''
   532  			AND (
   533  				UPPER(multi_transactions.from_asset) IN assets_token_codes
   534  			)
   535  		)
   536  		OR (
   537  			multi_transactions.to_asset != ''
   538  			AND (
   539  				UPPER(multi_transactions.to_asset) IN assets_token_codes
   540  			)
   541  		)
   542  	)
   543  	AND (
   544  		filterAllActivityStatus
   545  		OR (
   546  			filterStatusCompleted
   547  			AND agg_status = statusCompleted
   548  		)
   549  		OR (
   550  			filterStatusFinalized
   551  			AND agg_status = statusFinalized
   552  		)
   553  		OR (
   554  			filterStatusFailed
   555  			AND agg_status = statusFailed
   556  		)
   557  		OR (
   558  			filterStatusPending
   559  			AND agg_status = statusPending
   560  		)
   561  	)
   562  	AND (
   563  		includeAllNetworks
   564  		OR (
   565  			multi_transactions.from_network_id IN filter_networks
   566  		)
   567  		OR (
   568  			multi_transactions.to_network_id IN filter_networks
   569  		)
   570  		OR (
   571  			COALESCE(multi_transactions.from_network_id, 0) = 0
   572  			AND COALESCE(multi_transactions.to_network_id, 0) = 0
   573  			AND (
   574  				EXISTS (
   575  					SELECT
   576  						1
   577  					FROM
   578  						tr_network_ids
   579  					WHERE
   580  						multi_transactions.id = tr_network_ids.multi_transaction_id
   581  				)
   582  				OR EXISTS (
   583  					SELECT
   584  						1
   585  					FROM
   586  						pending_network_ids
   587  					WHERE
   588  						multi_transactions.id = pending_network_ids.multi_transaction_id
   589  				)
   590  			)
   591  		)
   592  	)
   593  ORDER BY
   594  	timestamp DESC
   595  LIMIT
   596  	? OFFSET ?