fix(@desktop/communities): Add toasts to send owner token process

Fix transfer ownership button.
Set correct data in SendModal.

Issue #12656
This commit is contained in:
Michal Iskierko 2023-11-24 09:48:50 +01:00 committed by Michał Iskierko
parent dadfc58126
commit d2b2aae000
20 changed files with 127 additions and 33 deletions

View File

@ -95,6 +95,9 @@ proc init*(self: Controller) =
self.events.on(SIGNAL_OWNER_TOKEN_OWNER_ADDRESS) do(e: Args):
let args = OwnerTokenOwnerAddressArgs(e)
self.communityTokensModule.onOwnerTokenOwnerAddress(args.chainId, args.contractAddress, args.address, args.addressName)
self.events.on(SIGNAL_OWNER_TOKEN_SENT) do(e: Args):
let args = OwnerTokenSentArgs(e)
self.communityTokensModule.onSendOwnerTokenStateChanged(args.chainId, args.txHash, args.tokenName, args.status)
proc deployContract*(self: Controller, communityId: string, addressFrom: string, password: string, deploymentParams: DeploymentParameters, tokenMetadata: CommunityTokensMetadataDto, tokenImageCropInfoJson: string, chainId: int) =
self.communityTokensService.deployContract(communityId, addressFrom, password, deploymentParams, tokenMetadata, tokenImageCropInfoJson, chainId)

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 onSendOwnerTokenStateChanged*(self: AccessInterface, chainId: int, transactionHash: string, tokenName: string, status: ContractTransactionStatus) {.base.} =
raise newException(ValueError, "No implementation available")
method onSetSignerStateChanged*(self: AccessInterface, communityId: string, chainId: int, transactionHash: string, status: ContractTransactionStatus) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -340,6 +340,10 @@ method onSetSignerStateChanged*(self: Module, communityId: string, chainId: int,
let url = self.createUrl(chainId, transactionHash)
self.view.emitSetSignerStateChanged(communityId, communityName, status.int, url)
method onSendOwnerTokenStateChanged*(self: Module, chainId: int, transactionHash: string, tokenName: string, status: ContractTransactionStatus) =
let url = self.createUrl(chainId, transactionHash)
self.view.emitSendOwnerTokenStateChanged(tokenName, status.int, url)
method onLostOwnership*(self: Module, communityId: string) =
let communityDto = self.controller.getCommunityById(communityId)
let communityName = communityDto.name

View File

@ -57,6 +57,7 @@ QtObject:
proc ownerTokenReceived*(self: View, communityId: string, communityName: string, chainId: int, contractAddress: 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.}
proc computeDeployFee*(self: View, communityId: string, chainId: int, accountAddress: string, tokenType: int, isOwnerDeployment: bool, requestId: string) {.slot.} =
self.communityTokensModule.computeDeployFee(communityId, chainId, accountAddress, intToEnum(tokenType, TokenType.Unknown), isOwnerDeployment, requestId)
@ -121,6 +122,9 @@ QtObject:
proc emitOwnershipLost*(self: View, communityId: string, communityName: string) =
self.ownershipNodeLost(communityId, communityName)
proc emitSendOwnerTokenStateChanged*(self: View, tokenName: string, status: int, url: string) =
self.sendOwnerTokenStateChanged(tokenName, status, url)
proc asyncGetOwnerTokenDetails*(self: View, communityId: string) {.slot.} =
self.communityTokensModule.asyncGetOwnerTokenDetails(communityId)

View File

@ -59,6 +59,10 @@ proc init*(self: Controller) =
let args = TransactionSentArgs(e)
self.delegate.transactionWasSent(args.chainId, args.txHash, args.uuid, args.error)
self.events.on(SIGNAL_OWNER_TOKEN_SENT) do(e:Args):
let args = OwnerTokenSentArgs(e)
self.delegate.transactionWasSent(args.chainId, args.txHash, args.uuid, "")
self.events.on(SIGNAL_SHARED_KEYCARD_MODULE_USER_AUTHENTICATED) do(e: Args):
let args = SharedKeycarModuleArgs(e)
if args.uniqueIdentifier != UNIQUE_WALLET_SECTION_SEND_MODULE_IDENTIFIER:
@ -114,9 +118,9 @@ proc suggestedRoutes*(self: Controller, accountFrom: string, accountTo: string,
proc transfer*(self: Controller, from_addr: string, to_addr: string, tokenSymbol: string,
value: string, uuid: string, selectedRoutes: seq[TransactionPathDto], password: string, sendType: SendType,
usePassword: bool, doHashing: bool) =
usePassword: bool, doHashing: bool, tokenName: string, isOwnerToken: bool) =
self.transactionService.transfer(from_addr, to_addr, tokenSymbol, value, uuid, selectedRoutes, password, sendType,
usePassword, doHashing)
usePassword, doHashing, tokenName, isOwnerToken)
proc proceedWithTransactionsSignatures*(self: Controller, fromAddr: string, toAddr: string, uuid: string,
signatures: TransactionsSignatures, selectedRoutes: seq[TransactionPathDto]) =

View File

@ -32,7 +32,7 @@ method suggestedRoutesReady*(self: AccessInterface, suggestedRoutes: SuggestedRo
raise newException(ValueError, "No implementation available")
method authenticateAndTransfer*(self: AccessInterface, from_addr: string, to_addr: string,
tokenSymbol: string, value: string, uuid: string, sendType: SendType) {.base.} =
tokenSymbol: string, value: string, uuid: string, sendType: SendType, selectedTokenName: string, selectedTokenIsOwnerToken: bool) {.base.} =
raise newException(ValueError, "No implementation available")
method onUserAuthenticated*(self: AccessInterface, password: string, pin: string) {.base.} =

View File

@ -37,6 +37,8 @@ type TmpSendTransactionDetails = object
uuid: string
sendType: SendType
resolvedSignatures: TransactionsSignatures
tokenName: string
isOwnerToken: bool
type
Module* = ref object of io_interface.AccessInterface
@ -255,7 +257,7 @@ method viewDidLoad*(self: Module) =
method getTokenBalanceOnChain*(self: Module, address: string, chainId: int, symbol: string): CurrencyAmount =
return self.controller.getTokenBalanceOnChain(address, chainId, symbol)
method authenticateAndTransfer*(self: Module, fromAddr: string, toAddr: string, tokenSymbol: string, value: string, uuid: string, sendType: SendType) =
method authenticateAndTransfer*(self: Module, fromAddr: string, toAddr: string, tokenSymbol: string, value: string, uuid: string, sendType: SendType, selectedTokenName: string, selectedTokenIsOwnerToken: bool) =
self.tmpSendTransactionDetails.fromAddr = fromAddr
self.tmpSendTransactionDetails.toAddr = toAddr
self.tmpSendTransactionDetails.tokenSymbol = tokenSymbol
@ -264,6 +266,8 @@ method authenticateAndTransfer*(self: Module, fromAddr: string, toAddr: string,
self.tmpSendTransactionDetails.sendType = sendType
self.tmpSendTransactionDetails.fromAddrPath = ""
self.tmpSendTransactionDetails.resolvedSignatures.clear()
self.tmpSendTransactionDetails.tokenName = selectedTokenName
self.tmpSendTransactionDetails.isOwnerToken = selectedTokenIsOwnerToken
let kp = self.controller.getKeypairByAccountAddress(fromAddr)
if kp.migratedToKeycard():
@ -286,7 +290,8 @@ method onUserAuthenticated*(self: Module, password: string, pin: string) =
self.controller.transfer(
self.tmpSendTransactionDetails.fromAddr, self.tmpSendTransactionDetails.toAddr,
self.tmpSendTransactionDetails.tokenSymbol, self.tmpSendTransactionDetails.value, self.tmpSendTransactionDetails.uuid,
self.tmpSendTransactionDetails.paths, password, self.tmpSendTransactionDetails.sendType, usePassword, doHashing
self.tmpSendTransactionDetails.paths, password, self.tmpSendTransactionDetails.sendType, usePassword, doHashing,
self.tmpSendTransactionDetails.tokenName, self.tmpSendTransactionDetails.isOwnerToken
)
proc signOnKeycard(self: Module) =

View File

@ -24,6 +24,8 @@ QtObject:
selectedAssetSymbol: string
showUnPreferredChains: bool
sendType: transaction_dto.SendType
selectedTokenIsOwnerToken: bool
selectedTokenName: string
selectedRecipient: string
# for receive modal
selectedReceiveAccount: AccountItem
@ -170,6 +172,12 @@ QtObject:
write = setSelectedRecipient
notify = selectedRecipientChanged
proc setSelectedTokenIsOwnerToken(self: View, isOwnerToken: bool) {.slot.} =
self.selectedTokenIsOwnerToken = isOwnerToken
proc setSelectedTokenName(self: View, tokenName: string) {.slot.} =
self.selectedTokenName = tokenName
proc updateNetworksDisabledChains(self: View) =
# if the setting to show unpreferred chains is toggled, add all unpreferred chains to disabled chains list
if not self.showUnPreferredChains:
@ -199,7 +207,7 @@ QtObject:
self.transactionSent(chainId, txHash, uuid, error)
proc authenticateAndTransfer*(self: View, value: string, uuid: string) {.slot.} =
self.delegate.authenticateAndTransfer(self.selectedSenderAccount.address(), self.selectedRecipient, self.selectedAssetSymbol, value, uuid, self.sendType)
self.delegate.authenticateAndTransfer(self.selectedSenderAccount.address(), self.selectedRecipient, self.selectedAssetSymbol, value, uuid, self.sendType, self.selectedTokenName, self.selectedTokenIsOwnerToken)
proc suggestedRoutesReady*(self: View, suggestedRoutes: QVariant) {.signal.}
proc setTransactionRoute*(self: View, routes: TransactionRoutes) =

View File

@ -8,6 +8,7 @@ import ../../../backend/eth
import ../ens/utils as ens_utils
import ../../common/conversion as common_conversion
import ../../common/utils as common_utils
import ../../common/types as common_types
import ../../../app/core/[main]
import ../../../app/core/signals/types
@ -44,11 +45,27 @@ const SIGNAL_HISTORY_NON_ARCHIVAL_NODE* = "historyNonArchivalNode"
const SIGNAL_HISTORY_ERROR* = "historyError"
const SIGNAL_CRYPTO_SERVICES_READY* = "cryptoServicesReady"
const SIGNAL_TRANSACTION_DECODED* = "transactionDecoded"
const SIGNAL_OWNER_TOKEN_SENT* = "ownerTokenSent"
const SIMPLE_TX_BRIDGE_NAME = "Transfer"
const HOP_TX_BRIDGE_NAME = "Hop"
const ERC721_TRANSFER_NAME = "ERC721Transfer"
type TokenTransferMetadata* = object
tokenName*: string
isOwnerToken*: bool
proc `%`*(self: TokenTransferMetadata): JsonNode =
result = %* {
"tokenName": self.tokenName,
"isOwnerToken": self.isOwnerToken,
}
proc toTokenTransferMetadata*(jsonObj: JsonNode): TokenTransferMetadata =
result = TokenTransferMetadata()
discard jsonObj.getProp("tokenName", result.tokenName)
discard jsonObj.getProp("isOwnerToken", result.isOwnerToken)
type
EstimatedTime* {.pure.} = enum
Unknown = 0
@ -79,6 +96,14 @@ type
uuid*: string
error*: string
type
OwnerTokenSentArgs* = ref object of Args
chainId*: int
txHash*: string
tokenName*: string
uuid*: string
status*: ContractTransactionStatus
type
SuggestedRoutesArgs* = ref object of Args
suggestedRoutes*: SuggestedRoutesDto
@ -126,6 +151,16 @@ QtObject:
of transactions.EventFetchingHistoryError:
self.events.emit(SIGNAL_HISTORY_ERROR, Args())
self.events.on(PendingTransactionTypeDto.WalletTransfer.event) do(e: Args):
try:
var receivedData = TransactionMinedArgs(e)
let tokenMetadata = receivedData.data.parseJson().toTokenTransferMetadata()
if tokenMetadata.isOwnerToken:
let status = if receivedData.success: ContractTransactionStatus.Completed else: ContractTransactionStatus.Failed
self.events.emit(SIGNAL_OWNER_TOKEN_SENT, OwnerTokenSentArgs(chainId: receivedData.chainId, txHash: receivedData.transactionHash, tokenName: tokenMetadata.tokenName, status: status))
except Exception as e:
debug "Not the owner token transfer", msg=e.msg
proc getPendingTransactions*(self: Service): seq[TransactionDto] =
try:
let response = backend.getPendingTransactions().result
@ -251,14 +286,20 @@ QtObject:
return path
proc sendTransactionSentSignal(self: Service, fromAddr: string, toAddr: string, uuid: string,
routes: seq[TransactionPathDto], response: RpcResponse[JsonNode], err: string = "") =
routes: seq[TransactionPathDto], response: RpcResponse[JsonNode], err: string = "", tokenName = "", isOwnerToken=false) =
if err.len > 0:
self.events.emit(SIGNAL_TRANSACTION_SENT, TransactionSentArgs(uuid: uuid, error: err))
elif response.result{"hashes"} != nil:
for route in routes:
for hash in response.result["hashes"][$route.fromNetwork.chainID]:
self.watchTransaction(hash.getStr, fromAddr, toAddr, $PendingTransactionTypeDto.WalletTransfer, " ", route.fromNetwork.chainID, track = false)
self.events.emit(SIGNAL_TRANSACTION_SENT, TransactionSentArgs(chainId: route.fromNetwork.chainID, txHash: hash.getStr, uuid: uuid , error: ""))
if isOwnerToken:
self.events.emit(SIGNAL_OWNER_TOKEN_SENT, OwnerTokenSentArgs(chainId: route.fromNetwork.chainID, txHash: hash.getStr, uuid: uuid, tokenName: tokenName, status: ContractTransactionStatus.InProgress))
else:
self.events.emit(SIGNAL_TRANSACTION_SENT, TransactionSentArgs(chainId: route.fromNetwork.chainID, txHash: hash.getStr, uuid: uuid , error: ""))
let metadata = TokenTransferMetadata(tokenName: tokenName, isOwnerToken: isOwnerToken)
self.watchTransaction(hash.getStr, fromAddr, toAddr, $PendingTransactionTypeDto.WalletTransfer, $(%metadata), route.fromNetwork.chainID, track = false)
proc transferEth(
self: Service,
@ -318,7 +359,9 @@ QtObject:
uuid: string,
routes: seq[TransactionPathDto],
password: string,
sendType: SendType
sendType: SendType,
tokenName: string,
isOwnerToken: bool
) =
try:
let isERC721Transfer = sendType == ERC721Transfer
@ -379,7 +422,7 @@ QtObject:
)
if password != "":
self.sendTransactionSentSignal(from_addr, to_addr, uuid, routes, response)
self.sendTransactionSentSignal(from_addr, to_addr, uuid, routes, response, err="", tokenName, isOwnerToken)
except Exception as e:
self.sendTransactionSentSignal(from_addr, to_addr, uuid, @[], RpcResponse[JsonNode](), fmt"Error sending token transfer transaction: {e.msg}")
@ -395,7 +438,9 @@ QtObject:
password: string,
sendType: SendType,
usePassword: bool,
doHashing: bool
doHashing: bool,
tokenName: string,
isOwnerToken: bool
) =
var finalPassword = ""
if usePassword:
@ -416,7 +461,7 @@ QtObject:
if(isEthTx):
self.transferEth(fromAddr, toAddr, tokenSymbol, value, uuid, selectedRoutes, finalPassword)
else:
self.transferToken(fromAddr, toAddr, tokenSymbol, value, uuid, selectedRoutes, finalPassword, sendType)
self.transferToken(fromAddr, toAddr, tokenSymbol, value, uuid, selectedRoutes, finalPassword, sendType, tokenName, isOwnerToken)
except Exception as e:
self.events.emit(SIGNAL_TRANSACTION_SENT, TransactionSentArgs(chainId: 0, txHash: "", uuid: uuid, error: fmt"Error sending token transfer transaction: {e.msg}"))

View File

@ -34,6 +34,7 @@ QtObject {
property int chainId
property string chainName
property string chainIcon
property string tokenAddress
// Account related properties (from where they will be / have been deployed):
property string accountAddress

View File

@ -758,7 +758,8 @@ StackView {
onRemotelyDestructClicked: remotelyDestructPopup.open()
onBurnClicked: burnTokensPopup.open()
onSendOwnershipClicked: Global.openTransferOwnershipPopup(root.communityName,
onSendOwnershipClicked: Global.openTransferOwnershipPopup(root.communityId,
root.communityName,
root.communityLogo,
tokenViewPage.token,
root.accounts,
@ -966,6 +967,7 @@ StackView {
token.remotelyDestructState: model.remotelyDestructState
token.accountAddress: model.accountAddress
token.multiplierIndex: model.multiplierIndex
token.tokenAddress: model.tokenAddress
}
onCountChanged: {

View File

@ -44,9 +44,8 @@ StackLayout {
property bool isControlNode: false
property int loginType: Constants.LoginType.Password
property bool communitySettingsDisabled
property var tokensModel
property var accounts // Wallet accounts model. Expected roles: address, name, color, emoji, walletType
readonly property var ownerToken: SQUtils.ModelUtils.getByKey(root.tokensModel, "privilegesLevel", Constants.TokenPrivilegesLevel.Owner)
property var ownerToken: null
property string overviewChartData: ""
@ -129,7 +128,8 @@ StackLayout {
onClicked: {
if(!!root.ownerToken && root.ownerToken.deployState === Constants.ContractTransactionStatus.Completed) {
Global.openTransferOwnershipPopup(root.name,
Global.openTransferOwnershipPopup(root.communityId,
root.name,
root.logoImageData,
root.ownerToken,
root.accounts,

View File

@ -20,6 +20,7 @@ StatusDialog {
id: root
// Community related props:
property string communityId
property string communityName
property string communityLogo
@ -109,9 +110,10 @@ StatusDialog {
onClicked: {
// Pre-populated dialog with the relevant Owner token info:
root.sendModalPopup.preSelectedSendType = Constants.SendType.Transfer
root.sendModalPopup.preSelectedSendType = Constants.SendType.ERC721Transfer
root.sendModalPopup.preSelectedAccount = ModelUtils.getByKey(root.accounts, "address", token.accountAddress)
root.sendModalPopup.preSelectedHoldingID = token.key
const uid = token.chainId+"+"+token.tokenAddress.toLowerCase()+"+"+"0" // TODO use getUidForData
root.sendModalPopup.preSelectedHoldingID = uid
root.sendModalPopup.preSelectedHoldingType = Constants.TokenType.ERC721
root.sendModalPopup.open()
close()

View File

@ -194,7 +194,7 @@ StatusSectionLayout {
pubsubTopicKey: root.community.pubsubTopicKey
sendModalPopup: root.sendModalPopup
tokensModel: root.community.communityTokens
ownerToken: tokensModelChangesTracker.ownerToken
accounts: root.walletAccountsModel
isPendingOwnershipRequest: root.isPendingOwnershipRequest
@ -576,6 +576,7 @@ StatusSectionLayout {
property bool isTMasterTokenDeployed: false
property bool isOwnerTokenFailed: false
property bool isTMasterTokenFailed: false
property var ownerToken: null
// It will monitorize if Owner and/or TMaster token items are included in the `model` despite the deployment state
property bool ownerOrTMasterTokenItemsExist: false
@ -590,7 +591,6 @@ StatusSectionLayout {
ownerOrTMasterTokenItemsExist = checkIfPrivilegedTokenItemsExist()
if(!ownerOrTMasterTokenItemsExist)
return
// It monitors the deployment:
if(!isOwnerTokenDeployed) {
isOwnerTokenDeployed = reviewTokenDeployState(true, Constants.ContractTransactionStatus.Completed)
@ -603,8 +603,10 @@ StatusSectionLayout {
}
// Not necessary to track more changes since privileged tokens have been correctly deployed.
if(isOwnerTokenDeployed && isTMasterTokenDeployed)
if(isOwnerTokenDeployed && isTMasterTokenDeployed) {
tokensModelChangesTracker.ownerToken = StatusQUtils.ModelUtils.getByKey(model, "privilegesLevel", Constants.TokenPrivilegesLevel.Owner)
tokensModelChangesTracker.enabled = false
}
}
function reviewTokenDeployState(isOwner, deployState) {

View File

@ -161,16 +161,17 @@ Item {
onLaunchSendModal: {
if(isCommunityOwnershipTransfer) {
let tokenItem = walletStore.currentViewedCollectible
Global.openTransferOwnershipPopup(tokenItem.communityName,
Global.openTransferOwnershipPopup(walletStore.currentViewedCollectible.communityId,
tokenItem.communityName,
tokenItem.communityImage,
{
"key": walletStore.currentViewedHoldingID,
"privilegesLevel": tokenItem.communityPrivilegesLevel,
"chainId": tokenItem.communityPrivilegesLevel,
"privilegesLevel": tokenItem.chainId,
"chainId": tokenItem.chainId,
"name": tokenItem.name,
"artworkSource": tokenItem.artworkSource,
"accountAddress": tokenItem.contractAddress
"accountAddress": leftTab.currentAddress,
"tokenAddress": tokenItem.contractAddress
},
walletStore.accounts,
root.sendModalPopup)

View File

@ -299,8 +299,8 @@ QtObject {
openPopup(importControlNodePopup, { community })
}
function openTransferOwnershipPopup(communityName, communityLogo, token, accounts, sendModalPopup) {
openPopup(transferOwnershipPopup, { communityName, communityLogo, token, accounts, sendModalPopup })
function openTransferOwnershipPopup(communityId, communityName, communityLogo, token, accounts, sendModalPopup) {
openPopup(transferOwnershipPopup, { communityId, communityName, communityLogo, token, accounts, sendModalPopup })
}
function openConfirmExternalLinkPopup(link, domain) {

View File

@ -124,13 +124,17 @@ StatusDialog {
if(!d.ensOrStickersPurpose && store.sendType !== Constants.SendType.Bridge)
store.setSendType(Constants.SendType.Transfer)
store.setSelectedAssetSymbol(selectedHolding.symbol)
store.setSelectedTokenIsOwnerToken(false)
} else if (d.selectedHoldingType === Constants.TokenType.ERC721) {
store.setSendType(Constants.SendType.ERC721Transfer)
amountToSendInput.input.text = 1
store.setSelectedAssetSymbol(selectedHolding.contractAddress+":"+selectedHolding.tokenId)
store.setRouteEnabledFromChains(selectedHolding.chainId)
store.updateRoutePreferredChains(selectedHolding.chainId)
store.setSelectedTokenIsOwnerToken(selectedHolding.communityPrivilegesLevel === Constants.TokenPrivilegesLevel.Owner)
}
store.setSelectedTokenName(selectedHolding.name)
recalculateRoutesAndFees()
}
@ -156,7 +160,6 @@ StatusDialog {
if(popup.preSelectedSendType !== Constants.SendType.Unknown) {
store.setSendType(popup.preSelectedSendType)
}
if ((popup.preSelectedHoldingType > Constants.TokenType.Native) &&
(popup.preSelectedHoldingType < Constants.TokenType.ERC1155)) {
tokenListRect.browsingHoldingType = popup.preSelectedHoldingType

View File

@ -139,10 +139,8 @@ QtObject {
root.ownershipLost(communityId, communityName)
}
// TODO: BACKEND!!!
function onSendOwnerTokenStateChanged(tokenName, status, url) {
console.warn("TODO: Backend missing! On Send owner token!")
root.onSendOwnerTokenStateChanged(tokenName, status, url)
root.sendOwnerTokenStateChanged(tokenName, status, url)
}
}

View File

@ -205,6 +205,14 @@ QtObject {
toNetworksModel.setRouteDisabledChains(chainId, disabled)
}
function setSelectedTokenName(tokenName) {
walletSectionSendInst.setSelectedTokenName(tokenName)
}
function setSelectedTokenIsOwnerToken(isOwnerToken) {
walletSectionSendInst.setSelectedTokenIsOwnerToken(isOwnerToken)
}
function setRouteEnabledFromChains(chainId) {
fromNetworksModel.setRouteEnabledFromChains(chainId)
}

View File

@ -48,7 +48,8 @@ QtObject {
signal openExportControlNodePopup(var community)
signal openImportControlNodePopup(var community)
signal contactRenamed(string publicKey)
signal openTransferOwnershipPopup(string communityName,
signal openTransferOwnershipPopup(string communityId,
string communityName,
string communityLogo,
var token,
var accounts,