feat(@desktop/community): Saving community tokens in database

Model with community tokens was moved to section_item - every section has its own model.
Every deployed smart contract is saved to database with "In Progress" state.
The app listenes to deployed transaction and updates contract state in database to "Failed" or "Deployed".
Corresponding model is updated.

Issue #9233
This commit is contained in:
Michal Iskierko 2023-01-29 14:33:58 +01:00 committed by Michał Iskierko
parent 4fca725b55
commit 147288b47b
21 changed files with 314 additions and 191 deletions

View File

@ -5,6 +5,7 @@ import ../../../core/signals/types
import ../../../core/eventemitter
import ../../../../app_service/service/community/service as community_service
import ../../../../app_service/service/contacts/service as contacts_service
import ../../../../app_service/service/community_tokens/service as community_tokens_service
type
Controller* = ref object of RootObj
@ -12,18 +13,21 @@ type
events: EventEmitter
communityService: community_service.Service
contactsService: contacts_service.Service
communityTokensService: community_tokens_service.Service
proc newController*(
delegate: io_interface.AccessInterface,
events: EventEmitter,
communityService: community_service.Service,
contactsService: contacts_service.Service,
communityTokensService: community_tokens_service.Service,
): Controller =
result = Controller()
result.delegate = delegate
result.events = events
result.communityService = communityService
result.contactsService = contactsService
result.communityTokensService = communityTokensService
proc delete*(self: Controller) =
discard
@ -223,3 +227,6 @@ proc requestExtractDiscordChannelsAndCategories*(self: Controller, filesToImport
proc requestCancelDiscordCommunityImport*(self: Controller, id: string) =
self.communityService.requestCancelDiscordCommunityImport(id)
proc getCommunityTokens*(self: Controller, communityId: string): seq[CommunityTokenDto] =
self.communityTokensService.getCommunityTokens(communityId)

View File

@ -1,7 +1,6 @@
import ./io_interface as minting_module_interface
import ../../../../../app_service/service/community_tokens/service as tokens_service
import ../../../../../app_service/service/community_tokens/dto/deployment_parameters
import ../../../../../app_service/service/community_tokens/service as community_tokens_service
import ../../../../core/signals/types
import ../../../../core/eventemitter
import ../../../shared_modules/keycard_popup/io_interface as keycard_shared_module
@ -13,17 +12,17 @@ type
Controller* = ref object of RootObj
mintingModule: minting_module_interface.AccessInterface
events: EventEmitter
tokensService: tokens_service.Service
communityTokensService: community_tokens_service.Service
proc newMintingController*(
mintingModule: minting_module_interface.AccessInterface,
events: EventEmitter,
tokensService: tokens_service.Service
communityTokensService: community_tokens_service.Service
): Controller =
result = Controller()
result.mintingModule = mintingModule
result.events = events
result.tokensService = tokensService
result.communityTokensService = communityTokensService
proc delete*(self: Controller) =
discard
@ -35,9 +34,12 @@ proc init*(self: Controller) =
return
self.mintingModule.onUserAuthenticated(args.password)
proc mintCollectibles*(self: Controller, addressFrom: string, password: string, deploymentParams: DeploymentParameters) =
self.tokensService.mintCollectibles(addressFrom, password, deploymentParams)
proc mintCollectibles*(self: Controller, communityId: string, addressFrom: string, password: string, deploymentParams: DeploymentParameters) =
self.communityTokensService.mintCollectibles(communityId, addressFrom, password, deploymentParams)
proc authenticateUser*(self: Controller, keyUid = "") =
let data = SharedKeycarModuleAuthenticationArgs(uniqueIdentifier: UNIQUE_MINT_COLLECTIBLES_MINTING_MODULE_IDENTIFIER, keyUid: keyUid)
self.events.emit(SIGNAL_SHARED_KEYCARD_MODULE_AUTHENTICATE_USER, data)
self.events.emit(SIGNAL_SHARED_KEYCARD_MODULE_AUTHENTICATE_USER, data)
proc getCommunityTokens*(self: Controller, communityId: string): seq[CommunityTokenDto] =
return self.communityTokensService.getCommunityTokens(communityId)

View File

@ -1,3 +1,5 @@
import ../../../../../app_service/service/community_tokens/dto/community_token
type
AccessInterface* {.pure inheritable.} = ref object of RootObj
@ -7,9 +9,9 @@ method delete*(self: AccessInterface) {.base.} =
method load*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method mintCollectible*(self: AccessInterface, address: string, name: string, symbol: string, description: string, supply: int, infiniteSupply: bool, transferable: bool,
method mintCollectible*(self: AccessInterface, communityId: string, address: string, name: string, symbol: string, description: string, supply: int, infiniteSupply: bool, transferable: bool,
selfDestruct: bool, network: string) {.base.} =
raise newException(ValueError, "No implementation available")
method onUserAuthenticated*(self: AccessInterface, password: string) {.base.} =
raise newException(ValueError, "No implementation available")
raise newException(ValueError, "No implementation available")

View File

@ -1,100 +0,0 @@
import strformat
type
TokenType* {.pure.} = enum
#ERC20,
ERC721
type
MintingState* {.pure.} = enum
InProgress,
Minted,
Failed
type
TokenItem* = ref object
tokenType: TokenType
tokenAddress: string
name: string
description: string
icon: string
supply: int
infiniteSupply: bool
transferable: bool
remoteSelfDestruct: bool
networkId: string
mintingState: MintingState
# TODO holders
proc initCollectibleTokenItem*(
tokenAddress: string,
name: string,
description: string,
icon: string,
supply: int,
infiniteSupply: bool,
transferable: bool,
remoteSelfDestruct: bool,
networkId: string,
mintingState: MintingState
): TokenItem =
result = TokenItem()
result.tokenType = TokenType.ERC721
result.tokenAddress = tokenAddress
result.name = name
result.description = description
result.icon = icon
result.supply = supply
result.infiniteSupply = infiniteSupply
result.transferable = transferable
result.remoteSelfDestruct = remoteSelfDestruct
result.networkId = networkId
result.mintingState = mintingState
proc `$`*(self: TokenItem): string =
result = fmt"""TokenItem(
tokenType: {$self.tokenType.int},
tokenAddress: {self.tokenAddress},
name: {self.name},
description: {self.description},
icon: {self.icon},
supply: {self.supply},
infiniteSupply: {self.infiniteSupply},
transferable: {self.transferable},
remoteSelfDestruct: {self.remoteSelfDestruct},
networkId: {self.networkId},
mintingState: {$self.mintingState.int}
]"""
proc getTokenType*(self: TokenItem): TokenType =
return self.tokenType
proc getTokenAddress*(self: TokenItem): string =
return self.tokenAddress
proc getName*(self: TokenItem): string =
return self.name
proc getDescription*(self: TokenItem): string =
return self.description
proc getIcon*(self: TokenItem): string =
return self.icon
proc getSupply*(self: TokenItem): int =
return self.supply
proc getInfiniteSupply*(self: TokenItem): bool =
return self.infiniteSupply
proc isTransferrable*(self: TokenItem): bool =
return self.transferable
proc isRemoteSelfDestruct*(self: TokenItem): bool =
return self.remoteSelfDestruct
proc getNetworkId*(self: TokenItem): string =
return self.networkId
proc getMintingState*(self: TokenItem): MintingState =
return self.mintingState

View File

@ -1,5 +1,5 @@
import NimQml, Tables
import token_item
import NimQml, Tables, strformat
import ../../../../../../app_service/service/community_tokens/dto/community_token
type
ModelRole {.pure.} = enum
@ -7,17 +7,16 @@ type
TokenAddress
Name
Description
Icon
Supply
InfiniteSupply
Transferable
RemoteSelfDestruct
NetworkId
MintingState
DeployState
QtObject:
type TokenModel* = ref object of QAbstractListModel
items*: seq[TokenItem]
items*: seq[CommunityTokenDto]
proc setup(self: TokenModel) =
self.QAbstractListModel.setup
@ -30,14 +29,31 @@ QtObject:
new(result, delete)
result.setup
proc updateDeployState*(self: TokenModel, contractAddress: string, deployState: DeployState) =
for i in 0 ..< self.items.len:
if(self.items[i].address == contractAddress):
self.items[i].deployState = deployState
let index = self.createIndex(i, 0, nil)
self.dataChanged(index, index, @[ModelRole.DeployState.int])
return
proc countChanged(self: TokenModel) {.signal.}
proc setItems*(self: TokenModel, items: seq[TokenItem]) =
proc setItems*(self: TokenModel, items: seq[CommunityTokenDto]) =
self.beginResetModel()
self.items = items
self.endResetModel()
self.countChanged()
proc appendItem*(self: TokenModel, item: CommunityTokenDto) =
let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete
self.beginInsertRows(parentModelIndex, self.items.len, self.items.len)
self.items.add(item)
self.endInsertRows()
self.countChanged()
proc getCount*(self: TokenModel): int {.slot.} =
self.items.len
@ -54,13 +70,12 @@ QtObject:
ModelRole.TokenAddress.int:"tokenAddress",
ModelRole.Name.int:"name",
ModelRole.Description.int:"description",
ModelRole.Icon.int:"icon",
ModelRole.Supply.int:"supply",
ModelRole.InfiniteSupply.int:"infiniteSupply",
ModelRole.Transferable.int:"transferable",
ModelRole.RemoteSelfDestruct.int:"remoteSelfDestruct",
ModelRole.NetworkId.int:"networkId",
ModelRole.MintingState.int:"mintingState",
ModelRole.DeployState.int:"deployState",
}.toTable
method data(self: TokenModel, index: QModelIndex, role: int): QVariant =
@ -72,25 +87,28 @@ QtObject:
let enumRole = role.ModelRole
case enumRole:
of ModelRole.TokenType:
result = newQVariant(item.getTokenType().int)
result = newQVariant(item.tokenType.int)
of ModelRole.TokenAddress:
result = newQVariant(item.getTokenAddress())
result = newQVariant(item.address)
of ModelRole.Name:
result = newQVariant(item.getName())
result = newQVariant(item.name)
of ModelRole.Description:
result = newQVariant(item.getDescription())
of ModelRole.Icon:
result = newQVariant(item.getIcon())
result = newQVariant(item.description)
of ModelRole.Supply:
result = newQVariant(item.getSupply())
result = newQVariant(item.supply)
of ModelRole.InfiniteSupply:
result = newQVariant(item.getInfiniteSupply())
result = newQVariant(item.infiniteSupply)
of ModelRole.Transferable:
result = newQVariant(item.isTransferrable())
result = newQVariant(item.transferable)
of ModelRole.RemoteSelfDestruct:
result = newQVariant(item.isRemoteSelfDestruct())
result = newQVariant(item.remoteSelfDestruct)
of ModelRole.NetworkId:
result = newQVariant(item.getNetworkId())
of ModelRole.MintingState:
result = newQVariant(item.getMintingState().int)
result = newQVariant(item.chainId)
of ModelRole.DeployState:
result = newQVariant(item.deployState.int)
proc `$`*(self: TokenModel): string =
for i in 0 ..< self.items.len:
result &= fmt"""TokenModel:
[{i}]:({$self.items[i]})
"""

View File

@ -1,12 +1,10 @@
import NimQml, json
import ../../../../../app_service/service/community_tokens/service as tokens_service
import ../../../../../app_service/service/community_tokens/dto/deployment_parameters
import ../../../../../app_service/service/community_tokens/service as community_tokens_service
import ../../../../core/eventemitter
import ../../../../global/global_singleton
import ../io_interface as parent_interface
import ./io_interface, ./view , ./controller
import ./models/token_item
export io_interface
@ -17,17 +15,18 @@ type
view: View
viewVariant: QVariant
tempAddressFrom: string
tempCommunityId: string
tempDeploymentParams: DeploymentParameters
proc newMintingModule*(
parent: parent_interface.AccessInterface,
events: EventEmitter,
tokensService: tokens_service.Service): Module =
communityTokensService: community_tokens_service.Service): Module =
result = Module()
result.parent = parent
result.view = newView(result)
result.viewVariant = newQVariant(result.view)
result.controller = controller.newMintingController(result, events, tokensService)
result.controller = controller.newMintingController(result, events, communityTokensService)
method delete*(self: Module) =
self.view.delete
@ -38,17 +37,11 @@ method load*(self: Module) =
singletonInstance.engine.setRootContextProperty("mintingModule", self.viewVariant)
self.controller.init()
self.view.load()
# tested data
var items: seq[TokenItem] = @[]
let tok1 = token_item.initCollectibleTokenItem("", "Collect1", "Desc1", "", 100, false, true, true, "", MintingState.Minted)
let tok2 = token_item.initCollectibleTokenItem("", "Collect2", "Desc2", "", 200, false, false, false, "", MintingState.Minted)
items.add(tok1)
items.add(tok2)
self.view.setItems(items)
method mintCollectible*(self: Module, fromAddress: string, name: string, symbol: string, description: string,
method mintCollectible*(self: Module, communityId: string, fromAddress: string, name: string, symbol: string, description: string,
supply: int, infiniteSupply: bool, transferable: bool, selfDestruct: bool, network: string) =
self.tempAddressFrom = fromAddress
self.tempCommunityId = communityId
self.tempDeploymentParams.name = name
self.tempDeploymentParams.symbol = symbol
self.tempDeploymentParams.description = description
@ -56,7 +49,6 @@ method mintCollectible*(self: Module, fromAddress: string, name: string, symbol:
self.tempDeploymentParams.infiniteSupply = infiniteSupply
self.tempDeploymentParams.transferable = transferable
self.tempDeploymentParams.remoteSelfDestruct = selfDestruct
#network not used now
if singletonInstance.userProfile.getIsKeycardUser():
let keyUid = singletonInstance.userProfile.getKeyUid()
self.controller.authenticateUser(keyUid)
@ -66,8 +58,9 @@ method mintCollectible*(self: Module, fromAddress: string, name: string, symbol:
method onUserAuthenticated*(self: Module, password: string) =
defer: self.tempAddressFrom = ""
defer: self.tempDeploymentParams = DeploymentParameters()
defer: self.tempCommunityId = ""
if password.len == 0:
discard
#TODO signalize somehow
else:
self.controller.mintCollectibles(self.tempAddressFrom, password, self.tempDeploymentParams)
self.controller.mintCollectibles(self.tempCommunityId, self.tempAddressFrom, password, self.tempDeploymentParams)

View File

@ -1,42 +1,26 @@
import NimQml, json, strutils, sequtils
import ./io_interface as minting_module_interface
import models/token_model
import models/token_item
QtObject:
type
View* = ref object of QObject
mintingModule: minting_module_interface.AccessInterface
model: TokenModel
modelVariant: QVariant
proc load*(self: View) =
discard
proc delete*(self: View) =
self.model.delete
self.modelVariant.delete
self.QObject.delete
proc newView*(mintingModule: minting_module_interface.AccessInterface): View =
new(result, delete)
result.QObject.setup
result.mintingModule = mintingModule
result.model = newTokenModel()
result.modelVariant = newQVariant(result.model)
proc mintCollectible*(self: View, fromAddress:string, name: string, symbol: string, description: string, supply: int, infiniteSupply: bool, transferable: bool, selfDestruct: bool, network: string) {.slot.} =
self.mintingModule.mintCollectible(fromAddress, name, symbol, description, supply, infiniteSupply, transferable, selfDestruct, network)
proc setItems*(self: View, items: seq[TokenItem]) =
self.model.setItems(items)
proc getModel(self: View): QVariant {.slot.} =
return self.modelVariant
QtProperty[QVariant] tokensModel:
read = getModel
proc mintCollectible*(self: View, communityId: string, fromAddress: string, name: string, symbol: string, description: string, supply: int, infiniteSupply: bool, transferable: bool, selfDestruct: bool, network: string) {.slot.} =
self.mintingModule.mintCollectible(communityId, fromAddress, name, symbol, description, supply, infiniteSupply, transferable, selfDestruct, network)

View File

@ -21,7 +21,7 @@ import ../../../core/eventemitter
import ../../../../app_service/common/types
import ../../../../app_service/service/community/service as community_service
import ../../../../app_service/service/contacts/service as contacts_service
import ../../../../app_service/service/community_tokens/service as tokens_service
import ../../../../app_service/service/community_tokens/service as community_tokens_service
import ../../../../app_service/service/chat/dto/chat
import ./minting/module as minting_module
@ -52,7 +52,7 @@ proc newModule*(
events: EventEmitter,
communityService: community_service.Service,
contactsService: contacts_service.Service,
tokensService: tokens_service.Service): Module =
communityTokensService: community_tokens_service.Service): Module =
result = Module()
result.delegate = delegate
result.view = newView(result)
@ -62,8 +62,9 @@ proc newModule*(
events,
communityService,
contactsService,
communityTokensService,
)
result.mintingModule = minting_module.newMintingModule(result, events, tokensService)
result.mintingModule = minting_module.newMintingModule(result, events, communityTokensService)
result.moduleLoaded = false
method delete*(self: Module) =
@ -143,6 +144,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)
)
method getCuratedCommunityItem(self: Module, c: CuratedCommunity): CuratedCommunityItem =

View File

@ -17,6 +17,7 @@ import ../../../app_service/service/gif/service as gif_service
import ../../../app_service/service/mailservers/service as mailservers_service
import ../../../app_service/service/privacy/service as privacy_service
import ../../../app_service/service/node/service as node_service
import ../../../app_service/service/community_tokens/service as community_tokens_service
import ../shared_models/section_item, io_interface
import ../shared_modules/keycard_popup/io_interface as keycard_shared_module
@ -42,6 +43,7 @@ type
privacyService: privacy_service.Service
mailserversService: mailservers_service.Service
nodeService: node_service.Service
communityTokensService: community_tokens_service.Service
activeSectionId: string
authenticateUserFlowRequestedBy: string
@ -61,6 +63,7 @@ proc newController*(delegate: io_interface.AccessInterface,
privacyService: privacy_service.Service,
mailserversService: mailservers_service.Service,
nodeService: node_service.Service,
communityTokensService: community_tokens_service.Service,
):
Controller =
result = Controller()
@ -77,6 +80,7 @@ proc newController*(delegate: io_interface.AccessInterface,
result.privacyService = privacyService
result.nodeService = nodeService
result.mailserversService = mailserversService
result.communityTokensService = communityTokensService
proc delete*(self: Controller) =
discard
@ -278,6 +282,14 @@ proc init*(self: Controller) =
self.events.on(SIGNAL_COMMUNITY_MY_REQUEST_ADDED) do(e: Args):
self.delegate.onMyRequestAdded();
self.events.on(SIGNAL_COMMUNITY_TOKEN_DEPLOYED) do(e: Args):
let args = CommunityTokenDeployedArgs(e)
self.delegate.onCommunityTokenDeployed(args.communityToken)
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.events.on(SIGNAL_SHARED_KEYCARD_MODULE_FLOW_TERMINATED) do(e: Args):
let args = SharedKeycarModuleFlowTerminatedArgs(e)
if args.uniqueIdentifier == UNIQUE_MAIN_MODULE_KEYCARD_SYNC_IDENTIFIER:
@ -389,3 +401,6 @@ proc getStatusForContactWithId*(self: Controller, publicKey: string): StatusUpda
proc getVerificationRequestFrom*(self: Controller, publicKey: string): VerificationRequest =
self.contactsService.getVerificationRequestFrom(publicKey)
proc getCommunityTokens*(self: Controller, communityId: string): seq[CommunityTokenDto] =
self.communityTokensService.getCommunityTokens(communityId)

View File

@ -8,6 +8,7 @@ import ../../../app_service/service/community/service as community_service
import ../../../app_service/service/message/service as message_service
import ../../../app_service/service/gif/service as gif_service
import ../../../app_service/service/mailservers/service as mailservers_service
import ../../../app_service/service/community_tokens/service as token_service
from ../../../app_service/common/types import StatusType
import ../../global/app_signals
@ -250,6 +251,12 @@ method tryKeycardSync*(self: AccessInterface, keyUid: string, pin: string) {.bas
method onSharedKeycarModuleKeycardSyncPurposeTerminated*(self: AccessInterface, lastStepInTheCurrentFlow: bool) {.base.} =
raise newException(ValueError, "No implementation available")
method onCommunityTokenDeployed*(self: AccessInterface, communityToken: CommunityTokenDto) {.base.} =
raise newException(ValueError, "No implementation available")
method onCommunityTokenDeployStateChanged*(self: AccessInterface, communityId: string, contractAddress: string, deployState: DeployState) {.base.} =
raise newException(ValueError, "No implementation available")
# This way (using concepts) is used only for the modules managed by AppController
type
DelegateInterface* = concept c

View File

@ -51,7 +51,7 @@ import ../../../app_service/service/devices/service as devices_service
import ../../../app_service/service/mailservers/service as mailservers_service
import ../../../app_service/service/gif/service as gif_service
import ../../../app_service/service/ens/service as ens_service
import ../../../app_service/service/community_tokens/service as tokens_service
import ../../../app_service/service/community_tokens/service as community_tokens_service
import ../../../app_service/service/network/service as network_service
import ../../../app_service/service/general/service as general_service
import ../../../app_service/service/keycard/service as keycard_service
@ -134,7 +134,7 @@ proc newModule*[T](
nodeService: node_service.Service,
gifService: gif_service.Service,
ensService: ens_service.Service,
tokensService: tokens_service.Service,
communityTokensService: community_tokens_service.Service,
networkService: network_service.Service,
generalService: general_service.Service,
keycardService: keycard_service.Service
@ -157,6 +157,7 @@ proc newModule*[T](
privacyService,
mailserversService,
nodeService,
communityTokensService
)
result.moduleLoaded = false
@ -191,7 +192,7 @@ proc newModule*[T](
result.stickersModule = stickers_module.newModule(result, events, stickersService, settingsService, walletAccountService, networkService, tokenService)
result.activityCenterModule = activity_center_module.newModule(result, events, activityCenterService, contactsService,
messageService, chatService, communityService)
result.communitiesModule = communities_module.newModule(result, events, communityService, contactsService, tokensService)
result.communitiesModule = communities_module.newModule(result, events, communityService, contactsService, communityTokensService)
result.appSearchModule = app_search_module.newModule(result, events, contactsService, chatService, communityService,
messageService)
result.nodeSectionModule = node_section_module.newModule(result, events, settingsService, nodeService, nodeConfigurationService)
@ -222,9 +223,11 @@ proc createChannelGroupItem[T](self: Module[T], c: ChannelGroupDto): SectionItem
let isCommunity = c.channelGroupType == ChannelGroupType.Community
var communityDetails: CommunityDto
var unviewedCount, mentionsCount: int
var communityTokens: seq[CommunityTokenDto]
if (isCommunity):
(unviewedCount, mentionsCount) = self.controller.getNumOfNotificationsForCommunity(c.id)
communityDetails = self.controller.getCommunityById(c.id)
communityTokens = self.controller.getCommunityTokens(c.id)
else:
let receivedContactRequests = self.controller.getContacts(ContactsGroup.IncomingPendingContactRequests)
(unviewedCount, mentionsCount) = self.controller.getNumOfNotificaitonsForChat()
@ -335,7 +338,8 @@ proc createChannelGroupItem[T](self: Module[T], c: ChannelGroupDto): SectionItem
requestToJoinId = requestDto.id
)
) else: @[],
c.encrypted
c.encrypted,
communityTokens
)
method load*[T](
@ -878,6 +882,16 @@ 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.} =
let item = self.view.model().getItemById(communityToken.communityId)
if item.id != "":
item.appendCommunityToken(communityToken)
method onCommunityTokenDeployStateChanged*[T](self: Module[T], communityId: string, contractAddress: string, deployState: DeployState) =
let item = self.view.model().getItemById(communityId)
if item.id != "":
item.updateCommunityTokenDeployState(contractAddress, deployState)
method contactUpdated*[T](self: Module[T], publicKey: string) =
let contactDetails = self.controller.getContactDetails(publicKey)
self.view.activeSection().updateMember(

View File

@ -23,6 +23,7 @@ QtObject:
proc pendingRequestsToJoinChanged*(self: ActiveSection) {.signal.}
proc pendingMemberRequestsChanged*(self: ActiveSection) {.signal.}
proc declinedMemberRequestsChanged*(self: ActiveSection) {.signal.}
proc communityTokensChanged*(self: ActiveSection) {.signal.}
proc setActiveSectionData*(self: ActiveSection, item: SectionItem) =
self.item = item
@ -31,6 +32,7 @@ QtObject:
self.pendingMemberRequestsChanged()
self.declinedMemberRequestsChanged()
self.pendingRequestsToJoinChanged()
self.communityTokensChanged()
proc getId*(self: ActiveSection): string {.slot.} =
return self.item.id
@ -197,6 +199,16 @@ QtObject:
read = bannedMembers
notify = bannedMembersChanged
proc communityTokens(self: ActiveSection): QVariant {.slot.} =
if (self.item.id == ""):
# FIXME (Jo) I don't know why but the Item is sometimes empty and doing anything here crashes the app
return newQVariant("")
return newQVariant(self.item.communityTokens)
QtProperty[QVariant] communityTokens:
read = communityTokens
notify = communityTokensChanged
proc amIBanned(self: ActiveSection): bool {.slot.} =
return self.item.amIBanned

View File

@ -1,9 +1,11 @@
import strformat
import ./member_model, ./member_item
import ../main/communities/models/[pending_request_item, pending_request_model]
import ../main/communities/minting/models/token_model as community_tokens_model
import ../../global/global_singleton
import ../../../app_service/common/types
import ../../../app_service/service/community_tokens/dto/community_token
type
SectionType* {.pure.} = enum
@ -51,6 +53,7 @@ type
pendingMemberRequestsModel: member_model.Model
declinedMemberRequestsModel: member_model.Model
encrypted: bool
communityTokensModel: community_tokens_model.TokenModel
proc initItem*(
id: string,
@ -86,6 +89,7 @@ proc initItem*(
pendingMemberRequests: seq[MemberItem] = @[],
declinedMemberRequests: seq[MemberItem] = @[],
encrypted: bool = false,
communityTokens: seq[CommunityTokenDto] = @[],
): SectionItem =
result.id = id
result.sectionType = sectionType
@ -125,6 +129,8 @@ proc initItem*(
result.declinedMemberRequestsModel = newModel()
result.declinedMemberRequestsModel.setItems(declinedMemberRequests)
result.encrypted = encrypted
result.communityTokensModel = newTokenModel()
result.communityTokensModel.setItems(communityTokens)
proc isEmpty*(self: SectionItem): bool =
return self.id.len == 0
@ -163,6 +169,7 @@ proc `$`*(self: SectionItem): string =
pendingMemberRequests:{self.pendingMemberRequestsModel},
declinedMemberRequests:{self.declinedMemberRequestsModel},
encrypted:{self.encrypted},
communityTokensModel:{self.communityTokensModel},
]"""
proc id*(self: SectionItem): string {.inline.} =
@ -302,3 +309,12 @@ proc pinMessageAllMembersEnabled*(self: SectionItem): bool {.inline.} =
proc encrypted*(self: SectionItem): bool {.inline.} =
self.encrypted
proc appendCommunityToken*(self: SectionItem, item: CommunityTokenDto) {.inline.} =
self.communityTokensModel.appendItem(item)
proc updateCommunityTokenDeployState*(self: SectionItem, contractAddress: string, deployState: DeployState) {.inline.} =
self.communityTokensModel.updateDeployState(contractAddress, deployState)
proc communityTokens*(self: SectionItem): community_tokens_model.TokenModel {.inline.} =
self.communityTokensModel

View File

@ -3,6 +3,8 @@ import NimQml, Tables, strutils, strformat
import json, json_serialization
import section_item, member_model
import ../../../app_service/service/community_tokens/dto/community_token
type
ModelRole {.pure.} = enum
@ -37,6 +39,7 @@ type
PinMessageAllMembersEnabled
BannedMembersModel
Encrypted
CommunityTokensModel
QtObject:
type
@ -105,6 +108,7 @@ QtObject:
ModelRole.PinMessageAllMembersEnabled.int:"pinMessageAllMembersEnabled",
ModelRole.BannedMembersModel.int:"bannedMembers",
ModelRole.Encrypted.int:"encrypted",
ModelRole.CommunityTokensModel.int:"communityTokens",
}.toTable
method data(self: SectionModel, index: QModelIndex, role: int): QVariant =
@ -180,6 +184,8 @@ QtObject:
result = newQVariant(item.bannedMembers)
of ModelRole.Encrypted:
result = newQVariant(item.encrypted)
of ModelRole.CommunityTokensModel:
result = newQVariant(item.communityTokens)
proc isItemExist(self: SectionModel, id: string): bool =
for it in self.items:
@ -272,6 +278,7 @@ QtObject:
ModelRole.PinMessageAllMembersEnabled.int,
ModelRole.BannedMembersModel.int,
ModelRole.Encrypted.int,
ModelRole.CommunityTokensModel.int
])
proc getNthEnabledItem*(self: SectionModel, nth: int): SectionItem =
@ -359,6 +366,14 @@ QtObject:
self.notificationsCountChanged()
return
proc appendCommunityToken*(self: SectionModel, id: string, item: CommunityTokenDto) =
for i in 0 ..< self.items.len:
if(self.items[i].id == id):
let index = self.createIndex(i, 0, nil)
self.items[i].appendCommunityToken(item)
self.dataChanged(index, index, @[ModelRole.CommunityTokensModel.int])
return
proc getSectionNameById*(self: SectionModel, sectionId: string): string {.slot.} =
for item in self.items:
if item.id == sectionId:

View File

@ -0,0 +1,75 @@
import json, json, sequtils
import ../../../../backend/response_type
include ../../../common/json_utils
import ../../../common/conversion
type
TokenType* {.pure.} = enum
ERC721
#ERC20
type
DeployState* {.pure.} = enum
Failed,
InProgress,
Deployed
type
CommunityTokenDto* = object
tokenType*: TokenType
communityId*: string
address*: string
name*: string
symbol*: string
description*: string
supply*: int
infiniteSupply*: bool
transferable*: bool
remoteSelfDestruct*: bool
tokenUri*: string
chainId*: int
deployState*: DeployState
image*: string
proc toJsonNode*(self: CommunityTokenDto): JsonNode =
result = %* {
"tokenType": self.tokenType.int,
"communityId": self.communityId,
"address": self.address,
"name": self.name,
"symbol": self.symbol,
"description": self.description,
"supply": self.supply,
"infiniteSupply": self.infiniteSupply,
"transferable": self.transferable,
"remoteSelfDestruct": self.remoteSelfDestruct,
"tokenUri": self.tokenUri,
"chainId": self.chainId,
"deployState": self.deployState.int,
"image": self.image
}
proc toCommunityTokenDto*(jsonObj: JsonNode): CommunityTokenDto =
result = CommunityTokenDto()
var tokenTypeInt: int
discard jsonObj.getProp("tokenType", tokenTypeInt)
result.tokenType = intToEnum(tokenTypeInt, TokenType.ERC721)
discard jsonObj.getProp("communityId", result.communityId)
discard jsonObj.getProp("address", result.address)
discard jsonObj.getProp("name", result.name)
discard jsonObj.getProp("symbol", result.symbol)
discard jsonObj.getProp("description", result.description)
discard jsonObj.getProp("supply", result.supply)
discard jsonObj.getProp("infiniteSupply", result.infiniteSupply)
discard jsonObj.getProp("transferable", result.transferable)
discard jsonObj.getProp("remoteSelfDestruct", result.remoteSelfDestruct)
discard jsonObj.getProp("tokenUri", result.tokenUri)
discard jsonObj.getProp("chainId", result.chainId)
var deployStateInt: int
discard jsonObj.getProp("deployState", deployStateInt)
result.deployState = intToEnum(deployStateInt, DeployState.Failed)
discard jsonObj.getProp("image", result.image)
proc parseCommunityTokens*(response: RpcResponse[JsonNode]): seq[CommunityTokenDto] =
result = map(response.result.getElems(),
proc(x: JsonNode): CommunityTokenDto = x.toCommunityTokenDto())

View File

@ -1,4 +1,4 @@
import NimQml, Tables, chronicles, sequtils, json, sugar, stint
import NimQml, Tables, chronicles, json, stint
import ../../../app/core/eventemitter
import ../../../app/core/tasks/[qt, threadpool]
@ -10,16 +10,31 @@ import ../eth/dto/transaction
import ../../../backend/response_type
import ../../common/json_utils
import ../../common/conversion
import ./dto/deployment_parameters
import ./dto/community_token
#include async_tasks
export community_token
export deployment_parameters
logScope:
topics = "community-tokens-service"
type
CommunityTokenDeployedStatusArgs* = ref object of Args
communityId*: string
contractAddress*: string
deployState*: DeployState
type
CommunityTokenDeployedArgs* = ref object of Args
communityToken*: CommunityTokenDto
# Signals which may be emitted by this service:
const SIGNAL_COMMUNITY_TOKEN_DEPLOY_STATUS* = "communityTokenDeployStatus"
const SIGNAL_COMMUNITY_TOKEN_DEPLOYED* = "communityTokenDeployed"
QtObject:
type
Service* = ref object of QObject
@ -47,32 +62,66 @@ QtObject:
proc init*(self: Service) =
self.events.on(PendingTransactionTypeDto.CollectibleDeployment.event) do(e: Args):
var receivedData = TransactionMinedArgs(e)
# TODO signalize module about about contract state
if receivedData.success:
echo "!!! Collectible deployed"
else:
echo "!!! Collectible not deployed"
let deployState = if receivedData.success: DeployState.Deployed else: DeployState.Failed
let tokenDto = toCommunityTokenDto(parseJson(receivedData.data))
if not receivedData.success:
error "Collectible contract not deployed", address=tokenDto.address
try:
discard updateCommunityTokenState(tokenDto.address, deployState) #update db state
except RpcException:
error "Error updating collectibles contract state", message = getCurrentExceptionMsg()
let data = CommunityTokenDeployedStatusArgs(communityId: tokenDto.communityId, contractAddress: tokenDto.address, deployState: deployState)
self.events.emit(SIGNAL_COMMUNITY_TOKEN_DEPLOY_STATUS, data)
proc mintCollectibles*(self: Service, addressFrom: string, password: string, deploymentParams: DeploymentParameters) =
proc mintCollectibles*(self: Service, communityId: string, addressFrom: string, password: string, deploymentParams: DeploymentParameters) =
try:
let chainId = self.networkService.getNetworkForCollectibles().chainId
let txData = TransactionDataDto(source: parseAddress(addressFrom))
let response = tokens_backend.deployCollectibles(chainId, %deploymentParams, %txData, password)
if (not response.error.isNil):
error "Error minting collectibles", message = response.error.message
return
let contractAddress = response.result["contractAddress"].getStr()
let transactionHash = response.result["transactionHash"].getStr()
echo "!!! Contract address ", contractAddress
echo "!!! Transaction hash ", transactionHash
var communityToken: CommunityTokenDto
communityToken.tokenType = TokenType.ERC721
communityToken.communityId = communityId
communityToken.address = contractAddress
communityToken.name = deploymentParams.name
communityToken.symbol = deploymentParams.symbol
communityToken.description = deploymentParams.description
communityToken.supply = deploymentParams.supply
communityToken.infiniteSupply = deploymentParams.infiniteSupply
communityToken.transferable = deploymentParams.transferable
communityToken.remoteSelfDestruct = deploymentParams.remoteSelfDestruct
communityToken.tokenUri = deploymentParams.tokenUri
communityToken.chainId = chainId
communityToken.deployState = DeployState.InProgress
communityToken.image = "" # TODO later
# save token to db
discard tokens_backend.addCommunityToken(communityToken)
let data = CommunityTokenDeployedArgs(communityToken: communityToken)
self.events.emit(SIGNAL_COMMUNITY_TOKEN_DEPLOYED, data)
# observe transaction state
self.transactionService.watchTransaction(
transactionHash,
addressFrom,
contractAddress,
$PendingTransactionTypeDto.CollectibleDeployment,
"",
$communityToken.toJsonNode(),
chainId,
)
except RpcException:
error "Error minting collectibles", message = getCurrentExceptionMsg()
proc getCommunityTokens*(self: Service, communityId: string): seq[CommunityTokenDto] =
try:
let chainId = self.networkService.getNetworkForCollectibles().chainId
let response = tokens_backend.getCommunityTokens(communityId, chainId)
return parseCommunityTokens(response)
except RpcException:
error "Error getting community tokens", message = getCurrentExceptionMsg()

View File

@ -2,7 +2,20 @@ import json
import ./eth
import ../app_service/common/utils
import ./core, ./response_type
import ../app_service/service/community_tokens/dto/community_token
proc deployCollectibles*(chainId: int, deploymentParams: JsonNode, txData: JsonNode, password: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [chainId, deploymentParams, txData, utils.hashPassword(password)]
return core.callPrivateRPC("collectibles_deploy", payload)
proc getCommunityTokens*(communityId: string, chainId: int): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [communityId, chainId]
return core.callPrivateRPC("wakuext_getCommunityTokens", payload)
proc addCommunityToken*(token: CommunityTokenDto): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [token.toJsonNode()]
return core.callPrivateRPC("wakuext_addCommunityToken", payload)
proc updateCommunityTokenState*(contractAddress: string, deployState: DeployState): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [contractAddress, deployState.int]
return core.callPrivateRPC("wakuext_updateCommunityTokenState", payload)

View File

@ -93,7 +93,7 @@ Item {
model: root.tokensModel
delegate: Text {
text: "name: " + name + ", descr: " + description + ", supply: " + supply
text: "name: " + name + ", descr: " + description + ", supply: " + supply + ", status: " + deployState
}
}
}

View File

@ -177,12 +177,11 @@ QtObject {
}
// Minting tokens:
property var mintTokensModel: mintingModuleInst ? mintingModuleInst.tokensModel : null
function mintCollectible(address, name, symbol, description, supply,
function mintCollectible(communityId, address, name, symbol, description, supply,
infiniteSupply, transferable, selfDestruct, network)
{
mintingModuleInst.mintCollectible(address, name, symbol, description, supply,
mintingModuleInst.mintCollectible(communityId, address, name, symbol, description, supply,
infiniteSupply, transferable, selfDestruct, network)
}
}

View File

@ -255,9 +255,9 @@ StatusSectionLayout {
CommunityMintTokensSettingsPanel {
transactionStore: root.transactionStore
tokensModel: root.communityStore.mintTokensModel
tokensModel: root.community.communityTokens
onMintCollectible: {
root.communityStore.mintCollectible(address, name, symbol, description, supply,
root.communityStore.mintCollectible(root.community.id, address, name, symbol, description, supply,
infiniteSupply, transferable, selfDestruct, network)
}
onPreviousPageNameChanged: root.backButtonName = previousPageName