feat(@desktop/communities): Expose remote destruct state to UI.

Issue #11182
This commit is contained in:
Michal Iskierko 2023-07-14 15:02:22 +02:00 committed by Michał Iskierko
parent 354bd3e923
commit 780a6b6c68
11 changed files with 155 additions and 21 deletions

View File

@ -16,7 +16,9 @@ type
chainIcon*: string
accountName*: string
remainingSupply*: Uint256
destructedAmount*: Uint256
burnState*: ContractTransactionStatus
remoteDestructedAddresses*: seq[string]
tokenOwnersModel*: token_owners_model.TokenOwnersModel
proc initTokenItem*(
@ -25,7 +27,9 @@ proc initTokenItem*(
tokenOwners: seq[CollectibleOwner],
accountName: string,
burnState: ContractTransactionStatus,
remainingSupply: Uint256
remoteDestructedAddresses: seq[string],
remainingSupply: Uint256,
destructedAmount: Uint256
): TokenItem =
result.tokenDto = tokenDto
if network != nil:
@ -33,11 +37,13 @@ proc initTokenItem*(
result.chainIcon = network.iconURL
result.accountName = accountName
result.remainingSupply = remainingSupply
result.destructedAmount = destructedAmount
result.burnState = burnState
result.remoteDestructedAddresses = remoteDestructedAddresses
result.tokenOwnersModel = newTokenOwnersModel()
result.tokenOwnersModel.setItems(tokenOwners.map(proc(owner: CollectibleOwner): TokenOwnersItem =
# TODO find member with the address - later when airdrop to member will be added
result = initTokenOwnersItem("", "", owner)
result = initTokenOwnersItem("", "", owner, remoteDestructedAddresses)
))
proc `$`*(self: TokenItem): string =
@ -46,7 +52,9 @@ proc `$`*(self: TokenItem): string =
chainName: {self.chainName},
chainIcon: {self.chainIcon},
remainingSupply: {self.remainingSupply},
destructedAmount: {self.destructedAmount},
burnState: {self.burnState},
tokenOwnersModel: {self.tokenOwnersModel}
tokenOwnersModel: {self.tokenOwnersModel},
remoteDestructedAddresses: {self.remoteDestructedAddresses}
]"""

View File

@ -29,6 +29,7 @@ type
RemainingSupply
Decimals
BurnState
RemotelyDestructState
QtObject:
type TokenModel* = ref object of QAbstractListModel
@ -63,11 +64,23 @@ QtObject:
self.dataChanged(index, index, @[ModelRole.BurnState.int])
return
proc updateSupply*(self: TokenModel, chainId: int, contractAddress: string, supply: Uint256) =
proc updateRemoteDestructedAddresses*(self: TokenModel, chainId: int, contractAddress: string, remoteDestructedAddresses: seq[string]) =
for i in 0 ..< self.items.len:
if((self.items[i].tokenDto.address == contractAddress) and (self.items[i].tokenDto.chainId == chainId)):
if self.items[i].tokenDto.supply != supply:
self.items[i].remoteDestructedAddresses = remoteDestructedAddresses
let index = self.createIndex(i, 0, nil)
defer: index.delete
self.dataChanged(index, index, @[ModelRole.RemotelyDestructState.int])
self.items[i].tokenOwnersModel.updateRemoteDestructState(remoteDestructedAddresses)
self.dataChanged(index, index, @[ModelRole.TokenOwnersModel.int])
return
proc updateSupply*(self: TokenModel, chainId: int, contractAddress: string, supply: Uint256, destructedAmount: Uint256) =
for i in 0 ..< self.items.len:
if((self.items[i].tokenDto.address == contractAddress) and (self.items[i].tokenDto.chainId == chainId)):
if self.items[i].tokenDto.supply != supply or self.items[i].destructedAmount != destructedAmount:
self.items[i].tokenDto.supply = supply
self.items[i].destructedAmount = destructedAmount
let index = self.createIndex(i, 0, nil)
defer: index.delete
self.dataChanged(index, index, @[ModelRole.Supply.int])
@ -88,7 +101,7 @@ QtObject:
if((self.items[i].tokenDto.address == contractAddress) and (self.items[i].tokenDto.chainId == chainId)):
self.items[i].tokenOwnersModel.setItems(owners.map(proc(owner: CollectibleOwner): TokenOwnersItem =
# TODO find member with the address - later when airdrop to member will be added
result = initTokenOwnersItem("", "", owner)
result = initTokenOwnersItem("", "", owner, self.items[i].remoteDestructedAddresses)
))
let index = self.createIndex(i, 0, nil)
defer: index.delete
@ -156,6 +169,7 @@ QtObject:
ModelRole.RemainingSupply.int:"remainingSupply",
ModelRole.Decimals.int:"decimals",
ModelRole.BurnState.int:"burnState",
ModelRole.RemotelyDestructState.int:"remotelyDestructState",
}.toTable
method data(self: TokenModel, index: QModelIndex, role: int): QVariant =
@ -179,7 +193,8 @@ QtObject:
of ModelRole.Description:
result = newQVariant(item.tokenDto.description)
of ModelRole.Supply:
result = newQVariant(supplyByType(item.tokenDto.supply, item.tokenDto.tokenType))
# we need to present maxSupply - destructedAmount
result = newQVariant(supplyByType(item.tokenDto.supply - item.destructedAmount, item.tokenDto.tokenType))
of ModelRole.InfiniteSupply:
result = newQVariant(item.tokenDto.infiniteSupply)
of ModelRole.Transferable:
@ -206,6 +221,9 @@ QtObject:
result = newQVariant(item.tokenDto.decimals)
of ModelRole.BurnState:
result = newQVariant(item.burnState.int)
of ModelRole.RemotelyDestructState:
let destructStatus = if len(item.remoteDestructedAddresses) > 0: ContractTransactionStatus.InProgress.int else: ContractTransactionStatus.Completed.int
result = newQVariant(destructStatus)
proc `$`*(self: TokenModel): string =
for i in 0 ..< self.items.len:

View File

@ -1,5 +1,6 @@
import strformat, stint
import backend/collectibles_types
import ../../../../../../app_service/common/types
type
TokenOwnersItem* = object
@ -7,15 +8,23 @@ type
imageSource*: string
ownerDetails*: CollectibleOwner
amount*: int
remotelyDestructState*: ContractTransactionStatus
proc remoteDestructTransactionStatus*(remoteDestructedAddresses: seq[string], address: string): ContractTransactionStatus =
if remoteDestructedAddresses.contains(address):
return ContractTransactionStatus.InProgress
return ContractTransactionStatus.Completed
proc initTokenOwnersItem*(
name: string,
imageSource: string,
ownerDetails: CollectibleOwner
ownerDetails: CollectibleOwner,
remoteDestructedAddresses: seq[string]
): TokenOwnersItem =
result.name = name
result.imageSource = imageSource
result.ownerDetails = ownerDetails
result.remotelyDestructState = remoteDestructTransactionStatus(remoteDestructedAddresses, ownerDetails.address)
for balance in ownerDetails.balances:
result.amount = result.amount + balance.balance.truncate(int)

View File

@ -7,6 +7,7 @@ type
ImageSource
WalletAddress
Amount
RemotelyDestructState
QtObject:
type TokenOwnersModel* = ref object of QAbstractListModel
@ -47,8 +48,18 @@ QtObject:
ModelRole.ImageSource.int:"imageSource",
ModelRole.WalletAddress.int:"walletAddress",
ModelRole.Amount.int:"amount",
ModelRole.RemotelyDestructState.int:"remotelyDestructState"
}.toTable
proc updateRemoteDestructState*(self: TokenOwnersModel, remoteDestructedAddresses: seq[string]) =
let indexBegin = self.createIndex(0, 0, nil)
let indexEnd = self.createIndex(self.items.len - 1, 0, nil)
defer: indexBegin.delete
defer: indexEnd.delete
for i in 0 ..< self.items.len:
self.items[0].remotelyDestructState = remoteDestructTransactionStatus(remoteDestructedAddresses, self.items[0].ownerDetails.address)
self.dataChanged(indexBegin, indexEnd, @[ModelRole.RemotelyDestructState.int])
method data(self: TokenOwnersModel, index: QModelIndex, role: int): QVariant =
if not index.isValid:
return
@ -65,6 +76,8 @@ QtObject:
result = newQVariant(item.ownerDetails.address)
of ModelRole.Amount:
result = newQVariant(item.amount)
of ModelRole.RemotelyDestructState:
result = newQVariant(item.remotelyDestructState.int)
proc `$`*(self: TokenOwnersModel): string =
for i in 0 ..< self.items.len:

View File

@ -57,6 +57,7 @@ type
# Forward declaration
proc setActiveSection*(self: Controller, sectionId: string, skipSavingInSettings: bool = false)
proc getRemainingSupply*(self: Controller, chainId: int, contractAddress: string): Uint256
proc getRemoteDestructedAmount*(self: Controller, chainId: int, contractAddress: string): Uint256
proc newController*(delegate: io_interface.AccessInterface,
events: EventEmitter,
@ -347,14 +348,27 @@ proc init*(self: Controller) =
let args = RemoteDestructArgs(e)
let communityToken = args.communityToken
self.delegate.onCommunityTokenSupplyChanged(communityToken.communityId, communityToken.chainId,
communityToken.address, communityToken.supply, self.getRemainingSupply(communityToken.chainId, communityToken.address))
communityToken.address, communityToken.supply,
self.getRemainingSupply(communityToken.chainId, communityToken.address),
self.getRemoteDestructedAmount(communityToken.chainId, communityToken.address))
self.delegate.onBurnStateChanged(communityToken.communityId, communityToken.chainId, communityToken.address, args.status)
self.events.on(SIGNAL_REMOTE_DESTRUCT_STATUS) do(e: Args):
let args = RemoteDestructArgs(e)
let communityToken = args.communityToken
self.delegate.onCommunityTokenSupplyChanged(communityToken.communityId, communityToken.chainId,
communityToken.address, communityToken.supply,
self.getRemainingSupply(communityToken.chainId, communityToken.address),
self.getRemoteDestructedAmount(communityToken.chainId, communityToken.address))
self.delegate.onRemoteDestructed(communityToken.communityId, communityToken.chainId, communityToken.address, args.remoteDestructAddresses)
self.events.on(SIGNAL_AIRDROP_STATUS) do(e: Args):
let args = AirdropArgs(e)
let communityToken = args.communityToken
self.delegate.onCommunityTokenSupplyChanged(communityToken.communityId, communityToken.chainId,
communityToken.address, communityToken.supply, self.getRemainingSupply(communityToken.chainId, communityToken.address))
communityToken.address, communityToken.supply,
self.getRemainingSupply(communityToken.chainId, communityToken.address),
self.getRemoteDestructedAmount(communityToken.chainId, communityToken.address))
self.events.on(SIGNAL_COMMUNITY_TOKEN_OWNERS_FETCHED) do(e: Args):
let args = CommunityTokenOwnersArgs(e)
@ -494,9 +508,15 @@ proc getCommunityTokenOwnerName*(self: Controller, chainId: int, contractAddress
proc getCommunityTokenBurnState*(self: Controller, chainId: int, contractAddress: string): ContractTransactionStatus =
return self.communityTokensService.getCommunityTokenBurnState(chainId, contractAddress)
proc getRemoteDestructedAddresses*(self: Controller, chainId: int, contractAddress: string): seq[string] =
return self.communityTokensService.getRemoteDestructedAddresses(chainId, contractAddress)
proc getRemainingSupply*(self: Controller, chainId: int, contractAddress: string): Uint256 =
return self.communityTokensService.getRemainingSupply(chainId, contractAddress)
proc getRemoteDestructedAmount*(self: Controller, chainId: int, contractAddress: string): Uint256 =
return self.communityTokensService.getRemoteDestructedAmount(chainId, contractAddress)
proc getNetwork*(self:Controller, chainId: int): NetworkDto =
self.networksService.getNetwork(chainId)

View File

@ -297,7 +297,7 @@ method onCommunityTokenOwnersFetched*(self: AccessInterface, communityId: string
method onCommunityTokenDeployStateChanged*(self: AccessInterface, communityId: string, chainId: int, contractAddress: string, deployState: DeployState) {.base.} =
raise newException(ValueError, "No implementation available")
method onCommunityTokenSupplyChanged*(self: AccessInterface, communityId: string, chainId: int, contractAddress: string, supply: Uint256, remainingSupply: Uint256) {.base.} =
method onCommunityTokenSupplyChanged*(self: AccessInterface, communityId: string, chainId: int, contractAddress: string, supply: Uint256, remainingSupply: Uint256, destructedAmount: Uint256) {.base.} =
raise newException(ValueError, "No implementation available")
method onCommunityTokenRemoved*(self: AccessInterface, communityId: string, chainId: int, contractAddress: string) =
@ -306,6 +306,9 @@ method onCommunityTokenRemoved*(self: AccessInterface, communityId: string, chai
method onBurnStateChanged*(self: AccessInterface, communityId: string, chainId: int, contractAddress: string, burnState: ContractTransactionStatus) {.base.} =
raise newException(ValueError, "No implementation available")
method onRemoteDestructed*(self: AccessInterface, communityId: string, chainId: int, contractAddress: string, addresses: seq[string]) {.base.} =
raise newException(ValueError, "No implementation available")
method onAcceptRequestToJoinFailed*(self: AccessInterface, communityId: string, memberKey: string, requestId: string) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -247,7 +247,9 @@ proc createTokenItem[T](self: Module[T], tokenDto: CommunityTokenDto) : TokenIte
let ownerAddressName = self.controller.getCommunityTokenOwnerName(tokenDto.chainId, tokenDto.address)
let remainingSupply = if tokenDto.infiniteSupply: stint.parse("0", Uint256) else: self.controller.getRemainingSupply(tokenDto.chainId, tokenDto.address)
let burnState = self.controller.getCommunityTokenBurnState(tokenDto.chainId, tokenDto.address)
result = initTokenItem(tokenDto, network, tokenOwners, ownerAddressName, burnState, remainingSupply)
let remoteDestructedAddresses = self.controller.getRemoteDestructedAddresses(tokenDto.chainId, tokenDto.address)
let destructedAmount = self.controller.getRemoteDestructedAmount(tokenDto.chainId, tokenDto.address)
result = initTokenItem(tokenDto, network, tokenOwners, ownerAddressName, burnState, remoteDestructedAddresses, remainingSupply, destructedAmount)
proc createChannelGroupItem[T](self: Module[T], channelGroup: ChannelGroupDto): SectionItem =
let isCommunity = channelGroup.channelGroupType == ChannelGroupType.Community
@ -1029,10 +1031,10 @@ method onCommunityTokenDeployStateChanged*[T](self: Module[T], communityId: stri
if item.id != "":
item.updateCommunityTokenDeployState(chainId, contractAddress, deployState)
method onCommunityTokenSupplyChanged*[T](self: Module[T], communityId: string, chainId: int, contractAddress: string, supply: Uint256, remainingSupply: Uint256) =
method onCommunityTokenSupplyChanged*[T](self: Module[T], communityId: string, chainId: int, contractAddress: string, supply: Uint256, remainingSupply: Uint256, destructedAmount: Uint256) =
let item = self.view.model().getItemById(communityId)
if item.id != "":
item.updateCommunityTokenSupply(chainId, contractAddress, supply)
item.updateCommunityTokenSupply(chainId, contractAddress, supply, destructedAmount)
item.updateCommunityRemainingSupply(chainId, contractAddress, remainingSupply)
method onBurnStateChanged*[T](self: Module[T], communityId: string, chainId: int, contractAddress: string, burnState: ContractTransactionStatus) =
@ -1040,6 +1042,11 @@ method onBurnStateChanged*[T](self: Module[T], communityId: string, chainId: int
if item.id != "":
item.updateBurnState(chainId, contractAddress, burnState)
method onRemoteDestructed*[T](self: Module[T], communityId: string, chainId: int, contractAddress: string, addresses: seq[string]) =
let item = self.view.model().getItemById(communityId)
if item.id != "":
item.updateRemoteDestructedAddresses(chainId, contractAddress, addresses)
method onAcceptRequestToJoinLoading*[T](self: Module[T], communityId: string, memberKey: string) =
let item = self.view.model().getItemById(communityId)
if item.id != "":

View File

@ -338,8 +338,8 @@ proc removeCommunityToken*(self: SectionItem, chainId: int, contractAddress: str
proc updateCommunityTokenDeployState*(self: SectionItem, chainId: int, contractAddress: string, deployState: DeployState) {.inline.} =
self.communityTokensModel.updateDeployState(chainId, contractAddress, deployState)
proc updateCommunityTokenSupply*(self: SectionItem, chainId: int, contractAddress: string, supply: Uint256) {.inline.} =
self.communityTokensModel.updateSupply(chainId, contractAddress, supply)
proc updateCommunityTokenSupply*(self: SectionItem, chainId: int, contractAddress: string, supply: Uint256, destructedAmount: Uint256) {.inline.} =
self.communityTokensModel.updateSupply(chainId, contractAddress, supply, destructedAmount)
proc updateCommunityRemainingSupply*(self: SectionItem, chainId: int, contractAddress: string, remainingSupply: Uint256) {.inline.} =
self.communityTokensModel.updateRemainingSupply(chainId, contractAddress, remainingSupply)
@ -347,6 +347,9 @@ proc updateCommunityRemainingSupply*(self: SectionItem, chainId: int, contractAd
proc updateBurnState*(self: SectionItem, chainId: int, contractAddress: string, burnState: ContractTransactionStatus) {.inline.} =
self.communityTokensModel.updateBurnState(chainId, contractAddress, burnState)
proc updateRemoteDestructedAddresses*(self: SectionItem, chainId: int, contractAddress: string, addresess: seq[string]) {.inline.} =
self.communityTokensModel.updateRemoteDestructedAddresses(chainId, contractAddress, addresess)
proc setCommunityTokenOwners*(self: SectionItem, chainId: int, contractAddress: string, owners: seq[CollectibleOwner]) {.inline.} =
self.communityTokensModel.setCommunityTokenOwners(chainId, contractAddress, owners)

View File

@ -88,6 +88,7 @@ type
communityToken*: CommunityTokenDto
transactionHash*: string
status*: ContractTransactionStatus
remoteDestructAddresses*: seq[string]
type
AirdropArgs* = ref object of Args
@ -95,6 +96,22 @@ type
transactionHash*: string
status*: ContractTransactionStatus
type
RemoteDestroyTransactionDetails* = object
chainId*: int
contractAddress*: string
addresses*: seq[string]
proc `%`*(self: RemoteDestroyTransactionDetails): JsonNode =
result = %* {
"contractAddress": self.contractAddress,
"chainId": self.chainId,
"addresses": self.addresses
}
proc toRemoteDestroyTransactionDetails*(json: JsonNode): RemoteDestroyTransactionDetails =
return RemoteDestroyTransactionDetails(chainId: json["chainId"].getInt, contractAddress: json["contractAddress"].getStr, addresses: to(json["addresses"], seq[string]))
type
ComputeFeeErrorCode* {.pure.} = enum
Success,
@ -183,6 +200,7 @@ QtObject:
# Forward declaration
proc fetchAllTokenOwners*(self: Service)
proc getCommunityTokenOwners*(self: Service, communityId: string, chainId: int, contractAddress: string): seq[CollectibleOwner]
proc getCommunityToken*(self: Service, chainId: int, address: string): CommunityTokenDto
proc delete*(self: Service) =
delete(self.tokenOwnersTimer)
@ -259,9 +277,10 @@ QtObject:
self.events.on(PendingTransactionTypeDto.RemoteDestructCollectible.event) do(e: Args):
let receivedData = TransactionMinedArgs(e)
try:
let tokenDto = toCommunityTokenDto(parseJson(receivedData.data))
let remoteDestructTransactionDetails = toRemoteDestroyTransactionDetails(parseJson(receivedData.data))
let tokenDto = self.getCommunityToken(remoteDestructTransactionDetails.chainId, remoteDestructTransactionDetails.contractAddress)
let transactionStatus = if receivedData.success: ContractTransactionStatus.Completed else: ContractTransactionStatus.Failed
let data = RemoteDestructArgs(communityToken: tokenDto, transactionHash: receivedData.transactionHash, status: transactionStatus)
let data = RemoteDestructArgs(communityToken: tokenDto, transactionHash: receivedData.transactionHash, status: transactionStatus, remoteDestructAddresses: @[])
self.events.emit(SIGNAL_REMOTE_DESTRUCT_STATUS, data)
# update owners list if burn was successfull
@ -391,6 +410,12 @@ QtObject:
if token.symbol == symbol:
return token
proc getCommunityToken*(self: Service, chainId: int, address: string): CommunityTokenDto =
let communityTokens = self.getAllCommunityTokens()
for token in communityTokens:
if token.chainId == chainId and token.address == address:
return token
proc getCommunityTokenBurnState*(self: Service, chainId: int, contractAddress: string): ContractTransactionStatus =
let burnTransactions = self.transactionService.getPendingTransactionsForType(PendingTransactionTypeDto.BurnCommunityToken)
for transaction in burnTransactions:
@ -402,6 +427,16 @@ QtObject:
discard
return ContractTransactionStatus.Completed
proc getRemoteDestructedAddresses*(self: Service, chainId: int, contractAddress: string): seq[string] =
try:
let burnTransactions = self.transactionService.getPendingTransactionsForType(PendingTransactionTypeDto.RemoteDestructCollectible)
for transaction in burnTransactions:
let remoteDestructTransactionDetails = toRemoteDestroyTransactionDetails(parseJson(transaction.additionalData))
if remoteDestructTransactionDetails.chainId == chainId and remoteDestructTransactionDetails.contractAddress == contractAddress:
return remoteDestructTransactionDetails.addresses
except Exception:
error "Error getting contract owner", message = getCurrentExceptionMsg()
proc contractOwner*(self: Service, chainId: int, contractAddress: string): string =
try:
let response = tokens_backend.contractOwner(chainId, contractAddress)
@ -423,6 +458,16 @@ QtObject:
except RpcException:
error "Error getting remaining supply", message = getCurrentExceptionMsg()
proc getRemoteDestructedAmount*(self: Service, chainId: int, contractAddress: string): Uint256 =
try:
let tokenType = self.getCommunityToken(chainId, contractAddress).tokenType
if tokenType != TokenType.ERC721:
return stint.parse("0", Uint256)
let response = tokens_backend.remoteDestructedAmount(chainId, contractAddress)
return stint.parse(response.result.getStr(), Uint256)
except RpcException:
error "Error getting remote destructed amount", message = getCurrentExceptionMsg()
proc airdropTokens*(self: Service, communityId: string, password: string, collectiblesAndAmounts: seq[CommunityTokenAndAmount], walletAddresses: seq[string]) =
try:
for collectibleAndAmount in collectiblesAndAmounts:
@ -535,7 +580,11 @@ QtObject:
let transactionHash = response.result.getStr()
debug "Remote destruct transaction hash ", transactionHash=transactionHash
var data = RemoteDestructArgs(communityToken: contract, transactionHash: transactionHash, status: ContractTransactionStatus.InProgress)
var transactionDetails = RemoteDestroyTransactionDetails(chainId: contract.chainId, contractAddress: contract.address)
for walletAndAmount in walletAndAmounts:
transactionDetails.addresses.add(walletAndAmount.walletAddress)
var data = RemoteDestructArgs(communityToken: contract, transactionHash: transactionHash, status: ContractTransactionStatus.InProgress, remoteDestructAddresses: transactionDetails.addresses)
self.events.emit(SIGNAL_REMOTE_DESTRUCT_STATUS, data)
# observe transaction state
@ -544,7 +593,7 @@ QtObject:
addressFrom,
contract.address,
$PendingTransactionTypeDto.RemoteDestructCollectible,
$contract.toJsonNode(),
$(%transactionDetails),
contract.chainId,
)
except Exception as e:

View File

@ -83,3 +83,7 @@ proc deployCollectiblesEstimate*(): RpcResponse[JsonNode] {.raises: [Exception].
proc deployAssetsEstimate*(): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %*[]
return core.callPrivateRPC("collectibles_deployAssetsEstimate", payload)
proc remoteDestructedAmount*(chainId: int, contractAddress: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %*[chainId, contractAddress]
return core.callPrivateRPC("collectibles_remoteDestructedAmount", payload)

View File

@ -739,9 +739,9 @@ StackView {
token.transferable: model.transferable
token.type: model.tokenType
token.burnState: model.burnState
token.remotelyDestructState: model.remotelyDestructState
// TODO: Backend
//token.accountAddress: model.accountAddress
//token.remotelyDestructState: model.remotelyDestructState
}
onCountChanged: {