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):
let args = OwnerTokenReceivedArgs(e)
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):
let args = SetSignerArgs(e)
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.} =
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.} =
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) =
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) =
let communityDto = self.controller.getCommunityById(communityId)
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 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 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 ownershipNodeLost*(self: View, communityId: string, communityName: 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) =
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) =
self.setSignerStateChanged(communityId, communityName, status, url)

View File

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

View File

@ -169,6 +169,17 @@ type
chainId*: int
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
FinaliseOwnershipStatusArgs* = ref object of Args
isPending*: bool
@ -214,6 +225,7 @@ const SIGNAL_OWNER_TOKEN_RECEIVED* = "communityTokens-ownerTokenReceived"
const SIGNAL_SET_SIGNER_STATUS* = "communityTokens-setSignerStatus"
const SIGNAL_FINALISE_OWNERSHIP_STATUS* = "communityTokens-finaliseOwnershipStatus"
const SIGNAL_OWNER_TOKEN_OWNER_ADDRESS* = "communityTokens-ownerTokenOwnerAddress"
const SIGNAL_COMMUNITY_TOKEN_RECEIVED* = "communityTokens-communityTokenReceived"
QtObject:
type
@ -304,6 +316,31 @@ QtObject:
except Exception as e:
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) =
try:
if not transactionArgs.success:
@ -338,6 +375,8 @@ QtObject:
var data = WalletSignal(e)
if data.eventType == collectibles_backend.eventCommunityCollectiblesReceived:
self.processReceivedCollectiblesWalletEvent(data.message)
elif data.eventType == tokens_backend.eventCommunityTokenReceived:
self.processReceivedCommunityTokenWalletEvent(data.message)
self.events.on(PendingTransactionTypeDto.SetSignerPublicKey.event) do(e: Args):
let receivedData = TransactionMinedArgs(e)

View File

@ -6,6 +6,11 @@ import ./core, ./response_type
import ../app_service/service/community_tokens/dto/community_token
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].} =
let payload = %* [chainId, deploymentParams, txData, hashedPassword]
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].} =
let payload = %*[chainId, contractAddress]
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
# see protocol/communities/token/community_token.go PrivilegesLevel
PrivilegesLevel* {.pure.} = enum
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,
NavigateToCommunityAdmin = 1,
OpenFinaliseOwnershipPopup = 2,
OpenSendModalPopup = 3
OpenSendModalPopup = 3,
ViewTransactionDetails = 4
}
// Stores:
@ -53,6 +54,22 @@ QtObject {
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) {
if (status === Constants.ContractTransactionStatus.Completed) {
Global.displayToastMessage(qsTr("%1 smart contract amended").arg(communityName),

View File

@ -129,6 +129,8 @@ Popup {
return contactRemovedComponent
case ActivityCenterStore.ActivityCenterNotificationType.NewKeypairAddedToPairedDevice:
return newKeypairFromPairedDeviceComponent
case ActivityCenterStore.ActivityCenterNotificationType.CommunityTokenReceived:
return communityTokenReceivedComponent
case ActivityCenterStore.ActivityCenterNotificationType.OwnerTokenReceived:
case ActivityCenterStore.ActivityCenterNotificationType.OwnershipReceived:
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 {
id: shareAccountsNotificationComponent
@ -286,7 +307,7 @@ Popup {
readonly property var community : notification ? root.store.getCommunityDetailsAsJson(notification.communityId) : null
communityName: community ? community.name : ""
communityColor: community ? community.color : "black"
communityColor: community ? community.color : "transparent"
communityImage: community ? community.image : ""
filteredIndex: parent.filteredIndex

View File

@ -36,7 +36,8 @@ QtObject {
OwnershipLost = 15,
OwnershipFailed = 16,
OwnershipDeclined = 17,
ShareAccounts = 18
ShareAccounts = 18,
CommunityTokenReceived = 19
}
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 sendOwnerTokenStateChanged(string tokenName, int status, string url)
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:
function deployCollectible(communityId, collectibleItem)
@ -131,6 +132,10 @@ QtObject {
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) {
root.setSignerStateChanged(communityId, communityName, status, url)
}

View File

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