feat(@desktop/toast): Community Token received notification (#13116)

This commit is contained in:
Cuteivist 2024-01-04 13:22:12 +01:00 committed by GitHub
parent fb558edf61
commit 0536ce898d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 219 additions and 10 deletions

View File

@ -86,6 +86,9 @@ proc init*(self: Controller) =
self.events.on(SIGNAL_OWNER_TOKEN_RECEIVED) do(e: Args): self.events.on(SIGNAL_OWNER_TOKEN_RECEIVED) do(e: Args):
let args = OwnerTokenReceivedArgs(e) let args = OwnerTokenReceivedArgs(e)
self.communityTokensModule.onOwnerTokenReceived(args.communityId, args.communityName, args.chainId, args.contractAddress) self.communityTokensModule.onOwnerTokenReceived(args.communityId, args.communityName, args.chainId, args.contractAddress)
self.events.on(SIGNAL_COMMUNITY_TOKEN_RECEIVED) do(e: Args):
let args = CommunityTokenReceivedArgs(e)
self.communityTokensModule.onCommunityTokenReceived(args.name, args.image, args.communityId, args.communityName, args.communityColor, $args.balance, args.chainId, args.txHash)
self.events.on(SIGNAL_SET_SIGNER_STATUS) do(e: Args): self.events.on(SIGNAL_SET_SIGNER_STATUS) do(e: Args):
let args = SetSignerArgs(e) let args = SetSignerArgs(e)
self.communityTokensModule.onSetSignerStateChanged(args.communityId, args.chainId, args.transactionHash, args.status) self.communityTokensModule.onSetSignerStateChanged(args.communityId, args.chainId, args.transactionHash, args.status)

View File

@ -96,6 +96,9 @@ method removeCommunityToken*(self: AccessInterface, communityId: string, chainId
method onOwnerTokenReceived*(self: AccessInterface, communityId: string, communityName: string, chainId: int, contractAddress: string) {.base.} = method onOwnerTokenReceived*(self: AccessInterface, communityId: string, communityName: string, chainId: int, contractAddress: string) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method onCommunityTokenReceived*(self: AccessInterface, name: string, image: string, communityId: string, communityName: string, communityColor: string, balance: string, chainId: int, txHash: string) {.base.} =
raise newException(ValueError, "No implementation available")
method onSendOwnerTokenStateChanged*(self: AccessInterface, chainId: int, transactionHash: string, tokenName: string, status: ContractTransactionStatus) {.base.} = method onSendOwnerTokenStateChanged*(self: AccessInterface, chainId: int, transactionHash: string, tokenName: string, status: ContractTransactionStatus) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")

View File

@ -334,6 +334,9 @@ method onAirdropStateChanged*(self: Module, communityId: string, tokenName: stri
method onOwnerTokenReceived*(self: Module, communityId: string, communityName: string, chainId: int, contractAddress: string) = method onOwnerTokenReceived*(self: Module, communityId: string, communityName: string, chainId: int, contractAddress: string) =
self.view.emitOwnerTokenReceived(communityId, communityName, chainId, contractAddress) self.view.emitOwnerTokenReceived(communityId, communityName, chainId, contractAddress)
method onCommunityTokenReceived*(self: Module, name: string, image: string, communityId: string, communityName: string, communityColor: string, balance: string, chainId: int, txHash: string) =
self.view.emitCommunityTokenReceived(name, image, communityId, communityName, communityColor, balance, chainId, txHash)
method onSetSignerStateChanged*(self: Module, communityId: string, chainId: int, transactionHash: string, status: ContractTransactionStatus) = method onSetSignerStateChanged*(self: Module, communityId: string, chainId: int, transactionHash: string, status: ContractTransactionStatus) =
let communityDto = self.controller.getCommunityById(communityId) let communityDto = self.controller.getCommunityById(communityId)
let communityName = communityDto.name let communityName = communityDto.name

View File

@ -55,6 +55,7 @@ QtObject:
proc burnFeeUpdated*(self: View, ethCurrency: QVariant, fiatCurrency: QVariant, errorCode: int, responseId: string) {.signal.} proc burnFeeUpdated*(self: View, ethCurrency: QVariant, fiatCurrency: QVariant, errorCode: int, responseId: string) {.signal.}
proc setSignerFeeUpdated*(self: View, ethCurrency: QVariant, fiatCurrency: QVariant, errorCode: int, responseId: string) {.signal.} proc setSignerFeeUpdated*(self: View, ethCurrency: QVariant, fiatCurrency: QVariant, errorCode: int, responseId: string) {.signal.}
proc ownerTokenReceived*(self: View, communityId: string, communityName: string, chainId: int, contractAddress: string) {.signal.} proc ownerTokenReceived*(self: View, communityId: string, communityName: string, chainId: int, contractAddress: string) {.signal.}
proc communityTokenReceived*(self: View, name: string, image: string, communityId: string, communityName: string, communityColor: string, balance: string, chainId: int, txHash: string) {.signal.}
proc setSignerStateChanged*(self: View, communityId: string, communityName: string, status: int, url: string) {.signal.} proc setSignerStateChanged*(self: View, communityId: string, communityName: string, status: int, url: string) {.signal.}
proc ownershipNodeLost*(self: View, communityId: string, communityName: string) {.signal.} proc ownershipNodeLost*(self: View, communityId: string, communityName: string) {.signal.}
proc sendOwnerTokenStateChanged*(self: View, tokenName: string, status: int, url: string) {.signal.} proc sendOwnerTokenStateChanged*(self: View, tokenName: string, status: int, url: string) {.signal.}
@ -116,6 +117,9 @@ QtObject:
proc emitOwnerTokenReceived*(self: View, communityId: string, communityName: string, chainId: int, contractAddress: string) = proc emitOwnerTokenReceived*(self: View, communityId: string, communityName: string, chainId: int, contractAddress: string) =
self.ownerTokenReceived(communityId, communityName, chainId, contractAddress) self.ownerTokenReceived(communityId, communityName, chainId, contractAddress)
proc emitCommunityTokenReceived*(self: View, name: string, image: string, communityId: string, communityName: string, communityColor: string, balance: string, chainId: int, txHash: string) =
self.communityTokenReceived(name, image, communityId, communityName, communityColor, balance, chainId, txHash)
proc emitSetSignerStateChanged*(self: View, communityId: string, communityName: string, status: int, url: string) = proc emitSetSignerStateChanged*(self: View, communityId: string, communityName: string, status: int, url: string) =
self.setSignerStateChanged(communityId, communityName, status, url) self.setSignerStateChanged(communityId, communityName, status, url)

View File

@ -27,6 +27,7 @@ type ActivityCenterNotificationType* {.pure.}= enum
SetSignerFailed = 16 SetSignerFailed = 16
SetSignerDeclined = 17 SetSignerDeclined = 17
ShareAccounts = 18 ShareAccounts = 18
CommunityTokenReceived = 19
type ActivityCenterGroup* {.pure.}= enum type ActivityCenterGroup* {.pure.}= enum
All = 0, All = 0,
@ -164,7 +165,8 @@ proc activityCenterNotificationTypesByGroup*(group: ActivityCenterGroup) : seq[i
ActivityCenterNotificationType.SetSignerFailed.int, ActivityCenterNotificationType.SetSignerFailed.int,
ActivityCenterNotificationType.SetSignerDeclined.int, ActivityCenterNotificationType.SetSignerDeclined.int,
ActivityCenterNotificationType.OwnershipLost.int, ActivityCenterNotificationType.OwnershipLost.int,
ActivityCenterNotificationType.ShareAccounts.int ActivityCenterNotificationType.ShareAccounts.int,
ActivityCenterNotificationType.CommunityTokenReceived.int
] ]
of ActivityCenterGroup.Mentions: of ActivityCenterGroup.Mentions:
return @[ActivityCenterNotificationType.Mention.int] return @[ActivityCenterNotificationType.Mention.int]

View File

@ -169,6 +169,17 @@ type
chainId*: int chainId*: int
contractAddress*: string contractAddress*: string
type
CommunityTokenReceivedArgs* = ref object of Args
name*: string
image*: string
communityId*: string
communityName*: string
communityColor*: string
chainId*: int
balance*: int
txHash*: string
type type
FinaliseOwnershipStatusArgs* = ref object of Args FinaliseOwnershipStatusArgs* = ref object of Args
isPending*: bool isPending*: bool
@ -214,6 +225,7 @@ const SIGNAL_OWNER_TOKEN_RECEIVED* = "communityTokens-ownerTokenReceived"
const SIGNAL_SET_SIGNER_STATUS* = "communityTokens-setSignerStatus" const SIGNAL_SET_SIGNER_STATUS* = "communityTokens-setSignerStatus"
const SIGNAL_FINALISE_OWNERSHIP_STATUS* = "communityTokens-finaliseOwnershipStatus" const SIGNAL_FINALISE_OWNERSHIP_STATUS* = "communityTokens-finaliseOwnershipStatus"
const SIGNAL_OWNER_TOKEN_OWNER_ADDRESS* = "communityTokens-ownerTokenOwnerAddress" const SIGNAL_OWNER_TOKEN_OWNER_ADDRESS* = "communityTokens-ownerTokenOwnerAddress"
const SIGNAL_COMMUNITY_TOKEN_RECEIVED* = "communityTokens-communityTokenReceived"
QtObject: QtObject:
type type
@ -304,6 +316,31 @@ QtObject:
except Exception as e: except Exception as e:
error "Error registering owner token received notification", msg=e.msg error "Error registering owner token received notification", msg=e.msg
proc processReceivedCommunityTokenWalletEvent(self: Service, jsonMessage: string) =
try:
let dataMessageJson = parseJson(jsonMessage)
let tokenDataPayload = fromJson(dataMessageJson, CommunityTokenReceivedPayload)
if len(tokenDataPayload.communityId) == 0:
return
let communityId = tokenDataPayload.communityId
let tokenReceivedArgs = CommunityTokenReceivedArgs(
communityId: communityId,
communityName: tokenDataPayload.communityName,
communityColor: tokenDataPayload.communityColor,
chainId: tokenDataPayload.chainId,
txHash: tokenDataPayload.txHash,
name: tokenDataPayload.name,
balance: tokenDataPayload.balance,
image: tokenDataPayload.image
)
self.events.emit(SIGNAL_COMMUNITY_TOKEN_RECEIVED, tokenReceivedArgs)
let response = tokens_backend.registerReceivedCommunityTokenNotification(communityId)
checkAndEmitACNotificationsFromResponse(self.events, response.result{"activityCenterNotifications"})
except Exception as e:
error "Error registering community token received notification", msg=e.msg
proc processSetSignerTransactionEvent(self: Service, transactionArgs: TransactionMinedArgs) = proc processSetSignerTransactionEvent(self: Service, transactionArgs: TransactionMinedArgs) =
try: try:
if not transactionArgs.success: if not transactionArgs.success:
@ -338,6 +375,8 @@ QtObject:
var data = WalletSignal(e) var data = WalletSignal(e)
if data.eventType == collectibles_backend.eventCommunityCollectiblesReceived: if data.eventType == collectibles_backend.eventCommunityCollectiblesReceived:
self.processReceivedCollectiblesWalletEvent(data.message) self.processReceivedCollectiblesWalletEvent(data.message)
elif data.eventType == tokens_backend.eventCommunityTokenReceived:
self.processReceivedCommunityTokenWalletEvent(data.message)
self.events.on(PendingTransactionTypeDto.SetSignerPublicKey.event) do(e: Args): self.events.on(PendingTransactionTypeDto.SetSignerPublicKey.event) do(e: Args):
let receivedData = TransactionMinedArgs(e) let receivedData = TransactionMinedArgs(e)

View File

@ -6,6 +6,11 @@ import ./core, ./response_type
import ../app_service/service/community_tokens/dto/community_token import ../app_service/service/community_tokens/dto/community_token
import interpret/cropped_image import interpret/cropped_image
from ./gen import rpc
# Mirrors the transfer event from status-go, services/wallet/transfer/commands.go
const eventCommunityTokenReceived*: string = "wallet-community-token-received"
proc deployCollectibles*(chainId: int, deploymentParams: JsonNode, txData: JsonNode, hashedPassword: string): RpcResponse[JsonNode] {.raises: [Exception].} = proc deployCollectibles*(chainId: int, deploymentParams: JsonNode, txData: JsonNode, hashedPassword: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [chainId, deploymentParams, txData, hashedPassword] let payload = %* [chainId, deploymentParams, txData, hashedPassword]
return core.callPrivateRPC("communitytokens_deployCollectibles", payload) return core.callPrivateRPC("communitytokens_deployCollectibles", payload)
@ -142,3 +147,6 @@ proc promoteSelfToControlNode*(communityId: string): RpcResponse[JsonNode] {.rai
proc getOwnerTokenOwnerAddress*(chainId: int, contractAddress: string): RpcResponse[JsonNode] {.raises: [Exception].} = proc getOwnerTokenOwnerAddress*(chainId: int, contractAddress: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %*[chainId, contractAddress] let payload = %*[chainId, contractAddress]
return core.callPrivateRPC("communitytokens_ownerTokenOwnerAddress", payload) return core.callPrivateRPC("communitytokens_ownerTokenOwnerAddress", payload)
rpc(registerReceivedCommunityTokenNotification, "wakuext"):
communityId: string

View File

@ -1,4 +1,40 @@
import json
include app_service/common/json_utils
import web3/conversions
import web3/ethtypes as eth
type type
# see protocol/communities/token/community_token.go PrivilegesLevel # see protocol/communities/token/community_token.go PrivilegesLevel
PrivilegesLevel* {.pure.} = enum PrivilegesLevel* {.pure.} = enum
Owner, Master, Community Owner, Master, Community
CommunityTokenReceivedPayload* = object
address*: eth.Address
name*: string
symbol*: string
image*: string
chainId*: int
communityId*: string
communityName*: string
communityColor*: string
communityImage*: string
balance*: int
txHash*: string
proc fromJson*(t: JsonNode, T: typedesc[CommunityTokenReceivedPayload]): CommunityTokenReceivedPayload {.inline.}=
let addressField = "address"
discard t.getProp("name", result.name)
discard t.getProp("symbol", result.symbol)
discard t.getProp("image", result.image)
discard t.getProp("chainId", result.chainId)
discard t.getProp("txHash", result.txHash)
result.balance = t{"balance"}.getInt()
fromJson(t[addressField], addressField, result.address)
var communityDataObj: JsonNode
if(t.getProp("community_data", communityDataObj)):
discard communityDataObj.getProp("id", result.communityId)
discard communityDataObj.getProp("name", result.communityName)
discard communityDataObj.getProp("color", result.communityColor)
discard communityDataObj.getProp("image", result.communityImage)

View File

@ -20,7 +20,8 @@ QtObject {
None = 0, None = 0,
NavigateToCommunityAdmin = 1, NavigateToCommunityAdmin = 1,
OpenFinaliseOwnershipPopup = 2, OpenFinaliseOwnershipPopup = 2,
OpenSendModalPopup = 3 OpenSendModalPopup = 3,
ViewTransactionDetails = 4
} }
// Stores: // Stores:
@ -53,6 +54,22 @@ QtObject {
communityId) communityId)
} }
function onCommunityTokenReceived(name, image, communityId, communityName, communityColor, balance, chainId, txHash) {
var data = {
communityId: communityId,
chainId: chainId,
txHash: txHash
}
Global.displayToastWithActionMessage(qsTr("You were airdropped %1 %2 asset from %3").arg(balance).arg(name).arg(communityName),
qsTr("View transaction details"),
image,
communityColor,
false,
Constants.ephemeralNotificationType.normal,
ToastsManager.ActionType.ViewTransactionDetails,
JSON.stringify(data))
}
function onSetSignerStateChanged(communityId, communityName, status, url) { function onSetSignerStateChanged(communityId, communityName, status, url) {
if (status === Constants.ContractTransactionStatus.Completed) { if (status === Constants.ContractTransactionStatus.Completed) {
Global.displayToastMessage(qsTr("%1 smart contract amended").arg(communityName), Global.displayToastMessage(qsTr("%1 smart contract amended").arg(communityName),

View File

@ -129,6 +129,8 @@ Popup {
return contactRemovedComponent return contactRemovedComponent
case ActivityCenterStore.ActivityCenterNotificationType.NewKeypairAddedToPairedDevice: case ActivityCenterStore.ActivityCenterNotificationType.NewKeypairAddedToPairedDevice:
return newKeypairFromPairedDeviceComponent return newKeypairFromPairedDeviceComponent
case ActivityCenterStore.ActivityCenterNotificationType.CommunityTokenReceived:
return communityTokenReceivedComponent
case ActivityCenterStore.ActivityCenterNotificationType.OwnerTokenReceived: case ActivityCenterStore.ActivityCenterNotificationType.OwnerTokenReceived:
case ActivityCenterStore.ActivityCenterNotificationType.OwnershipReceived: case ActivityCenterStore.ActivityCenterNotificationType.OwnershipReceived:
case ActivityCenterStore.ActivityCenterNotificationType.OwnershipLost: case ActivityCenterStore.ActivityCenterNotificationType.OwnershipLost:
@ -278,6 +280,25 @@ Popup {
} }
} }
Component {
id: communityTokenReceivedComponent
ActivityNotificationCommunityTokenReceived {
readonly property var community : notification ? root.store.getCommunityDetailsAsJson(notification.communityId) : null
communityName: community ? community.name : ""
communityColor: community ? community.color : "black"
communityImage: community ? community.image : ""
filteredIndex: parent.filteredIndex
notification: parent.notification
store: root.store
activityCenterStore: root.activityCenterStore
onCloseActivityCenter: root.close()
}
}
Component { Component {
id: shareAccountsNotificationComponent id: shareAccountsNotificationComponent
@ -286,7 +307,7 @@ Popup {
readonly property var community : notification ? root.store.getCommunityDetailsAsJson(notification.communityId) : null readonly property var community : notification ? root.store.getCommunityDetailsAsJson(notification.communityId) : null
communityName: community ? community.name : "" communityName: community ? community.name : ""
communityColor: community ? community.color : "black" communityColor: community ? community.color : "transparent"
communityImage: community ? community.image : "" communityImage: community ? community.image : ""
filteredIndex: parent.filteredIndex filteredIndex: parent.filteredIndex

View File

@ -36,7 +36,8 @@ QtObject {
OwnershipLost = 15, OwnershipLost = 15,
OwnershipFailed = 16, OwnershipFailed = 16,
OwnershipDeclined = 17, OwnershipDeclined = 17,
ShareAccounts = 18 ShareAccounts = 18,
CommunityTokenReceived = 19
} }
enum ActivityCenterReadType { enum ActivityCenterReadType {

View File

@ -0,0 +1,70 @@
import QtQuick 2.14
import QtQuick.Layouts 1.14
import StatusQ.Controls 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Components 0.1
import shared 1.0
import shared.panels 1.0
import utils 1.0
import "../panels"
import "../popups"
import "../stores"
ActivityNotificationBase {
id: root
required property string communityName
required property string communityImage
required property string communityColor
bodyComponent: RowLayout {
spacing: 8
StatusSmartIdenticon {
name: root.communityName
Layout.preferredWidth: 40
Layout.preferredHeight: 40
Layout.alignment: Qt.AlignTop
Layout.leftMargin: Style.current.padding
Layout.topMargin: 2
asset {
width: 24
height: width
name: root.communityImage
color: root.communityColor
bgWidth: 40
bgHeight: 40
}
}
ColumnLayout {
spacing: 2
Layout.alignment: Qt.AlignTop
RowLayout {
StatusBaseText {
Layout.fillWidth: true
verticalAlignment: Text.AlignVCenter
font.weight: Font.Medium
font.pixelSize: Theme.primaryTextFontSize
wrapMode: Text.WordWrap
color: Theme.palette.primaryColor1
text: qsTr("You were airdropped community asset from %1").arg(root.communityName)
}
StatusTimeStampLabel {
id: timestamp
verticalAlignment: Text.AlignVCenter
timestamp: root.notification.timestamp
}
}
}
}
ctaComponent: undefined
}

View File

@ -34,6 +34,7 @@ QtObject {
signal communityOwnershipDeclined(string communityName) signal communityOwnershipDeclined(string communityName)
signal sendOwnerTokenStateChanged(string tokenName, int status, string url) signal sendOwnerTokenStateChanged(string tokenName, int status, string url)
signal ownerTokenReceived(string communityId, string communityName) signal ownerTokenReceived(string communityId, string communityName)
signal communityTokenReceived(string name, string image, string communityId, string communityName, string communityColor, string balance, int chainId, string txHash)
// Minting tokens: // Minting tokens:
function deployCollectible(communityId, collectibleItem) function deployCollectible(communityId, collectibleItem)
@ -131,6 +132,10 @@ QtObject {
root.ownerTokenReceived(communityId, communityName) root.ownerTokenReceived(communityId, communityName)
} }
function onCommunityTokenReceived(name, image, communityId, communityName, communityColor, balance, chainId, txHash) {
root.communityTokenReceived(name, image, communityId, communityName, communityColor, balance, chainId, txHash)
}
function onSetSignerStateChanged(communityId, communityName, status, url) { function onSetSignerStateChanged(communityId, communityName, status, url) {
root.setSignerStateChanged(communityId, communityName, status, url) root.setSignerStateChanged(communityId, communityName, status, url)
} }

View File

@ -55,14 +55,11 @@ ColumnLayout {
readonly property bool isCustomView: cmbTokenOrder.currentValue === SortOrderComboBox.TokenOrderCustom readonly property bool isCustomView: cmbTokenOrder.currentValue === SortOrderComboBox.TokenOrderCustom
function tokenIsVisible(symbol, currencyBalance) { function tokenIsVisible(symbol, currencyBalance) {
if (symbol === "ETH") // always visible // NOTE Backend returns ETH, SNT, STT and DAI by default
return true
if (!d.controller.filterAcceptsSymbol(symbol)) // explicitely hidden if (!d.controller.filterAcceptsSymbol(symbol)) // explicitely hidden
return false return false
if (symbol === "SNT" || symbol === "STT" || symbol === "DAI") // visible by default // Received tokens can have 0 balance, which indicate previosuly owned token
return true return true // TODO handle UI threshold (#12611)
// We'll receive the tokens only with non zero balance except for Eth, Dai or SNT/STT
return !!currencyBalance // TODO handle UI threshold (#12611)
} }
readonly property var controller: ManageTokensController { readonly property var controller: ManageTokensController {