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 ?