feat(wallet) handle multi-transaction update events for activity filter

Bump status-go to include multi-transaction update events

Throttle down "update transactions" button to once every two seconds

Closes #11233
This commit is contained in:
Stefan 2023-07-07 15:25:28 +01:00 committed by Stefan Dunca
parent 4a3e8ca1b2
commit 42f2546e4a
4 changed files with 66 additions and 7 deletions

View File

@ -186,6 +186,7 @@ QtObject:
self.status.setIsFilterDirty(false) self.status.setIsFilterDirty(false)
self.model.resetModel(@[]) self.model.resetModel(@[])
self.eventsHandler.updateSubscribedAddresses(self.addresses) self.eventsHandler.updateSubscribedAddresses(self.addresses)
self.eventsHandler.updateSubscribedChainIDs(self.chainIds)
self.status.setNewDataAvailable(false) self.status.setNewDataAvailable(false)
let response = backend_activity.filterActivityAsync(self.addresses, seq[backend_activity.ChainId](self.chainIds), self.currentActivityFilter, 0, FETCH_BATCH_COUNT_DEFAULT) let response = backend_activity.filterActivityAsync(self.addresses, seq[backend_activity.ChainId](self.chainIds), self.currentActivityFilter, 0, FETCH_BATCH_COUNT_DEFAULT)

View File

@ -27,6 +27,7 @@ QtObject:
# Ignore events older than this relevantTimestamp # Ignore events older than this relevantTimestamp
relevantTimestamp: int relevantTimestamp: int
subscribedAddresses: HashSet[string] subscribedAddresses: HashSet[string]
subscribedChainIDs: HashSet[int]
newDataAvailableFn: proc() newDataAvailableFn: proc()
proc setup(self: EventsHandler) = proc setup(self: EventsHandler) =
@ -73,19 +74,31 @@ QtObject:
if data.at > 0 and self.relevantTimestamp > 0 and data.at < self.relevantTimestamp: if data.at > 0 and self.relevantTimestamp > 0 and data.at < self.relevantTimestamp:
return return
# Check addresses if any was reported # Check chain, if any was reported
if len(self.subscribedChainIDs) > 0 and data.chainID > 0:
var contains = false
for chainID in self.subscribedChainIDs:
if data.chainID == chainID:
contains = true
break
if not contains:
return
var contains = data.accounts.len == 0 var contains = data.accounts.len == 0
# Check addresses if any was reported
for address in data.accounts: for address in data.accounts:
if address in self.subscribedAddresses: if address in self.subscribedAddresses:
contains = true contains = true
break break
if contains: if not contains:
# TODO: throttle down the number of events to one per 1 seconds until the backend supports subscription return
self.newDataAvailableFn()
self.newDataAvailableFn()
self.walletEventHandlers[EventNewTransfers] = newDataAvailableCallback self.walletEventHandlers[EventNewTransfers] = newDataAvailableCallback
self.walletEventHandlers[EventPendingTransactionUpdate] = newDataAvailableCallback self.walletEventHandlers[EventPendingTransactionUpdate] = newDataAvailableCallback
self.walletEventHandlers[EventMTTransactionUpdate] = newDataAvailableCallback
proc newEventsHandler*(events: EventEmitter): EventsHandler = proc newEventsHandler*(events: EventEmitter): EventsHandler =
new(result, delete) new(result, delete)
@ -93,6 +106,7 @@ QtObject:
result.eventHandlers = initTable[string, EventCallbackProc]() result.eventHandlers = initTable[string, EventCallbackProc]()
result.subscribedAddresses = initHashSet[string]() result.subscribedAddresses = initHashSet[string]()
result.subscribedChainIDs = initHashSet[int]()
result.setup() result.setup()
@ -110,4 +124,9 @@ QtObject:
proc updateSubscribedAddresses*(self: EventsHandler, addresses: seq[string]) = proc updateSubscribedAddresses*(self: EventsHandler, addresses: seq[string]) =
self.subscribedAddresses.clear() self.subscribedAddresses.clear()
for address in addresses: for address in addresses:
self.subscribedAddresses.incl(address) self.subscribedAddresses.incl(address)
proc updateSubscribedChainIDs*(self: EventsHandler, chainIDs: seq[int]) =
self.subscribedChainIDs.clear()
for chainID in chainIDs:
self.subscribedChainIDs.incl(chainID)

View File

@ -39,6 +39,7 @@ const EventNonArchivalNodeDetected*: string = "non-archival-node-detected"
# Mirrors the pending transfer event from status-go, status-go/services/wallet/transfer/transaction.go # Mirrors the pending transfer event from status-go, status-go/services/wallet/transfer/transaction.go
const EventPendingTransactionUpdate*: string = "pending-transaction-update" const EventPendingTransactionUpdate*: string = "pending-transaction-update"
const EventMTTransactionUpdate*: string = "multi-transaction-update"
proc getTransactionByHash*(chainId: int, hash: string): RpcResponse[JsonNode] {.raises: [Exception].} = proc getTransactionByHash*(chainId: int, hash: string): RpcResponse[JsonNode] {.raises: [Exception].} =
core.callPrivateRPCWithChainId("eth_getTransactionByHash", chainId, %* [hash]) core.callPrivateRPCWithChainId("eth_getTransactionByHash", chainId, %* [hash])

View File

@ -50,6 +50,15 @@ ColumnLayout {
property var activityFiltersStore: WalletStores.ActivityFiltersStore{} property var activityFiltersStore: WalletStores.ActivityFiltersStore{}
readonly property int loadingSectionWidth: 56 readonly property int loadingSectionWidth: 56
readonly property int topSectionMargin: 20 readonly property int topSectionMargin: 20
property bool showRefreshButton: false
property double lastRefreshTime
readonly property int maxSecondsBetweenRefresh: 3
function refreshData() {
RootStore.resetFilter()
d.lastRefreshTime = Date.now()
d.showRefreshButton = false
}
} }
StyledText { StyledText {
@ -363,8 +372,8 @@ ColumnLayout {
text: qsTr("New transactions") text: qsTr("New transactions")
visible: RootStore.newDataAvailable visible: d.showRefreshButton
onClicked: RootStore.resetFilter() onClicked: d.refreshData()
icon.name: "arrow-up" icon.name: "arrow-up"
@ -378,4 +387,33 @@ ColumnLayout {
z: 3 z: 3
} }
} }
Connections {
target: RootStore
function onNewDataAvailableChanged() {
if (!d.lastRefreshTime || ((Date.now() - d.lastRefreshTime) > (1000 * d.maxSecondsBetweenRefresh))) {
d.showRefreshButton = RootStore.newDataAvailable
return
}
if (showRefreshButtonTimer.running) {
if (!RootStore.newDataAvailable) {
showRefreshButtonTimer.stop()
d.showRefreshButton = false
}
} else if(RootStore.newDataAvailable) {
showRefreshButtonTimer.start()
}
}
}
Timer {
id: showRefreshButtonTimer
interval: 2000
running: false
repeat: false
onTriggered: d.showRefreshButton = RootStore.newDataAvailable
}
} }