From 277dda7533c8602f2fe0a4c72615be05ff9df118 Mon Sep 17 00:00:00 2001 From: Cuteivist Date: Tue, 9 Apr 2024 16:16:03 +0200 Subject: [PATCH] feat(wallet): Disable send for soulbound collectibles (#14327) --- src/app/modules/shared_models/collectibles_entry.nim | 10 ++++++++++ src/app/modules/shared_models/collectibles_model.nim | 4 ++++ src/backend/collectibles_types.nim | 11 +++++++++-- ui/app/AppLayouts/Wallet/WalletLayout.qml | 10 +++++++++- ui/app/AppLayouts/Wallet/panels/WalletFooter.qml | 10 ++++++++-- 5 files changed, 40 insertions(+), 5 deletions(-) diff --git a/src/app/modules/shared_models/collectibles_entry.nim b/src/app/modules/shared_models/collectibles_entry.nim index d60d7ed406..17fc015e9a 100644 --- a/src/app/modules/shared_models/collectibles_entry.nim +++ b/src/app/modules/shared_models/collectibles_entry.nim @@ -320,6 +320,16 @@ QtObject: read = getTokenType notify = tokenTypeChanged + proc soulboundChanged*(self: CollectiblesEntry) {.signal.} + proc getSoulbound*(self: CollectiblesEntry): bool {.slot.} = + if not self.hasCollectibleData() or isNone(self.getCollectibleData().soulbound): + return false + return self.getCollectibleData().soulbound.get() + + QtProperty[bool] soulbound: + read = getSoulbound + notify = soulboundChanged + proc updateDataIfSameID*(self: CollectiblesEntry, update: backend.Collectible): bool = if self.id != update.id: return false diff --git a/src/app/modules/shared_models/collectibles_model.nim b/src/app/modules/shared_models/collectibles_model.nim index 831c1d09eb..6139f0a491 100644 --- a/src/app/modules/shared_models/collectibles_model.nim +++ b/src/app/modules/shared_models/collectibles_model.nim @@ -27,6 +27,7 @@ type CommunityPrivilegesLevel CommunityImage TokenType + Soulbound QtObject: type @@ -149,6 +150,7 @@ QtObject: CollectibleRole.CommunityPrivilegesLevel.int:"communityPrivilegesLevel", CollectibleRole.CommunityImage.int:"communityImage", CollectibleRole.TokenType.int:"tokenType", + CollectibleRole.Soulbound.int:"soulbound" }.toTable method data(self: Model, index: QModelIndex, role: int): QVariant = @@ -203,6 +205,8 @@ QtObject: result = newQVariant(item.getCommunityImage()) of CollectibleRole.TokenType: result = newQVariant(item.getTokenType()) + of CollectibleRole.Soulbound: + result = newQVariant(item.getSoulbound()) proc rowData(self: Model, index: int, column: string): string {.slot.} = if (index >= self.items.len): diff --git a/src/backend/collectibles_types.nim b/src/backend/collectibles_types.nim index 0138edf4cc..ebe99d6603 100644 --- a/src/backend/collectibles_types.nim +++ b/src/backend/collectibles_types.nim @@ -41,6 +41,7 @@ type animationMediaType*: Option[string] traits*: Option[seq[CollectibleTrait]] backgroundColor*: Option[string] + soulbound*: Option[bool] CollectionData* = ref object of RootObj name*: string @@ -229,7 +230,8 @@ proc `$`*(self: CollectibleData): string = animationUrl:{self.animationUrl}, animationMediaType:{self.animationMediaType}, traits:{self.traits}, - backgroundColor:{self.backgroundColor} + backgroundColor:{self.backgroundColor}, + soulbound:{self.soulbound} )""" proc getCollectibleTraits*(t: JsonNode): Option[seq[CollectibleTrait]] = @@ -256,7 +258,7 @@ proc fromJson*(t: JsonNode, T: typedesc[CollectibleData]): CollectibleData = else: result.imageUrl = none(string) let animationUrlNode = t{"animation_url"} - if animationUrlNode != nil and animationUrlNode.kind != JNull: + if animationUrlNode != nil and animationUrlNode.kind != JBool: result.animationUrl = some(animationUrlNode.getStr()) else: result.animationUrl = none(string) @@ -265,6 +267,11 @@ proc fromJson*(t: JsonNode, T: typedesc[CollectibleData]): CollectibleData = result.animationMediaType = some(animationMediaTypeNode.getStr()) else: result.animationMediaType = none(string) + let soulboundNode = t{"soulbound"} + if soulboundNode != nil and soulboundNode.kind != JNull: + result.soulbound = some(soulboundNode.getBool()) + else: + result.soulbound = none(bool) result.traits = getCollectibleTraits(t{"traits"}) let backgroundColorNode = t{"background_color"} if backgroundColorNode != nil and backgroundColorNode.kind != JNull: diff --git a/ui/app/AppLayouts/Wallet/WalletLayout.qml b/ui/app/AppLayouts/Wallet/WalletLayout.qml index 4e3eb15ad2..c68d3ce271 100644 --- a/ui/app/AppLayouts/Wallet/WalletLayout.qml +++ b/ui/app/AppLayouts/Wallet/WalletLayout.qml @@ -262,7 +262,15 @@ Item { walletStore: RootStore networkConnectionStore: root.networkConnectionStore isCommunityOwnershipTransfer: footer.isHoldingSelected && footer.isOwnerCommunityCollectible - communityName: !!walletStore.currentViewedCollectible ? walletStore.currentViewedCollectible.communityName : "" + communityName: { + if (!walletStore.currentViewedCollectible) + return "" + const name = walletStore.currentViewedCollectible.communityName + const id = walletStore.currentViewedCollectible.communityId + if (name === id) + return Utils.compactAddress(id, 4) + return name + } onLaunchShareAddressModal: Global.openShowQRPopup({ switchingAccounsEnabled: true, changingPreferredChainsEnabled: true, diff --git a/ui/app/AppLayouts/Wallet/panels/WalletFooter.qml b/ui/app/AppLayouts/Wallet/panels/WalletFooter.qml index 7437e325d4..fbecb28796 100644 --- a/ui/app/AppLayouts/Wallet/panels/WalletFooter.qml +++ b/ui/app/AppLayouts/Wallet/panels/WalletFooter.qml @@ -28,6 +28,12 @@ Rectangle { color: Theme.palette.statusAppLayout.rightPanelBackgroundColor + QtObject { + id: d + readonly property bool isCollectibleViewed: !!walletStore.currentViewedCollectible + readonly property bool isCollectibleSoulbound: d.isCollectibleViewed && walletStore.currentViewedCollectible.soulbound + } + StatusModalDivider { anchors.top: parent.top width: parent.width @@ -42,9 +48,9 @@ Rectangle { objectName: "walletFooterSendButton" icon.name: "send" text: root.isCommunityOwnershipTransfer ? qsTr("Send Owner token to transfer %1 Community ownership").arg(root.communityName) : qsTr("Send") - interactive: networkConnectionStore.sendBuyBridgeEnabled + interactive: !d.isCollectibleSoulbound && networkConnectionStore.sendBuyBridgeEnabled onClicked: root.launchSendModal() - tooltip.text: networkConnectionStore.sendBuyBridgeToolTipText + tooltip.text: d.isCollectibleSoulbound ? qsTr("Soulbound collectibles cannot be sent to another wallet") : networkConnectionStore.sendBuyBridgeToolTipText visible: !walletStore.overview.isWatchOnlyAccount && walletStore.overview.canSend }