diff --git a/src/app/modules/shared_models/collectibles_entry.nim b/src/app/modules/shared_models/collectibles_entry.nim index ff60b68e79..c8818178f5 100644 --- a/src/app/modules/shared_models/collectibles_entry.nim +++ b/src/app/modules/shared_models/collectibles_entry.nim @@ -5,6 +5,8 @@ import backend/collectibles as backend import collectible_trait_model import ../../../app_service/service/community_tokens/dto/community_token +const invalidTimestamp* = high(int) + # Additional data needed to build an Entry, which is # not included in the backend data and needs to be # fetched from a different source. @@ -91,6 +93,12 @@ QtObject: proc getCommunityData(self: CollectiblesEntry): backend.CommunityData = return self.data.communityData.get() + proc hasOwnership(self: CollectiblesEntry): bool = + return self.data != nil and isSome(self.data.ownership) + + proc getOwnership(self: CollectiblesEntry): seq[backend.AccountBalance] = + return self.data.ownership.get() + proc getChainID*(self: CollectiblesEntry): int {.slot.} = return self.id.contractID.chainID @@ -233,6 +241,33 @@ QtObject: read = getTraits notify = traitsChanged + proc balanceChanged*(self: CollectiblesEntry) {.signal.} + proc getBalance*(self: CollectiblesEntry): UInt256 = + var balance: UInt256 = stint.u256(0) + if self.hasOwnership(): + for item in self.getOwnership(): + balance += item.balance + return balance + proc getBalanceAsString*(self: CollectiblesEntry): string {.slot.} = + return $self.getBalance() + + QtProperty[string] balance: + read = getBalanceAsString + notify = balanceChanged + + proc lastTxTimestampChanged*(self: CollectiblesEntry) {.signal.} + proc getLastTxTimestamp*(self: CollectiblesEntry): int = + var lastTxTimestamp = -1 + if self.hasOwnership(): + for item in self.getOwnership(): + lastTxTimestamp = max(lastTxTimestamp, item.txTimestamp) + if lastTxTimestamp < 0: + lastTxTimestamp = invalidTimestamp + return lastTxTimestamp + + QtProperty[int] lastTxTimestamp: + read = getLastTxTimestamp + notify = lastTxTimestampChanged proc communityIdChanged*(self: CollectiblesEntry) {.signal.} proc getCommunityID*(self: CollectiblesEntry): string {.slot.} = @@ -320,6 +355,8 @@ QtObject: self.collectionNameChanged() self.collectionImageUrlChanged() self.traitsChanged() + self.balanceChanged() + self.lastTxTimestampChanged() self.communityIdChanged() self.communityNameChanged() self.communityColorChanged() diff --git a/src/app/modules/shared_models/collectibles_model.nim b/src/app/modules/shared_models/collectibles_model.nim index 0bfdd45afa..643778d236 100644 --- a/src/app/modules/shared_models/collectibles_model.nim +++ b/src/app/modules/shared_models/collectibles_model.nim @@ -23,6 +23,8 @@ type CollectionName CollectionSlug IsLoading + Balance + LastTxTimestamp # Community-related roles CommunityId CommunityName @@ -160,6 +162,8 @@ QtObject: CollectibleRole.CollectionName.int:"collectionName", CollectibleRole.CollectionSlug.int:"collectionSlug", CollectibleRole.IsLoading.int:"isLoading", + CollectibleRole.Balance.int:"balance", + CollectibleRole.LastTxTimestamp.int:"lastTxTimestamp", CollectibleRole.CommunityId.int:"communityId", CollectibleRole.CommunityName.int:"communityName", CollectibleRole.CommunityColor.int:"communityColor", @@ -204,6 +208,10 @@ QtObject: result = newQVariant(item.getCollectionSlug()) of CollectibleRole.IsLoading: result = newQVariant(false) + of CollectibleRole.Balance: + result = newQVariant(item.getBalanceAsString()) + of CollectibleRole.LastTxTimestamp: + result = newQVariant(item.getLastTxTimestamp()) of CollectibleRole.CommunityId: result = newQVariant(item.getCommunityId()) of CollectibleRole.CommunityName: @@ -239,6 +247,8 @@ QtObject: of "collectionName": result = item.getCollectionName() of "collectionSlug": result = item.getCollectionSlug() of "isLoading": result = $false + of "balance": result = item.getBalanceAsString() + of "lastTxTimestamp": result = $item.getLastTxTimestamp() of "communityId": result = item.getCommunityID() of "communityName": result = item.getCommunityName() of "communityColor": result = item.getCommunityColor() diff --git a/src/app/modules/shared_modules/collectibles/controller.nim b/src/app/modules/shared_modules/collectibles/controller.nim index c894c6a5b3..54cbd1c7b8 100644 --- a/src/app/modules/shared_modules/collectibles/controller.nim +++ b/src/app/modules/shared_modules/collectibles/controller.nim @@ -85,7 +85,7 @@ QtObject: for chainID in self.chainIds: self.ownershipStatus[address][chainID] = OwnershipStatus( state: OwnershipStateUpdating, - timestamp: invalidTimestamp + timestamp: backend_collectibles.invalidTimestamp ) self.model.setIsUpdating(true) @@ -141,7 +141,7 @@ QtObject: error "error fetching collectibles entries: ", res.errorCode self.model.setIsError(true) return - + try: let items = res.collectibles.map(header => (block: let extradata = self.getExtraData(header.id.contractID.chainID) @@ -185,14 +185,16 @@ QtObject: self.setOwnershipState(address, chainID, OwnershipStateUpdating) ) - self.eventsHandler.onCollectiblesOwnershipUpdatePartial(proc (address: string, chainID: int) = + self.eventsHandler.onCollectiblesOwnershipUpdatePartial(proc (address: string, chainID: int, changes: backend_collectibles.OwnershipUpdateMessage) = self.setOwnershipState(address, chainID, OwnershipStateUpdating) - self.resetModel() + if changes.hasChanges(): + self.resetModel() ) - self.eventsHandler.onCollectiblesOwnershipUpdateFinished(proc (address: string, chainID: int) = + self.eventsHandler.onCollectiblesOwnershipUpdateFinished(proc (address: string, chainID: int, changes: backend_collectibles.OwnershipUpdateMessage) = self.setOwnershipState(address, chainID, OwnershipStateIdle) - self.resetModel() + if changes.hasChanges(): + self.resetModel() ) self.eventsHandler.onCollectiblesOwnershipUpdateFinishedWithError(proc (address: string, chainID: int) = diff --git a/src/app/modules/shared_modules/collectibles/events_handler.nim b/src/app/modules/shared_modules/collectibles/events_handler.nim index 05d5fec3d1..09c32ea90d 100644 --- a/src/app/modules/shared_modules/collectibles/events_handler.nim +++ b/src/app/modules/shared_modules/collectibles/events_handler.nim @@ -9,6 +9,7 @@ import backend/collectibles as backend_collectibles type EventCallbackProc = proc (eventObject: JsonNode) type WalletEventCallbackProc = proc (data: WalletSignal) type OwnershipUpdateCallbackProc = proc (address: string, chainID: int) +type OwnershipUpdateChangesCallbackProc = proc (address: string, chainID: int, changes: backend_collectibles.OwnershipUpdateMessage) # EventsHandler responsible for catching collectibles related backend events and reporting them QtObject: @@ -22,8 +23,8 @@ QtObject: subscribedChainIDs: HashSet[int] collectiblesOwnershipUpdateStartedFn: OwnershipUpdateCallbackProc - collectiblesOwnershipUpdatePartialFn: OwnershipUpdateCallbackProc - collectiblesOwnershipUpdateFinishedFn: OwnershipUpdateCallbackProc + collectiblesOwnershipUpdatePartialFn: OwnershipUpdateChangesCallbackProc + collectiblesOwnershipUpdateFinishedFn: OwnershipUpdateChangesCallbackProc collectiblesOwnershipUpdateFinishedWithErrorFn: OwnershipUpdateCallbackProc requestId: int32 @@ -43,10 +44,10 @@ QtObject: proc onCollectiblesOwnershipUpdateStarted*(self: EventsHandler, handler: OwnershipUpdateCallbackProc) = self.collectiblesOwnershipUpdateStartedFn = handler - proc onCollectiblesOwnershipUpdatePartial*(self: EventsHandler, handler: OwnershipUpdateCallbackProc) = + proc onCollectiblesOwnershipUpdatePartial*(self: EventsHandler, handler: OwnershipUpdateChangesCallbackProc) = self.collectiblesOwnershipUpdatePartialFn = handler - proc onCollectiblesOwnershipUpdateFinished*(self: EventsHandler, handler: OwnershipUpdateCallbackProc) = + proc onCollectiblesOwnershipUpdateFinished*(self: EventsHandler, handler: OwnershipUpdateChangesCallbackProc) = self.collectiblesOwnershipUpdateFinishedFn = handler proc onCollectiblesOwnershipUpdateFinishedWithError*(self: EventsHandler, handler: OwnershipUpdateCallbackProc) = @@ -82,12 +83,16 @@ QtObject: self.walletEventHandlers[backend_collectibles.eventCollectiblesOwnershipUpdatePartial] = proc (data: WalletSignal) = if self.collectiblesOwnershipUpdatePartialFn == nil or self.shouldIgnoreEvent(data): return - self.collectiblesOwnershipUpdatePartialFn(data.accounts[0], data.chainID) + let changesJson = parseJson(data.message) + let changes = fromJson(changesJson, backend_collectibles.OwnershipUpdateMessage) + self.collectiblesOwnershipUpdatePartialFn(data.accounts[0], data.chainID, changes) self.walletEventHandlers[backend_collectibles.eventCollectiblesOwnershipUpdateFinished] = proc (data: WalletSignal) = if self.collectiblesOwnershipUpdateFinishedFn == nil or self.shouldIgnoreEvent(data): return - self.collectiblesOwnershipUpdateFinishedFn(data.accounts[0], data.chainID) + let changesJson = parseJson(data.message) + let changes = fromJson(changesJson, backend_collectibles.OwnershipUpdateMessage) + self.collectiblesOwnershipUpdateFinishedFn(data.accounts[0], data.chainID, changes) self.walletEventHandlers[backend_collectibles.eventCollectiblesOwnershipUpdateFinishedWithError] = proc (data: WalletSignal) = if self.collectiblesOwnershipUpdateFinishedWithErrorFn == nil or self.shouldIgnoreEvent(data): diff --git a/src/backend/collectibles.nim b/src/backend/collectibles.nim index 5784710088..3a6a796e5e 100644 --- a/src/backend/collectibles.nim +++ b/src/backend/collectibles.nim @@ -46,6 +46,12 @@ type state*: OwnershipState timestamp*: int + # Mirrors services/wallet/collectibles/service.go OwnershipUpdateMessage + OwnershipUpdateMessage* = ref object + added*: seq[CollectibleUniqueID] + updated*: seq[CollectibleUniqueID] + removed*: seq[CollectibleUniqueID] + # Mirrors services/wallet/collectibles/service.go GetOwnedCollectiblesResponse GetOwnedCollectiblesResponse* = object collectibles*: seq[Collectible] @@ -95,6 +101,35 @@ proc fromJson*(t: JsonNode, T: typedesc[OwnershipStatus]): OwnershipStatus {.inl timestamp: t{"timestamp"}.getInt ) +# OwnershipUpdateMessage +proc `$`*(self: OwnershipUpdateMessage): string = + return fmt"""OwnershipUpdateMessage( + added:{self.added}, + updated:{self.updated}, + removed:{self.removed} + """ + +proc hasChanges*(self: OwnershipUpdateMessage): bool {.inline.} = + return self.added.len != 0 or self.updated.len != 0 or self.removed.len != 0 + +proc fromJson*(t: JsonNode, T: typedesc[OwnershipUpdateMessage]): OwnershipUpdateMessage {.inline.} = + var added: seq[CollectibleUniqueID] + var updated: seq[CollectibleUniqueID] + var removed: seq[CollectibleUniqueID] + + for item in t["added"].getElems(): + added.add(fromJson(item, CollectibleUniqueID)) + for item in t["updated"].getElems(): + updated.add(fromJson(item, CollectibleUniqueID)) + for item in t["removed"].getElems(): + removed.add(fromJson(item, CollectibleUniqueID)) + + return OwnershipUpdateMessage( + added: added, + updated: updated, + removed: removed + ) + # CollectibleFilter proc newCollectibleFilterAllCommunityIds*(): seq[string] {.inline.} = return @[] diff --git a/src/backend/collectibles_types.nim b/src/backend/collectibles_types.nim index 2576627af4..118662d0be 100644 --- a/src/backend/collectibles_types.nim +++ b/src/backend/collectibles_types.nim @@ -45,12 +45,19 @@ type privilegesLevel*: PrivilegesLevel imageUrl*: Option[string] + # Mirrors services/wallet/thirdparty/collectible_types.go CollectibleOwner + AccountBalance* = ref object + address*: string + balance*: UInt256 + txTimestamp*: int + Collectible* = ref object of RootObj dataType*: CollectibleDataType id* : CollectibleUniqueID collectibleData*: Option[CollectibleData] collectionData*: Option[CollectionData] communityData*: Option[CommunityData] + ownership*: Option[seq[AccountBalance]] # Mirrors services/wallet/thirdparty/collectible_types.go TokenBalance CollectibleBalance* = ref object @@ -243,6 +250,24 @@ proc fromJson*(t: JsonNode, T: typedesc[ref CommunityData]): ref CommunityData { result = new(CommunityData) result[] = fromJson(t, CommunityData) +# AccountBalance +proc `$`*(self: AccountBalance): string = + return fmt"""AccountBalance( + address:{self.address}, + balance:{self.balance}, + txTimestamp:{self.txTimestamp} + )""" + +proc getAccountBalances(jsonAsset: JsonNode): seq[AccountBalance] = + var balanceList: seq[AccountBalance] = @[] + for item in jsonAsset.getElems(): + balanceList.add(AccountBalance( + address: item{"address"}.getStr, + balance: stint.parse(item{"balance"}.getStr, Uint256), + txTimestamp: item{"txTimestamp"}.getInt + )) + return balanceList + # Collectible proc `$`*(self: Collectible): string = return fmt"""Collectible( @@ -250,7 +275,8 @@ proc `$`*(self: Collectible): string = id:{self.id}, collectibleData:{self.collectibleData}, collectionData:{self.collectionData}, - communityData:{self.communityData} + communityData:{self.communityData}, + ownership:{self.ownership} )""" proc fromJson*(t: JsonNode, T: typedesc[Collectible]): Collectible {.inline.} = @@ -272,6 +298,11 @@ proc fromJson*(t: JsonNode, T: typedesc[Collectible]): Collectible {.inline.} = result.communityData = some(fromJson(communityDataNode, CommunityData)) else: result.communityData = none(CommunityData) + let ownershipNode = t{"ownership"} + if ownershipNode != nil and ownershipNode.kind != JNull: + result.ownership = some(getAccountBalances(ownershipNode)) + else: + result.ownership = none(seq[AccountBalance]) proc toIds(self: seq[Collectible]): seq[CollectibleUniqueID] = result = @[] diff --git a/vendor/status-go b/vendor/status-go index 70b2cab096..ee6621b066 160000 --- a/vendor/status-go +++ b/vendor/status-go @@ -1 +1 @@ -Subproject commit 70b2cab096af313ae6017d4ca9554574d440eb7a +Subproject commit ee6621b06610f0a3223cf875cc969abfa25750c9