feat(@desktop/communities): Adding token owners model
- replace qml owners model with Nim one - get token owners from wallet service - keeping owners cache in community_tokens/service and refresh every 10 minutes Issue #10254
This commit is contained in:
parent
cc191ae0e4
commit
2087616b82
|
@ -247,5 +247,5 @@ proc requestCancelDiscordCommunityImport*(self: Controller, id: string) =
|
|||
proc getCommunityTokens*(self: Controller, communityId: string): seq[CommunityTokenDto] =
|
||||
self.communityTokensService.getCommunityTokens(communityId)
|
||||
|
||||
proc getNetworks*(self:Controller): seq[NetworkDto] =
|
||||
self.networksService.getNetworks()
|
||||
proc getNetwork*(self:Controller, chainId: int): NetworkDto =
|
||||
self.networksService.getNetwork(chainId)
|
||||
|
|
|
@ -23,7 +23,6 @@ import ../../../../app_service/service/network/service as networks_service
|
|||
import ../../../../app_service/service/transaction/service as transaction_service
|
||||
import ../../../../app_service/service/community_tokens/service as community_tokens_service
|
||||
import ../../../../app_service/service/chat/dto/chat
|
||||
import ./tokens/models/token_item
|
||||
import ./tokens/module as community_tokens_module
|
||||
|
||||
export io_interface
|
||||
|
@ -132,16 +131,6 @@ proc createMemberItem(self: Module, memberId, requestId: string): MemberItem =
|
|||
isVerified = contactDetails.details.isContactVerified(),
|
||||
requestToJoinId = requestId)
|
||||
|
||||
proc createTokenItem(self: Module, tokenDto: CommunityTokenDto) : TokenItem =
|
||||
var chainName, chainIcon: string
|
||||
let networks = self.controller.getNetworks()
|
||||
for network in networks:
|
||||
if network.chainId == tokenDto.chainId:
|
||||
chainName = network.chainName
|
||||
chainIcon = network.iconURL
|
||||
break
|
||||
result = initTokenItem(tokenDto, chainName, chainIcon)
|
||||
|
||||
method getCommunityItem(self: Module, c: CommunityDto): SectionItem =
|
||||
return initItem(
|
||||
c.id,
|
||||
|
@ -179,8 +168,7 @@ method getCommunityItem(self: Module, c: CommunityDto): SectionItem =
|
|||
declinedMemberRequests = c.declinedRequestsToJoin.map(proc(requestDto: CommunityMembershipRequestDto): MemberItem =
|
||||
result = self.createMemberItem(requestDto.publicKey, requestDto.id)),
|
||||
encrypted = c.encrypted,
|
||||
communityTokens = self.controller.getCommunityTokens(c.id).map(proc(tokenDto: CommunityTokenDto): TokenItem =
|
||||
result = self.createTokenItem(tokenDto))
|
||||
communityTokens = @[]
|
||||
)
|
||||
|
||||
proc getCuratedCommunityItem(self: Module, c: CommunityDto): CuratedCommunityItem =
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
import strformat
|
||||
import strformat, sequtils
|
||||
import ../../../../../../app_service/service/community_tokens/dto/community_token
|
||||
import ../../../../../../app_service/service/collectible/dto
|
||||
import ../../../../../../app_service/service/network/dto
|
||||
|
||||
import token_owners_model
|
||||
import token_owners_item
|
||||
|
||||
export community_token
|
||||
|
||||
|
@ -8,20 +13,28 @@ type
|
|||
tokenDto*: CommunityTokenDto
|
||||
chainName*: string
|
||||
chainIcon*: string
|
||||
tokenOwnersModel*: token_owners_model.TokenOwnersModel
|
||||
|
||||
proc initTokenItem*(
|
||||
tokenDto: CommunityTokenDto,
|
||||
chainName: string,
|
||||
chainIcon: string,
|
||||
network: NetworkDto,
|
||||
tokenOwners: seq[CollectibleOwner]
|
||||
): TokenItem =
|
||||
result.tokenDto = tokenDto
|
||||
result.chainName = chainName
|
||||
result.chainIcon = chainIcon
|
||||
if network != nil:
|
||||
result.chainName = network.chainName
|
||||
result.chainIcon = network.iconURL
|
||||
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)
|
||||
))
|
||||
|
||||
proc `$`*(self: TokenItem): string =
|
||||
result = fmt"""TokenItem(
|
||||
tokenDto: {self.tokenDto},
|
||||
chainName: {self.chainName},
|
||||
chainIcon: {self.chainIcon}
|
||||
chainIcon: {self.chainIcon},
|
||||
tokenOwnersModel: {self.tokenOwnersModel}
|
||||
]"""
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import NimQml, Tables, strformat
|
||||
import NimQml, Tables, strformat, sequtils
|
||||
import token_item
|
||||
import token_owners_item
|
||||
import token_owners_model
|
||||
import ../../../../../../app_service/service/community_tokens/dto/community_token
|
||||
import ../../../../../../app_service/service/collectible/dto
|
||||
|
||||
type
|
||||
ModelRole {.pure.} = enum
|
||||
|
@ -18,6 +21,7 @@ type
|
|||
Image
|
||||
ChainName
|
||||
ChainIcon
|
||||
TokenOwnersModel
|
||||
|
||||
QtObject:
|
||||
type TokenModel* = ref object of QAbstractListModel
|
||||
|
@ -34,14 +38,25 @@ QtObject:
|
|||
new(result, delete)
|
||||
result.setup
|
||||
|
||||
proc updateDeployState*(self: TokenModel, contractAddress: string, deployState: DeployState) =
|
||||
proc updateDeployState*(self: TokenModel, chainId: int, contractAddress: string, deployState: DeployState) =
|
||||
for i in 0 ..< self.items.len:
|
||||
if(self.items[i].tokenDto.address == contractAddress):
|
||||
if((self.items[i].tokenDto.address == contractAddress) and (self.items[i].tokenDto.chainId == chainId)):
|
||||
self.items[i].tokenDto.deployState = deployState
|
||||
let index = self.createIndex(i, 0, nil)
|
||||
self.dataChanged(index, index, @[ModelRole.DeployState.int])
|
||||
return
|
||||
|
||||
proc setCommunityTokenOwners*(self: TokenModel, chainId: int, contractAddress: string, owners: seq[CollectibleOwner]) =
|
||||
for i in 0 ..< self.items.len:
|
||||
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)
|
||||
))
|
||||
let index = self.createIndex(i, 0, nil)
|
||||
self.dataChanged(index, index, @[ModelRole.TokenOwnersModel.int])
|
||||
return
|
||||
|
||||
proc countChanged(self: TokenModel) {.signal.}
|
||||
|
||||
proc setItems*(self: TokenModel, items: seq[TokenItem]) =
|
||||
|
@ -85,6 +100,7 @@ QtObject:
|
|||
ModelRole.Image.int:"image",
|
||||
ModelRole.ChainName.int:"chainName",
|
||||
ModelRole.ChainIcon.int:"chainIcon",
|
||||
ModelRole.TokenOwnersModel.int:"tokenOwnersModel",
|
||||
}.toTable
|
||||
|
||||
method data(self: TokenModel, index: QModelIndex, role: int): QVariant =
|
||||
|
@ -123,6 +139,8 @@ QtObject:
|
|||
result = newQVariant(item.chainName)
|
||||
of ModelRole.ChainIcon:
|
||||
result = newQVariant(item.chainIcon)
|
||||
of ModelRole.TokenOwnersModel:
|
||||
result = newQVariant(item.tokenOwnersModel)
|
||||
|
||||
proc `$`*(self: TokenModel): string =
|
||||
for i in 0 ..< self.items.len:
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
import strformat, stint
|
||||
import ../../../../../../app_service/service/collectible/dto
|
||||
|
||||
type
|
||||
TokenOwnersItem* = object
|
||||
name*: string
|
||||
imageSource*: string
|
||||
ownerDetails*: CollectibleOwner
|
||||
amount*: int
|
||||
|
||||
proc initTokenOwnersItem*(
|
||||
name: string,
|
||||
imageSource: string,
|
||||
ownerDetails: CollectibleOwner
|
||||
): TokenOwnersItem =
|
||||
result.name = name
|
||||
result.imageSource = imageSource
|
||||
result.ownerDetails = ownerDetails
|
||||
for balance in ownerDetails.balances:
|
||||
result.amount = result.amount + balance.balance.truncate(int)
|
||||
|
||||
proc `$`*(self: TokenOwnersItem): string =
|
||||
result = fmt"""TokenOwnersItem(
|
||||
name: {self.name},
|
||||
amount: {self.amount},
|
||||
ownerDetails: {self.ownerDetails}
|
||||
]"""
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
import NimQml, Tables, strformat
|
||||
import token_owners_item
|
||||
|
||||
type
|
||||
ModelRole {.pure.} = enum
|
||||
Name = UserRole + 1
|
||||
ImageSource
|
||||
WalletAddress
|
||||
Amount
|
||||
|
||||
QtObject:
|
||||
type TokenOwnersModel* = ref object of QAbstractListModel
|
||||
items*: seq[TokenOwnersItem]
|
||||
|
||||
proc setup(self: TokenOwnersModel) =
|
||||
self.QAbstractListModel.setup
|
||||
|
||||
proc delete(self: TokenOwnersModel) =
|
||||
self.items = @[]
|
||||
self.QAbstractListModel.delete
|
||||
|
||||
proc newTokenOwnersModel*(): TokenOwnersModel =
|
||||
new(result, delete)
|
||||
result.setup
|
||||
|
||||
proc countChanged(self: TokenOwnersModel) {.signal.}
|
||||
|
||||
proc setItems*(self: TokenOwnersModel, items: seq[TokenOwnersItem]) =
|
||||
self.beginResetModel()
|
||||
self.items = items
|
||||
self.endResetModel()
|
||||
self.countChanged()
|
||||
|
||||
proc count*(self: TokenOwnersModel): int {.slot.} =
|
||||
self.items.len
|
||||
|
||||
QtProperty[int] count:
|
||||
read = count
|
||||
notify = countChanged
|
||||
|
||||
method rowCount(self: TokenOwnersModel, index: QModelIndex = nil): int =
|
||||
return self.items.len
|
||||
|
||||
method roleNames(self: TokenOwnersModel): Table[int, string] =
|
||||
{
|
||||
ModelRole.Name.int:"name",
|
||||
ModelRole.ImageSource.int:"imageSource",
|
||||
ModelRole.WalletAddress.int:"walletAddress",
|
||||
ModelRole.Amount.int:"amount",
|
||||
}.toTable
|
||||
|
||||
method data(self: TokenOwnersModel, index: QModelIndex, role: int): QVariant =
|
||||
if not index.isValid:
|
||||
return
|
||||
if index.row < 0 or index.row >= self.items.len:
|
||||
return
|
||||
let item = self.items[index.row]
|
||||
let enumRole = role.ModelRole
|
||||
case enumRole:
|
||||
of ModelRole.Name:
|
||||
result = newQVariant(item.name)
|
||||
of ModelRole.ImageSource:
|
||||
result = newQVariant(item.imageSource)
|
||||
of ModelRole.WalletAddress:
|
||||
result = newQVariant(item.ownerDetails.address)
|
||||
of ModelRole.Amount:
|
||||
result = newQVariant(item.amount)
|
||||
|
||||
proc `$`*(self: TokenOwnersModel): string =
|
||||
for i in 0 ..< self.items.len:
|
||||
result &= fmt"""TokenOwnersModel:
|
||||
[{i}]:({$self.items[i]})
|
||||
"""
|
|
@ -341,7 +341,11 @@ proc init*(self: Controller) =
|
|||
|
||||
self.events.on(SIGNAL_COMMUNITY_TOKEN_DEPLOY_STATUS) do(e: Args):
|
||||
let args = CommunityTokenDeployedStatusArgs(e)
|
||||
self.delegate.onCommunityTokenDeployStateChanged(args.communityId, args.contractAddress, args.deployState)
|
||||
self.delegate.onCommunityTokenDeployStateChanged(args.communityId, args.chainId, args.contractAddress, args.deployState)
|
||||
|
||||
self.events.on(SIGNAL_COMMUNITY_TOKEN_OWNERS_FETCHED) do(e: Args):
|
||||
let args = CommunityTokenOwnersArgs(e)
|
||||
self.delegate.onCommunityTokenOwnersFetched(args.communityId, args.chainId, args.contractAddress, args.owners)
|
||||
|
||||
self.events.on(SIGNAL_ACCEPT_REQUEST_TO_JOIN_LOADING) do(e: Args):
|
||||
var args = CommunityMemberArgs(e)
|
||||
|
@ -467,5 +471,8 @@ proc getVerificationRequestFrom*(self: Controller, publicKey: string): Verificat
|
|||
proc getCommunityTokens*(self: Controller, communityId: string): seq[CommunityTokenDto] =
|
||||
self.communityTokensService.getCommunityTokens(communityId)
|
||||
|
||||
proc getCommunityTokenOwners*(self: Controller, communityId: string, chainId: int, contractAddress: string): seq[CollectibleOwner] =
|
||||
return self.communityTokensService.getCommunityTokenOwners(communityId, chainId, contractAddress)
|
||||
|
||||
proc getNetwork*(self:Controller, chainId: int): NetworkDto =
|
||||
self.networksService.getNetwork(chainId)
|
|
@ -297,7 +297,10 @@ method onSharedKeycarModuleKeycardSyncPurposeTerminated*(self: AccessInterface,
|
|||
method onCommunityTokenDeployed*(self: AccessInterface, communityToken: CommunityTokenDto) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method onCommunityTokenDeployStateChanged*(self: AccessInterface, communityId: string, contractAddress: string, deployState: DeployState) {.base.} =
|
||||
method onCommunityTokenOwnersFetched*(self: AccessInterface, communityId: string, chainId: int, contractAddress: string, owners: seq[CollectibleOwner]) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method onCommunityTokenDeployStateChanged*(self: AccessInterface, communityId: string, chainId: int, contractAddress: string, deployState: DeployState) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method onAcceptRequestToJoinFailed*(self: AccessInterface, communityId: string, memberKey: string, requestId: string) {.base.} =
|
||||
|
|
|
@ -237,12 +237,10 @@ method delete*[T](self: Module[T]) =
|
|||
self.view.delete
|
||||
self.viewVariant.delete
|
||||
|
||||
proc createTokenItem[T](self: Module[T], tokenDto: CommunityTokenDto, network: NetworkDto) : TokenItem =
|
||||
var chainName, chainIcon: string
|
||||
if network != nil:
|
||||
chainName = network.chainName
|
||||
chainIcon = network.iconURL
|
||||
result = initTokenItem(tokenDto, chainName, chainIcon)
|
||||
proc createTokenItem[T](self: Module[T], tokenDto: CommunityTokenDto) : TokenItem =
|
||||
let network = self.controller.getNetwork(tokenDto.chainId)
|
||||
let tokenOwners = self.controller.getCommunityTokenOwners(tokenDto.communityId, tokenDto.chainId, tokenDto.address)
|
||||
result = initTokenItem(tokenDto, network, tokenOwners)
|
||||
|
||||
proc createChannelGroupItem[T](self: Module[T], channelGroup: ChannelGroupDto): SectionItem =
|
||||
let isCommunity = channelGroup.channelGroupType == ChannelGroupType.Community
|
||||
|
@ -252,8 +250,7 @@ proc createChannelGroupItem[T](self: Module[T], channelGroup: ChannelGroupDto):
|
|||
communityDetails = self.controller.getCommunityById(channelGroup.id)
|
||||
let communityTokens = self.controller.getCommunityTokens(channelGroup.id)
|
||||
communityTokensItems = communityTokens.map(proc(tokenDto: CommunityTokenDto): TokenItem =
|
||||
let network = self.controller.getNetwork(tokenDto.chainId)
|
||||
result = self.createTokenItem(tokenDto, network)
|
||||
result = self.createTokenItem(tokenDto)
|
||||
)
|
||||
|
||||
let unviewedCount = channelGroup.unviewedMessagesCount
|
||||
|
@ -1004,16 +1001,20 @@ method contactsStatusUpdated*[T](self: Module[T], statusUpdates: seq[StatusUpdat
|
|||
let status = toOnlineStatus(s.statusType)
|
||||
self.view.activeSection().setOnlineStatusForMember(s.publicKey, status)
|
||||
|
||||
method onCommunityTokenDeployed*[T](self: Module[T], communityToken: CommunityTokenDto) {.base.} =
|
||||
method onCommunityTokenDeployed*[T](self: Module[T], communityToken: CommunityTokenDto) =
|
||||
let item = self.view.model().getItemById(communityToken.communityId)
|
||||
if item.id != "":
|
||||
let network = self.controller.getNetwork(communityToken.chainId)
|
||||
item.appendCommunityToken(self.createTokenItem(communityToken, network))
|
||||
item.appendCommunityToken(self.createTokenItem(communityToken))
|
||||
|
||||
method onCommunityTokenDeployStateChanged*[T](self: Module[T], communityId: string, contractAddress: string, deployState: DeployState) =
|
||||
method onCommunityTokenOwnersFetched*[T](self: Module[T], communityId: string, chainId: int, contractAddress: string, owners: seq[CollectibleOwner]) =
|
||||
let item = self.view.model().getItemById(communityId)
|
||||
if item.id != "":
|
||||
item.updateCommunityTokenDeployState(contractAddress, deployState)
|
||||
item.setCommunityTokenOwners(chainId, contractAddress, owners)
|
||||
|
||||
method onCommunityTokenDeployStateChanged*[T](self: Module[T], communityId: string, chainId: int, contractAddress: string, deployState: DeployState) =
|
||||
let item = self.view.model().getItemById(communityId)
|
||||
if item.id != "":
|
||||
item.updateCommunityTokenDeployState(chainId, contractAddress, deployState)
|
||||
|
||||
method onAcceptRequestToJoinLoading*[T](self: Module[T], communityId: string, memberKey: string) =
|
||||
let item = self.view.model().getItemById(communityId)
|
||||
|
@ -1220,3 +1221,4 @@ method activateStatusDeepLink*[T](self: Module[T], statusDeepLink: string) =
|
|||
method onDeactivateChatLoader*[T](self: Module[T], sectionId: string, chatId: string) =
|
||||
if (sectionId.len > 0 and self.channelGroupModules.contains(sectionId)):
|
||||
self.channelGroupModules[sectionId].onDeactivateChatLoader(chatId)
|
||||
|
|
@ -3,6 +3,7 @@ import ./member_model, ./member_item
|
|||
import ../main/communities/models/[pending_request_item, pending_request_model]
|
||||
import ../main/communities/tokens/models/token_model as community_tokens_model
|
||||
import ../main/communities/tokens/models/token_item
|
||||
import ../../../app_service/service/collectible/dto
|
||||
|
||||
import ../../global/global_singleton
|
||||
|
||||
|
@ -321,8 +322,11 @@ proc encrypted*(self: SectionItem): bool {.inline.} =
|
|||
proc appendCommunityToken*(self: SectionItem, item: TokenItem) {.inline.} =
|
||||
self.communityTokensModel.appendItem(item)
|
||||
|
||||
proc updateCommunityTokenDeployState*(self: SectionItem, contractAddress: string, deployState: DeployState) {.inline.} =
|
||||
self.communityTokensModel.updateDeployState(contractAddress, deployState)
|
||||
proc updateCommunityTokenDeployState*(self: SectionItem, chainId: int, contractAddress: string, deployState: DeployState) {.inline.} =
|
||||
self.communityTokensModel.updateDeployState(chainId, contractAddress, deployState)
|
||||
|
||||
proc setCommunityTokenOwners*(self: SectionItem, chainId: int, contractAddress: string, owners: seq[CollectibleOwner]) {.inline.} =
|
||||
self.communityTokensModel.setCommunityTokenOwners(chainId, contractAddress, owners)
|
||||
|
||||
proc communityTokens*(self: SectionItem): community_tokens_model.TokenModel {.inline.} =
|
||||
self.communityTokensModel
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
include ../../common/json_utils
|
||||
import ../../../backend/eth
|
||||
import ../../../backend/collectibles
|
||||
import ../../../app/core/tasks/common
|
||||
import ../../../app/core/tasks/qt
|
||||
import ../transaction/dto
|
||||
|
@ -21,3 +22,30 @@ const asyncGetSuggestedFeesTask: Task = proc(argEncoded: string) {.gcsafe, nimca
|
|||
"error": e.msg,
|
||||
})
|
||||
|
||||
type
|
||||
FetchCollectibleOwnersArg = ref object of QObjectTaskArg
|
||||
chainId*: int
|
||||
contractAddress*: string
|
||||
communityId*: string
|
||||
|
||||
const fetchCollectibleOwnersTaskArg: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||
let arg = decode[FetchCollectibleOwnersArg](argEncoded)
|
||||
try:
|
||||
let response = collectibles.getCollectibleOwnersByContractAddress(arg.chainId, arg.contractAddress)
|
||||
let output = %* {
|
||||
"chainId": arg.chainId,
|
||||
"contractAddress": arg.contractAddress,
|
||||
"communityId": arg.communityId,
|
||||
"result": response.result,
|
||||
"error": ""
|
||||
}
|
||||
arg.finish(output)
|
||||
except Exception as e:
|
||||
let output = %* {
|
||||
"chainId": arg.chainId,
|
||||
"contractAddress": arg.contractAddress,
|
||||
"communityId": arg.communityId,
|
||||
"result": "",
|
||||
"error": e.msg
|
||||
}
|
||||
arg.finish(output)
|
|
@ -0,0 +1,13 @@
|
|||
import json
|
||||
|
||||
type
|
||||
CommunityTokenOwner* = object
|
||||
walletAddress*: string
|
||||
amount*: int
|
||||
|
||||
proc `%`*(x: CommunityTokenOwner): JsonNode =
|
||||
result = newJobject()
|
||||
result["walletAddress"] = %x.walletAddress
|
||||
result["amount"] = %x.amount
|
||||
|
||||
|
|
@ -10,6 +10,7 @@ import ../settings/service as settings_service
|
|||
import ../wallet_account/service as wallet_account_service
|
||||
import ../ens/utils as ens_utils
|
||||
import ../eth/dto/transaction
|
||||
import ../collectible/dto as collectibles_dto
|
||||
|
||||
import ../../../backend/response_type
|
||||
|
||||
|
@ -18,12 +19,15 @@ import ../community/dto/community
|
|||
|
||||
import ./dto/deployment_parameters
|
||||
import ./dto/community_token
|
||||
import ./airdrop_details
|
||||
import ./dto/community_token_owner
|
||||
|
||||
import airdrop_details
|
||||
|
||||
include async_tasks
|
||||
|
||||
export community_token
|
||||
export deployment_parameters
|
||||
export community_token_owner
|
||||
|
||||
logScope:
|
||||
topics = "community-tokens-service"
|
||||
|
@ -59,14 +63,23 @@ type
|
|||
fiatCurrency*: CurrencyAmount
|
||||
errorCode*: ComputeFeeErrorCode
|
||||
|
||||
type ContractTuple = tuple
|
||||
type
|
||||
ContractTuple = tuple
|
||||
address: string
|
||||
chainId: int
|
||||
|
||||
type
|
||||
CommunityTokenOwnersArgs* = ref object of Args
|
||||
communityId*: string
|
||||
contractAddress*: string
|
||||
chainId*: int
|
||||
owners*: seq[CollectibleOwner]
|
||||
|
||||
# Signals which may be emitted by this service:
|
||||
const SIGNAL_COMMUNITY_TOKEN_DEPLOY_STATUS* = "communityTokenDeployStatus"
|
||||
const SIGNAL_COMMUNITY_TOKEN_DEPLOYED* = "communityTokenDeployed"
|
||||
const SIGNAL_COMPUTE_DEPLOY_FEE* = "computeDeployFee"
|
||||
const SIGNAL_COMMUNITY_TOKEN_OWNERS_FETCHED* = "communityTokenOwnersFetched"
|
||||
|
||||
QtObject:
|
||||
type
|
||||
|
@ -80,8 +93,14 @@ QtObject:
|
|||
tempAccountAddress: string
|
||||
tempChainId: int
|
||||
addressAndTxMap: Table[ContractTuple, string]
|
||||
tokenOwnersTimer: QTimer
|
||||
tokenOwnersCache: Table[ContractTuple, seq[CollectibleOwner]]
|
||||
|
||||
# Forward declaration
|
||||
proc fetchAllTokenOwners*(self: Service)
|
||||
|
||||
proc delete*(self: Service) =
|
||||
delete(self.tokenOwnersTimer)
|
||||
self.QObject.delete
|
||||
|
||||
proc newService*(
|
||||
|
@ -101,8 +120,13 @@ QtObject:
|
|||
result.settingsService = settingsService
|
||||
result.walletAccountService = walletAccountService
|
||||
result.addressAndTxMap = initTable[ContractTuple, string]()
|
||||
result.tokenOwnersTimer = newQTimer()
|
||||
result.tokenOwnersTimer.setInterval(10*60*1000)
|
||||
signalConnect(result.tokenOwnersTimer, "timeout()", result, "onRefreshTransferableTokenOwners()", 2)
|
||||
|
||||
proc init*(self: Service) =
|
||||
self.fetchAllTokenOwners()
|
||||
self.tokenOwnersTimer.start()
|
||||
self.events.on(PendingTransactionTypeDto.CollectibleDeployment.event) do(e: Args):
|
||||
var receivedData = TransactionMinedArgs(e)
|
||||
let deployState = if receivedData.success: DeployState.Deployed else: DeployState.Failed
|
||||
|
@ -140,7 +164,6 @@ QtObject:
|
|||
|
||||
proc deployCollectibles*(self: Service, communityId: string, addressFrom: string, password: string, deploymentParams: DeploymentParameters, tokenMetadata: CommunityTokensMetadataDto, chainId: int) =
|
||||
try:
|
||||
# TODO this will come from SendModal
|
||||
let suggestedFees = self.transactionService.suggestedFees(chainId)
|
||||
let contractGasUnits = self.deployCollectiblesEstimate()
|
||||
if suggestedFees == nil:
|
||||
|
@ -202,6 +225,13 @@ QtObject:
|
|||
except RpcException:
|
||||
error "Error getting community tokens", message = getCurrentExceptionMsg()
|
||||
|
||||
proc getAllCommunityTokens*(self: Service): seq[CommunityTokenDto] =
|
||||
try:
|
||||
let response = tokens_backend.getAllCommunityTokens()
|
||||
return parseCommunityTokens(response)
|
||||
except RpcException:
|
||||
error "Error getting all community tokens", message = getCurrentExceptionMsg()
|
||||
|
||||
proc getCommunityTokenBySymbol*(self: Service, communityId: string, symbol: string): CommunityTokenDto =
|
||||
let communityTokens = self.getCommunityTokens(communityId)
|
||||
for token in communityTokens:
|
||||
|
@ -303,3 +333,43 @@ QtObject:
|
|||
let data = ComputeDeployFeeArgs(ethCurrency: ethCurrency, fiatCurrency: fiatCurrency,
|
||||
errorCode: (if ethValue > balance: ComputeFeeErrorCode.Balance else: ComputeFeeErrorCode.Success))
|
||||
self.events.emit(SIGNAL_COMPUTE_DEPLOY_FEE, data)
|
||||
|
||||
proc fetchCommunityOwners*(self: Service, communityId: string, chainId: int, contractAddress: string) =
|
||||
let arg = FetchCollectibleOwnersArg(
|
||||
tptr: cast[ByteAddress](fetchCollectibleOwnersTaskArg),
|
||||
vptr: cast[ByteAddress](self.vptr),
|
||||
slot: "onCommunityTokenOwnersFetched",
|
||||
chainId: chainId,
|
||||
contractAddress: contractAddress,
|
||||
communityId: communityId
|
||||
)
|
||||
self.threadpool.start(arg)
|
||||
|
||||
# get owners from cache
|
||||
proc getCommunityTokenOwners*(self: Service, communityId: string, chainId: int, contractAddress: string): seq[CollectibleOwner] =
|
||||
return self.tokenOwnersCache.getOrDefault((address: contractAddress, chainId: chainId))
|
||||
|
||||
proc onCommunityTokenOwnersFetched*(self:Service, response: string) {.slot.} =
|
||||
let responseJson = response.parseJson()
|
||||
if responseJson{"error"}.kind != JNull and responseJson{"error"}.getStr != "":
|
||||
let errorMessage = responseJson["error"].getStr
|
||||
error "Can't fetch community token owners", chainId=responseJson["chainId"], contractAddress=responseJson["contractAddress"], errorMsg=errorMessage
|
||||
return
|
||||
let chainId = responseJson["chainId"].getInt
|
||||
let contractAddress = responseJson["contractAddress"].getStr
|
||||
let communityId = responseJson["communityId"].getStr
|
||||
let resultJson = responseJson["result"]
|
||||
let owners = collectibles_dto.toCollectibleOwnershipDto(resultJson).owners
|
||||
let data = CommunityTokenOwnersArgs(chainId: chainId, contractAddress: contractAddress, communityId: communityId, owners: owners)
|
||||
self.events.emit(SIGNAL_COMMUNITY_TOKEN_OWNERS_FETCHED, data)
|
||||
|
||||
proc onRefreshTransferableTokenOwners*(self:Service) {.slot.} =
|
||||
let allTokens = self.getAllCommunityTokens()
|
||||
for token in allTokens:
|
||||
if token.transferable:
|
||||
self.fetchCommunityOwners(token.communityId, token.chainId, token.address)
|
||||
|
||||
proc fetchAllTokenOwners*(self: Service) =
|
||||
let allTokens = self.getAllCommunityTokens()
|
||||
for token in allTokens:
|
||||
self.fetchCommunityOwners(token.communityId, token.chainId, token.address)
|
|
@ -12,6 +12,10 @@ proc getCommunityTokens*(communityId: string): RpcResponse[JsonNode] {.raises: [
|
|||
let payload = %* [communityId]
|
||||
return core.callPrivateRPC("wakuext_getCommunityTokens", payload)
|
||||
|
||||
proc getAllCommunityTokens*(): RpcResponse[JsonNode] {.raises: [Exception].} =
|
||||
let payload = %* []
|
||||
return core.callPrivateRPC("wakuext_getAllCommunityTokens", payload)
|
||||
|
||||
proc addCommunityToken*(token: CommunityTokenDto): RpcResponse[JsonNode] {.raises: [Exception].} =
|
||||
let payload = %* [token.toJsonNode()]
|
||||
return core.callPrivateRPC("wakuext_addCommunityToken", payload)
|
||||
|
|
|
@ -20,7 +20,7 @@ SettingsPageLayout {
|
|||
|
||||
// Models:
|
||||
property var tokensModel
|
||||
property var holdersModel
|
||||
|
||||
property string feeText
|
||||
property string errorText
|
||||
property bool isFeeLoading: true
|
||||
|
@ -51,7 +51,7 @@ SettingsPageLayout {
|
|||
|
||||
signal signMintTransactionOpened(int chainId, string accountAddress)
|
||||
|
||||
signal remoteSelfDestructCollectibles(var holdersModel,
|
||||
signal remoteSelfDestructCollectibles(var tokenOwnersModel,
|
||||
int chainId,
|
||||
string accountName,
|
||||
string accountAddress)
|
||||
|
@ -89,6 +89,8 @@ SettingsPageLayout {
|
|||
property int chainId
|
||||
property string chainName
|
||||
|
||||
property var tokenOwnersModel
|
||||
|
||||
readonly property var initialItem: (root.tokensModel && root.tokensModel.count > 0) ? mintedTokensView : welcomeView
|
||||
onInitialItemChanged: updateInitialStackView()
|
||||
|
||||
|
@ -228,7 +230,6 @@ SettingsPageLayout {
|
|||
}
|
||||
|
||||
viewWidth: root.viewWidth
|
||||
holdersModel: root.holdersModel
|
||||
|
||||
onMintCollectible: popup.open()
|
||||
|
||||
|
@ -283,7 +284,7 @@ SettingsPageLayout {
|
|||
id: remoteSelfdestructPopup
|
||||
|
||||
collectibleName: root.title
|
||||
model: root.holdersModel
|
||||
model: d.tokenOwnersModel
|
||||
|
||||
onSelfDestructClicked: {
|
||||
alertPopup.tokenCount = tokenCount
|
||||
|
@ -303,7 +304,7 @@ SettingsPageLayout {
|
|||
function signSelfRemoteDestructTransaction() {
|
||||
root.isFeeLoading = true
|
||||
root.feeText = ""
|
||||
root.remoteSelfDestructCollectibles(root.holdersModel,
|
||||
root.remoteSelfDestructCollectibles(d.tokenOwnersModel,
|
||||
d.chainId,
|
||||
d.accountName,
|
||||
d.accountAddress)
|
||||
|
@ -356,7 +357,6 @@ SettingsPageLayout {
|
|||
property int index // TODO: Update it to key when model has role key implemented
|
||||
|
||||
viewWidth: root.viewWidth
|
||||
holdersModel: root.holdersModel
|
||||
|
||||
Binding {
|
||||
target: root
|
||||
|
@ -364,9 +364,16 @@ SettingsPageLayout {
|
|||
value: view.name
|
||||
}
|
||||
|
||||
Binding {
|
||||
target: d
|
||||
property: "tokenOwnersModel"
|
||||
value: view.tokenOwnersModel
|
||||
}
|
||||
|
||||
Instantiator {
|
||||
id: instantiator
|
||||
|
||||
|
||||
model: SortFilterProxyModel {
|
||||
sourceModel: root.tokensModel
|
||||
filters: IndexFilter {
|
||||
|
@ -388,7 +395,8 @@ SettingsPageLayout {
|
|||
Bind { property: "chainId"; value: model.chainId },
|
||||
Bind { property: "chainName"; value: model.chainName },
|
||||
Bind { property: "chainIcon"; value: model.chainIcon },
|
||||
Bind { property: "accountName"; value: model.accountName }
|
||||
Bind { property: "accountName"; value: model.accountName },
|
||||
Bind { property: "tokenOwnersModel"; value: model.tokenOwnersModel }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ import shared.controls 1.0
|
|||
Control {
|
||||
id: root
|
||||
|
||||
// Expected roles: ensName, walletAddress, imageSource, amount, selfDestructAmount and selfDestruct
|
||||
// Expected roles: name, walletAddress, imageSource, amount, selfDestructAmount and selfDestruct
|
||||
property var model
|
||||
|
||||
property string tokenName
|
||||
|
@ -42,7 +42,7 @@ Control {
|
|||
enabled: searcher.enabled
|
||||
expression: {
|
||||
searcher.text
|
||||
return model.ensName.toLowerCase().includes(searcher.text.toLowerCase()) ||
|
||||
return model.name.toLowerCase().includes(searcher.text.toLowerCase()) ||
|
||||
model.walletAddress.toLowerCase().includes(searcher.text.toLowerCase())
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ Control {
|
|||
bottomPadding: 0
|
||||
minimumHeight: 36 // by design
|
||||
maximumHeight: minimumHeight
|
||||
enabled: root.model.count > 0
|
||||
enabled: root.model && root.model.count > 0
|
||||
placeholderText: enabled ? qsTr("Search") : qsTr("No placeholders to search")
|
||||
}
|
||||
|
||||
|
@ -81,8 +81,8 @@ Control {
|
|||
spacing: Style.current.padding
|
||||
|
||||
StatusListItem {
|
||||
readonly property bool unknownHolder: model.ensName === ""
|
||||
readonly property string formattedTitle: unknownHolder ? "?" : model.ensName
|
||||
readonly property bool unknownHolder: model.name === ""
|
||||
readonly property string formattedTitle: unknownHolder ? "?" : model.name
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import StatusQ.Core 0.1
|
|||
import StatusQ.Controls 0.1
|
||||
import StatusQ.Popups.Dialog 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import StatusQ.Core.Utils 0.1
|
||||
|
||||
import AppLayouts.Chat.panels.communities 1.0
|
||||
|
||||
|
@ -36,11 +37,11 @@ StatusDialog {
|
|||
}
|
||||
|
||||
function calculateTotalTokensToDestruct() {
|
||||
tokenCount = 0
|
||||
d.tokenCount = 0
|
||||
for(var i = 0; i < tokenHoldersPanel.model.count; i ++) {
|
||||
var item = tokenHoldersPanel.model.get(i)
|
||||
var item = ModelUtils.get(tokenHoldersPanel.model, i)
|
||||
if(item.selfDestruct) {
|
||||
tokenCount += item.selfDestructAmount
|
||||
d.tokenCount += item.selfDestructAmount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -277,7 +277,6 @@ StatusSectionLayout {
|
|||
rootStore.communityTokensStore
|
||||
|
||||
tokensModel: root.community.communityTokens
|
||||
holdersModel: communityTokensStore.holdersModel
|
||||
layer1Networks: communityTokensStore.layer1Networks
|
||||
layer2Networks: communityTokensStore.layer2Networks
|
||||
testNetworks: communityTokensStore.testNetworks
|
||||
|
@ -303,7 +302,7 @@ StatusSectionLayout {
|
|||
}
|
||||
onSignSelfDestructTransactionOpened: communityTokensStore.computeSelfDestructFee(chainId)
|
||||
onRemoteSelfDestructCollectibles: {
|
||||
communityTokensStore.remoteSelfDestructCollectibles(holdersModel,
|
||||
communityTokensStore.remoteSelfDestructCollectibles(tokenOwnersModel,
|
||||
chainId,
|
||||
accountName,
|
||||
accountAddress)
|
||||
|
|
|
@ -16,7 +16,6 @@ StatusScrollView {
|
|||
|
||||
property int viewWidth: 560 // by design
|
||||
property bool preview: false
|
||||
property var holdersModel
|
||||
|
||||
// Collectible object properties:
|
||||
property alias artworkSource: image.source
|
||||
|
@ -31,6 +30,8 @@ StatusScrollView {
|
|||
property int chainId
|
||||
property string chainIcon
|
||||
property int deployState
|
||||
property var tokenOwnersModel
|
||||
|
||||
property alias accountName: accountBox.value
|
||||
|
||||
signal mintCollectible(url artworkSource,
|
||||
|
@ -248,11 +249,10 @@ StatusScrollView {
|
|||
}
|
||||
}
|
||||
|
||||
// Disabled until backend is ready (milestone 12)
|
||||
TokenHoldersPanel {
|
||||
visible: false//!root.preview
|
||||
visible: !root.preview
|
||||
tokenName: root.name
|
||||
model: root.holdersModel
|
||||
model: root.tokenOwnersModel
|
||||
Layout.topMargin: Style.current.padding
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
|
|
@ -13,48 +13,9 @@ QtObject {
|
|||
property var enabledNetworks: networksModule.enabled
|
||||
property var allNetworks: networksModule.all
|
||||
|
||||
// Token holders model: MOCKED DATA -> TODO: Update with real data
|
||||
readonly property var holdersModel: ListModel {
|
||||
|
||||
readonly property string image: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0BhCExPynn1gWf9bx498P7/
|
||||
nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
|
||||
|
||||
Component.onCompleted:
|
||||
append([
|
||||
{
|
||||
ensName: "carmen.eth",
|
||||
walletAddress: "0xb794f5450ba39494ce839613fffba74279579268",
|
||||
imageSource:image,
|
||||
amount: 3,
|
||||
selfDestructAmount: 0,
|
||||
selfDestruct: false
|
||||
},
|
||||
{
|
||||
ensName: "chris.eth",
|
||||
walletAddress: "0xb794f5ea0ba39494ce839613fffba74279579268",
|
||||
imageSource: image,
|
||||
amount: 2,
|
||||
selfDestructAmount: 0,
|
||||
selfDestruct: false
|
||||
},
|
||||
{
|
||||
ensName: "emily.eth",
|
||||
walletAddress: "0xb794f5ea0ba39494ce839613fffba74279579268",
|
||||
imageSource: image,
|
||||
amount: 2,
|
||||
selfDestructAmount: 0,
|
||||
selfDestruct: false
|
||||
},
|
||||
{
|
||||
ensName: "",
|
||||
walletAddress: "0xb794f5ea0ba39494ce839613fffba74279579268",
|
||||
imageSource: "",
|
||||
amount: 1,
|
||||
selfDestructAmount: 0,
|
||||
selfDestruct: false
|
||||
}
|
||||
])
|
||||
}
|
||||
signal deployFeeUpdated(var ethCurrency, var fiatCurrency, int error)
|
||||
signal deploymentStateChanged(string communityId, int status, string url)
|
||||
signal selfDestructFeeUpdated(string value) // TO BE REMOVED
|
||||
|
||||
// Minting tokens:
|
||||
function deployCollectible(communityId, accountAddress, name, symbol, description, supply,
|
||||
|
@ -65,10 +26,6 @@ QtObject {
|
|||
infiniteSupply, transferable, selfDestruct, chainId, artworkSource)
|
||||
}
|
||||
|
||||
signal deployFeeUpdated(var ethCurrency, var fiatCurrency, int error)
|
||||
signal deploymentStateChanged(string communityId, int status, string url)
|
||||
signal selfDestructFeeUpdated(string value) // TO BE REMOVED
|
||||
|
||||
readonly property Connections connections: Connections {
|
||||
target: communityTokensModuleInst
|
||||
function onDeployFeeUpdated(ethCurrency, fiatCurrency, errorCode) {
|
||||
|
|
Loading…
Reference in New Issue