feat: Add activity filtering by contract deploy and minting (#4009)
This commit is contained in:
parent
8ba9f38ce7
commit
e77fc59f5e
|
@ -420,6 +420,7 @@ func getActivityEntries(ctx context.Context, deps FilterDependencies, addresses
|
||||||
rows, err := deps.db.QueryContext(ctx, queryString,
|
rows, err := deps.db.QueryContext(ctx, queryString,
|
||||||
startFilterDisabled, filter.Period.StartTimestamp, endFilterDisabled, filter.Period.EndTimestamp,
|
startFilterDisabled, filter.Period.StartTimestamp, endFilterDisabled, filter.Period.EndTimestamp,
|
||||||
filterActivityTypeAll, sliceContains(filter.Types, SendAT), sliceContains(filter.Types, ReceiveAT),
|
filterActivityTypeAll, sliceContains(filter.Types, SendAT), sliceContains(filter.Types, ReceiveAT),
|
||||||
|
sliceContains(filter.Types, ContractDeploymentAT), sliceContains(filter.Types, MintAT),
|
||||||
fromTrType, toTrType,
|
fromTrType, toTrType,
|
||||||
filterAllAddresses, filterAllToAddresses,
|
filterAllAddresses, filterAllToAddresses,
|
||||||
includeAllStatuses, filterStatusCompleted, filterStatusFailed, filterStatusFinalized, filterStatusPending,
|
includeAllStatuses, filterStatusCompleted, filterStatusFailed, filterStatusFinalized, filterStatusPending,
|
||||||
|
@ -519,7 +520,7 @@ func getActivityEntries(ctx context.Context, deps FilterDependencies, addresses
|
||||||
)
|
)
|
||||||
|
|
||||||
// Extract tokens
|
// Extract tokens
|
||||||
if activityType == SendAT {
|
if activityType == SendAT || activityType == ContractDeploymentAT {
|
||||||
entry.tokenOut = involvedToken
|
entry.tokenOut = involvedToken
|
||||||
outChainID = new(common.ChainID)
|
outChainID = new(common.ChainID)
|
||||||
*outChainID = common.ChainID(chainID.Int64)
|
*outChainID = common.ChainID(chainID.Int64)
|
||||||
|
@ -624,10 +625,14 @@ func getTrInAndOutAmounts(activityType Type, trAmount sql.NullString) (inAmount
|
||||||
amount, ok := new(big.Int).SetString(trAmount.String, 16)
|
amount, ok := new(big.Int).SetString(trAmount.String, 16)
|
||||||
if ok {
|
if ok {
|
||||||
switch activityType {
|
switch activityType {
|
||||||
|
case ContractDeploymentAT:
|
||||||
|
fallthrough
|
||||||
case SendAT:
|
case SendAT:
|
||||||
inAmount = (*hexutil.Big)(big.NewInt(0))
|
inAmount = (*hexutil.Big)(big.NewInt(0))
|
||||||
outAmount = (*hexutil.Big)(amount)
|
outAmount = (*hexutil.Big)(amount)
|
||||||
return
|
return
|
||||||
|
case MintAT:
|
||||||
|
fallthrough
|
||||||
case ReceiveAT:
|
case ReceiveAT:
|
||||||
inAmount = (*hexutil.Big)(amount)
|
inAmount = (*hexutil.Big)(amount)
|
||||||
outAmount = (*hexutil.Big)(big.NewInt(0))
|
outAmount = (*hexutil.Big)(big.NewInt(0))
|
||||||
|
|
|
@ -620,7 +620,7 @@ func TestGetActivityEntriesCheckOffsetAndLimit(t *testing.T) {
|
||||||
}, entries[0])
|
}, entries[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
func countTypes(entries []Entry) (sendCount, receiveCount, swapCount, buyCount, bridgeCount int) {
|
func countTypes(entries []Entry) (sendCount, receiveCount, contractCount, mintCount, swapCount, buyCount, bridgeCount int) {
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
switch entry.activityType {
|
switch entry.activityType {
|
||||||
case SendAT:
|
case SendAT:
|
||||||
|
@ -633,6 +633,10 @@ func countTypes(entries []Entry) (sendCount, receiveCount, swapCount, buyCount,
|
||||||
buyCount++
|
buyCount++
|
||||||
case BridgeAT:
|
case BridgeAT:
|
||||||
bridgeCount++
|
bridgeCount++
|
||||||
|
case ContractDeploymentAT:
|
||||||
|
contractCount++
|
||||||
|
case MintAT:
|
||||||
|
mintCount++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -662,15 +666,29 @@ func TestGetActivityEntriesFilterByType(t *testing.T) {
|
||||||
transfer.InsertTestTransfer(t, deps.db, trs[i].To, &trs[i])
|
transfer.InsertTestTransfer(t, deps.db, trs[i].To, &trs[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trsSpecial, _, _ := transfer.GenerateTestTransfers(t, deps.db, 100, 2)
|
||||||
|
// Insert MintAT
|
||||||
|
trsSpecial[0].From = eth.HexToAddress("0x0")
|
||||||
|
transfer.InsertTestTransferWithOptions(t, deps.db, trsSpecial[0].To, &trsSpecial[0], &transfer.TestTransferOptions{
|
||||||
|
TokenAddress: eth.HexToAddress("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"),
|
||||||
|
TokenID: (big.NewInt(1318)),
|
||||||
|
})
|
||||||
|
|
||||||
|
// Insert ContractDeploymentAt
|
||||||
|
trsSpecial[1].To = eth.HexToAddress("0x0")
|
||||||
|
transfer.InsertTestTransferWithOptions(t, deps.db, trsSpecial[1].From, &trsSpecial[1], &transfer.TestTransferOptions{
|
||||||
|
NullifyAddresses: []eth.Address{trsSpecial[1].To},
|
||||||
|
})
|
||||||
|
|
||||||
// Test filtering out without address involved
|
// Test filtering out without address involved
|
||||||
var filter Filter
|
var filter Filter
|
||||||
|
|
||||||
filter.Types = allActivityTypesFilter()
|
filter.Types = allActivityTypesFilter()
|
||||||
// Set tr1 to Receive and pendingTr to Send; rest of two MT remain default Send
|
// Set tr1 to Receive and pendingTr to Send; rest of two MT remain default Send
|
||||||
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}
|
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, trsSpecial[0].To, trsSpecial[1].From}
|
||||||
entries, err := getActivityEntries(context.Background(), deps, addresses, []common.ChainID{}, filter, 0, 15)
|
entries, err := getActivityEntries(context.Background(), deps, addresses, []common.ChainID{}, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 9, len(entries))
|
require.Equal(t, 11, len(entries))
|
||||||
|
|
||||||
filter.Types = []Type{SendAT, SwapAT}
|
filter.Types = []Type{SendAT, SwapAT}
|
||||||
entries, err = getActivityEntries(context.Background(), deps, addresses, []common.ChainID{}, filter, 0, 15)
|
entries, err = getActivityEntries(context.Background(), deps, addresses, []common.ChainID{}, filter, 0, 15)
|
||||||
|
@ -678,10 +696,12 @@ func TestGetActivityEntriesFilterByType(t *testing.T) {
|
||||||
// 3 from td Send + 2 trs MT Send + 1 (swap)
|
// 3 from td Send + 2 trs MT Send + 1 (swap)
|
||||||
require.Equal(t, 6, len(entries))
|
require.Equal(t, 6, len(entries))
|
||||||
|
|
||||||
sendCount, receiveCount, swapCount, _, bridgeCount := countTypes(entries)
|
sendCount, receiveCount, contractCount, mintCount, swapCount, _, bridgeCount := countTypes(entries)
|
||||||
|
|
||||||
require.Equal(t, 5, sendCount)
|
require.Equal(t, 5, sendCount)
|
||||||
require.Equal(t, 0, receiveCount)
|
require.Equal(t, 0, receiveCount)
|
||||||
|
require.Equal(t, 0, contractCount)
|
||||||
|
require.Equal(t, 0, mintCount)
|
||||||
require.Equal(t, 1, swapCount)
|
require.Equal(t, 1, swapCount)
|
||||||
require.Equal(t, 0, bridgeCount)
|
require.Equal(t, 0, bridgeCount)
|
||||||
|
|
||||||
|
@ -690,11 +710,39 @@ func TestGetActivityEntriesFilterByType(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 3, len(entries))
|
require.Equal(t, 3, len(entries))
|
||||||
|
|
||||||
sendCount, receiveCount, swapCount, _, bridgeCount = countTypes(entries)
|
sendCount, receiveCount, contractCount, mintCount, swapCount, _, bridgeCount = countTypes(entries)
|
||||||
require.Equal(t, 0, sendCount)
|
require.Equal(t, 0, sendCount)
|
||||||
require.Equal(t, 1, receiveCount)
|
require.Equal(t, 1, receiveCount)
|
||||||
|
require.Equal(t, 0, contractCount)
|
||||||
|
require.Equal(t, 0, mintCount)
|
||||||
require.Equal(t, 0, swapCount)
|
require.Equal(t, 0, swapCount)
|
||||||
require.Equal(t, 2, bridgeCount)
|
require.Equal(t, 2, bridgeCount)
|
||||||
|
|
||||||
|
filter.Types = []Type{MintAT}
|
||||||
|
entries, err = getActivityEntries(context.Background(), deps, addresses, []common.ChainID{}, filter, 0, 15)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 1, len(entries))
|
||||||
|
|
||||||
|
sendCount, receiveCount, contractCount, mintCount, swapCount, _, bridgeCount = countTypes(entries)
|
||||||
|
require.Equal(t, 0, sendCount)
|
||||||
|
require.Equal(t, 0, receiveCount)
|
||||||
|
require.Equal(t, 0, contractCount)
|
||||||
|
require.Equal(t, 1, mintCount)
|
||||||
|
require.Equal(t, 0, swapCount)
|
||||||
|
require.Equal(t, 0, bridgeCount)
|
||||||
|
|
||||||
|
filter.Types = []Type{ContractDeploymentAT}
|
||||||
|
entries, err = getActivityEntries(context.Background(), deps, addresses, []common.ChainID{}, filter, 0, 15)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 1, len(entries))
|
||||||
|
|
||||||
|
sendCount, receiveCount, contractCount, mintCount, swapCount, _, bridgeCount = countTypes(entries)
|
||||||
|
require.Equal(t, 0, sendCount)
|
||||||
|
require.Equal(t, 0, receiveCount)
|
||||||
|
require.Equal(t, 1, contractCount)
|
||||||
|
require.Equal(t, 0, mintCount)
|
||||||
|
require.Equal(t, 0, swapCount)
|
||||||
|
require.Equal(t, 0, bridgeCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetActivityEntriesFilterByAddresses(t *testing.T) {
|
func TestGetActivityEntriesFilterByAddresses(t *testing.T) {
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
--
|
--
|
||||||
-- 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
|
-- 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
|
||||||
--
|
--
|
||||||
|
-- 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 perforamnce.
|
||||||
|
--
|
||||||
-- Token filtering has two parts
|
-- Token filtering has two parts
|
||||||
-- 1. Filtering by symbol (multi_transactions and pending_transactions tables) where the chain ID is ignored, basically the filter_networks will account for that
|
-- 1. Filtering by symbol (multi_transactions and pending_transactions tables) where the chain ID is ignored, basically the filter_networks will account for that
|
||||||
-- 2. Filtering by token identity (chain and address for transfers table) where the symbol is ignored and all the token identities must be provided
|
-- 2. Filtering by token identity (chain and address for transfers table) where the symbol is ignored and all the token identities must be provided
|
||||||
|
@ -23,6 +25,8 @@ WITH filter_conditions AS (
|
||||||
? AS filterActivityTypeAll,
|
? AS filterActivityTypeAll,
|
||||||
? AS filterActivityTypeSend,
|
? AS filterActivityTypeSend,
|
||||||
? AS filterActivityTypeReceive,
|
? AS filterActivityTypeReceive,
|
||||||
|
? AS filterActivityTypeContractDeployment,
|
||||||
|
? AS filterActivityTypeMint,
|
||||||
? AS fromTrType,
|
? AS fromTrType,
|
||||||
? AS toTrType,
|
? AS toTrType,
|
||||||
? AS filterAllAddresses,
|
? AS filterAllAddresses,
|
||||||
|
@ -37,7 +41,8 @@ WITH filter_conditions AS (
|
||||||
? AS statusPending,
|
? AS statusPending,
|
||||||
? AS includeAllTokenTypeAssets,
|
? AS includeAllTokenTypeAssets,
|
||||||
? AS includeAllNetworks,
|
? AS includeAllNetworks,
|
||||||
? AS pendingStatus
|
? AS pendingStatus,
|
||||||
|
"0000000000000000000000000000000000000000" AS zeroAddress
|
||||||
),
|
),
|
||||||
filter_addresses(address) AS (
|
filter_addresses(address) AS (
|
||||||
SELECT
|
SELECT
|
||||||
|
@ -195,15 +200,16 @@ WHERE
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
AND (
|
AND (
|
||||||
|
-- Check description at the top of the file why code below is duplicated
|
||||||
filterActivityTypeAll
|
filterActivityTypeAll
|
||||||
OR (
|
OR (
|
||||||
filterActivityTypeSend
|
filterActivityTypeSend
|
||||||
AND (
|
AND (
|
||||||
filterAllAddresses
|
filterAllAddresses
|
||||||
OR (
|
OR (HEX(transfers.tx_from_address) IN filter_addresses)
|
||||||
HEX(transfers.tx_from_address) IN filter_addresses
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
AND NOT (tr_type = fromTrType and transfers.tx_to_address IS NULL AND transfers.type = "eth"
|
||||||
|
AND transfers.contract_address IS NOT NULL AND HEX(transfers.contract_address) != zeroAddress)
|
||||||
)
|
)
|
||||||
OR (
|
OR (
|
||||||
filterActivityTypeReceive
|
filterActivityTypeReceive
|
||||||
|
@ -211,6 +217,28 @@ WHERE
|
||||||
filterAllAddresses
|
filterAllAddresses
|
||||||
OR (HEX(transfers.tx_to_address) IN filter_addresses)
|
OR (HEX(transfers.tx_to_address) IN filter_addresses)
|
||||||
)
|
)
|
||||||
|
AND NOT (tr_type = toTrType AND transfers.type = "erc721" AND (
|
||||||
|
transfers.tx_from_address IS NULL
|
||||||
|
OR HEX(transfers.tx_from_address) = zeroAddress))
|
||||||
|
)
|
||||||
|
OR (
|
||||||
|
filterActivityTypeContractDeployment
|
||||||
|
AND tr_type = fromTrType AND transfers.tx_to_address IS NULL AND transfers.type = "eth"
|
||||||
|
AND transfers.contract_address IS NOT NULL AND HEX(transfers.contract_address) != zeroAddress
|
||||||
|
AND (
|
||||||
|
filterAllAddresses
|
||||||
|
OR (HEX(transfers.address) IN filter_addresses)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
OR (
|
||||||
|
filterActivityTypeMint
|
||||||
|
AND tr_type = toTrType AND transfers.type = "erc721" AND (
|
||||||
|
transfers.tx_from_address IS NULL
|
||||||
|
OR HEX(transfers.tx_from_address) = zeroAddress
|
||||||
|
) AND (
|
||||||
|
filterAllAddresses
|
||||||
|
OR (HEX(transfers.address) IN filter_addresses)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
AND (
|
AND (
|
||||||
|
|
|
@ -380,6 +380,9 @@ func isMetadataEmpty(asset thirdparty.CollectibleData) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Manager) fetchTokenURI(id thirdparty.CollectibleUniqueID) (string, error) {
|
func (o *Manager) fetchTokenURI(id thirdparty.CollectibleUniqueID) (string, error) {
|
||||||
|
if id.TokenID == nil {
|
||||||
|
return "", errors.New("empty token ID")
|
||||||
|
}
|
||||||
backend, err := o.rpcClient.EthClient(uint64(id.ContractID.ChainID))
|
backend, err := o.rpcClient.EthClient(uint64(id.ContractID.ChainID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
|
|
@ -242,7 +242,7 @@ func InsertTestTransferWithOptions(tb testing.TB, db *sql.DB, address eth_common
|
||||||
|
|
||||||
block := blockDBFields{
|
block := blockDBFields{
|
||||||
chainID: uint64(tr.ChainID),
|
chainID: uint64(tr.ChainID),
|
||||||
account: tr.To,
|
account: address,
|
||||||
blockNumber: big.NewInt(tr.BlkNumber),
|
blockNumber: big.NewInt(tr.BlkNumber),
|
||||||
blockHash: blkHash,
|
blockHash: blkHash,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue