feat(@desktop:communities): Minting functionality with dummy data
Add Community Tokens testing UI with minting button, enabled by a Advanced Settings toggle. Add minting module,view and needed models. Add community_tokens service to call collectibles smart contract functions. Issue #8921
This commit is contained in:
parent
a12e599be2
commit
b6f5c558a9
|
@ -31,6 +31,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/common/account_constants
|
||||
|
||||
import ../modules/startup/module as startup_module
|
||||
|
@ -95,6 +96,7 @@ type
|
|||
nodeService: node_service.Service
|
||||
gifService: gif_service.Service
|
||||
ensService: ens_service.Service
|
||||
tokensService: tokens_service.Service
|
||||
|
||||
# Modules
|
||||
startupModule: startup_module.AccessInterface
|
||||
|
@ -209,6 +211,8 @@ proc newAppController*(statusFoundation: StatusFoundation): AppController =
|
|||
result.ensService = ens_service.newService(statusFoundation.events, statusFoundation.threadpool,
|
||||
result.settingsService, result.walletAccountService, result.transactionService,
|
||||
result.networkService, result.tokenService)
|
||||
result.tokensService = tokens_service.newService(statusFoundation.events, statusFoundation.threadpool,
|
||||
result.networkService, result.transactionService)
|
||||
result.providerService = provider_service.newService(statusFoundation.events, statusFoundation.threadpool, result.ensService)
|
||||
|
||||
# Modules
|
||||
|
@ -254,6 +258,7 @@ proc newAppController*(statusFoundation: StatusFoundation): AppController =
|
|||
result.nodeService,
|
||||
result.gifService,
|
||||
result.ensService,
|
||||
result.tokensService,
|
||||
result.networkService,
|
||||
result.generalService,
|
||||
result.keycardService
|
||||
|
@ -309,6 +314,7 @@ proc delete*(self: AppController) =
|
|||
self.profileService.delete
|
||||
self.generalService.delete
|
||||
self.ensService.delete
|
||||
self.tokensService.delete
|
||||
self.gifService.delete
|
||||
self.keycardService.delete
|
||||
|
||||
|
@ -397,6 +403,7 @@ proc load(self: AppController) =
|
|||
self.aboutService.init()
|
||||
self.devicesService.init()
|
||||
self.ensService.init()
|
||||
self.tokensService.init()
|
||||
self.gifService.init()
|
||||
|
||||
# Accessible after user login
|
||||
|
|
|
@ -10,6 +10,8 @@ const LSS_KEY_IS_WALLET_ENABLED* = "isExperimentalWalletEnabled"
|
|||
const DEFAULT_IS_WALLET_ENABLED = false
|
||||
const LSS_KEY_IS_COMMUNITY_PERMISSIONS_ENABLED* = "isExperimentalCommunityPermissionsEnabled"
|
||||
const DEFAULT_IS_COMMUNITY_PERMISSIONS_ENABLED = false
|
||||
const LSS_KEY_IS_COMMUNITY_TOKENS_ENABLED* = "isExperimentalCommunityTokensEnabled"
|
||||
const DEFAULT_IS_COMMUNITY_TOKENS_ENABLED = false
|
||||
const LSS_KEY_NODE_MANAGEMENT_ENABLED* = "nodeManagementEnabled"
|
||||
const DEFAULT_NODE_MANAGEMENT_ENABLED = false
|
||||
const LSS_KEY_IS_BROWSER_ENABLED* = "isExperimentalBrowserEnabled"
|
||||
|
@ -239,6 +241,18 @@ QtObject:
|
|||
write = setIsCommunityPermissionsEnabled
|
||||
notify = isCommunityPermissionsEnabledChanged
|
||||
|
||||
proc isCommunityTokensEnabledChanged*(self: LocalAccountSensitiveSettings) {.signal.}
|
||||
proc getIsCommunityTokensEnabled*(self: LocalAccountSensitiveSettings): bool {.slot.} =
|
||||
getSettingsProp[bool](self, LSS_KEY_IS_COMMUNITY_TOKENS_ENABLED, newQVariant(DEFAULT_IS_COMMUNITY_TOKENS_ENABLED))
|
||||
proc setIsCommunityTokensEnabled*(self: LocalAccountSensitiveSettings, value: bool) {.slot.} =
|
||||
setSettingsProp(self, LSS_KEY_IS_COMMUNITY_TOKENS_ENABLED, newQVariant(value)):
|
||||
self.isCommunityTokensEnabledChanged()
|
||||
|
||||
QtProperty[bool] isCommunityTokensEnabled:
|
||||
read = getIsCommunityTokensEnabled
|
||||
write = setIsCommunityTokensEnabled
|
||||
notify = isCommunityTokensEnabledChanged
|
||||
|
||||
proc isWalletEnabledChanged*(self: LocalAccountSensitiveSettings) {.signal.}
|
||||
proc getIsWalletEnabled*(self: LocalAccountSensitiveSettings): bool {.slot.} =
|
||||
getSettingsProp[bool](self, LSS_KEY_IS_WALLET_ENABLED, newQVariant(DEFAULT_IS_WALLET_ENABLED))
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
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 ../../../../core/signals/types
|
||||
import ../../../../core/eventemitter
|
||||
import ../../../shared_modules/keycard_popup/io_interface as keycard_shared_module
|
||||
|
||||
|
||||
const UNIQUE_MINT_COLLECTIBLES_MINTING_MODULE_IDENTIFIER* = "MintingModule-MintCollectibles"
|
||||
|
||||
type
|
||||
Controller* = ref object of RootObj
|
||||
mintingModule: minting_module_interface.AccessInterface
|
||||
events: EventEmitter
|
||||
tokensService: tokens_service.Service
|
||||
|
||||
proc newMintingController*(
|
||||
mintingModule: minting_module_interface.AccessInterface,
|
||||
events: EventEmitter,
|
||||
tokensService: tokens_service.Service
|
||||
): Controller =
|
||||
result = Controller()
|
||||
result.mintingModule = mintingModule
|
||||
result.events = events
|
||||
result.tokensService = tokensService
|
||||
|
||||
proc delete*(self: Controller) =
|
||||
discard
|
||||
|
||||
proc init*(self: Controller) =
|
||||
self.events.on(SIGNAL_SHARED_KEYCARD_MODULE_USER_AUTHENTICATED) do(e: Args):
|
||||
let args = SharedKeycarModuleArgs(e)
|
||||
if args.uniqueIdentifier != UNIQUE_MINT_COLLECTIBLES_MINTING_MODULE_IDENTIFIER:
|
||||
return
|
||||
self.mintingModule.onUserAuthenticated(args.password)
|
||||
|
||||
proc mintCollectibles*(self: Controller, addressFrom: string, password: string, deploymentParams: DeploymentParameters) =
|
||||
self.tokensService.mintCollectibles(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)
|
|
@ -0,0 +1,15 @@
|
|||
type
|
||||
AccessInterface* {.pure inheritable.} = ref object of RootObj
|
||||
|
||||
method delete*(self: AccessInterface) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
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,
|
||||
selfDestruct: bool, network: string) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method onUserAuthenticated*(self: AccessInterface, password: string) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
|
@ -0,0 +1,100 @@
|
|||
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
|
|
@ -0,0 +1,96 @@
|
|||
import NimQml, Tables
|
||||
import token_item
|
||||
|
||||
type
|
||||
ModelRole {.pure.} = enum
|
||||
TokenType = UserRole + 1
|
||||
TokenAddress
|
||||
Name
|
||||
Description
|
||||
Icon
|
||||
Supply
|
||||
InfiniteSupply
|
||||
Transferable
|
||||
RemoteSelfDestruct
|
||||
NetworkId
|
||||
MintingState
|
||||
|
||||
QtObject:
|
||||
type TokenModel* = ref object of QAbstractListModel
|
||||
items*: seq[TokenItem]
|
||||
|
||||
proc setup(self: TokenModel) =
|
||||
self.QAbstractListModel.setup
|
||||
|
||||
proc delete(self: TokenModel) =
|
||||
self.items = @[]
|
||||
self.QAbstractListModel.delete
|
||||
|
||||
proc newTokenModel*(): TokenModel =
|
||||
new(result, delete)
|
||||
result.setup
|
||||
|
||||
proc countChanged(self: TokenModel) {.signal.}
|
||||
|
||||
proc setItems*(self: TokenModel, items: seq[TokenItem]) =
|
||||
self.beginResetModel()
|
||||
self.items = items
|
||||
self.endResetModel()
|
||||
self.countChanged()
|
||||
|
||||
proc getCount*(self: TokenModel): int {.slot.} =
|
||||
self.items.len
|
||||
|
||||
QtProperty[int] count:
|
||||
read = getCount
|
||||
notify = countChanged
|
||||
|
||||
method rowCount(self: TokenModel, index: QModelIndex = nil): int =
|
||||
return self.items.len
|
||||
|
||||
method roleNames(self: TokenModel): Table[int, string] =
|
||||
{
|
||||
ModelRole.TokenType.int:"tokenType",
|
||||
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",
|
||||
}.toTable
|
||||
|
||||
method data(self: TokenModel, 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.TokenType:
|
||||
result = newQVariant(item.getTokenType().int)
|
||||
of ModelRole.TokenAddress:
|
||||
result = newQVariant(item.getTokenAddress())
|
||||
of ModelRole.Name:
|
||||
result = newQVariant(item.getName())
|
||||
of ModelRole.Description:
|
||||
result = newQVariant(item.getDescription())
|
||||
of ModelRole.Icon:
|
||||
result = newQVariant(item.getIcon())
|
||||
of ModelRole.Supply:
|
||||
result = newQVariant(item.getSupply())
|
||||
of ModelRole.InfiniteSupply:
|
||||
result = newQVariant(item.getInfiniteSupply())
|
||||
of ModelRole.Transferable:
|
||||
result = newQVariant(item.isTransferrable())
|
||||
of ModelRole.RemoteSelfDestruct:
|
||||
result = newQVariant(item.isRemoteSelfDestruct())
|
||||
of ModelRole.NetworkId:
|
||||
result = newQVariant(item.getNetworkId())
|
||||
of ModelRole.MintingState:
|
||||
result = newQVariant(item.getMintingState().int)
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
import NimQml, json
|
||||
|
||||
import ../../../../../app_service/service/community_tokens/service as tokens_service
|
||||
import ../../../../../app_service/service/community_tokens/dto/deployment_parameters
|
||||
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
|
||||
|
||||
type
|
||||
Module* = ref object of io_interface.AccessInterface
|
||||
parent: parent_interface.AccessInterface
|
||||
controller: Controller
|
||||
view: View
|
||||
viewVariant: QVariant
|
||||
tempAddressFrom: string
|
||||
tempDeploymentParams: DeploymentParameters
|
||||
|
||||
proc newMintingModule*(
|
||||
parent: parent_interface.AccessInterface,
|
||||
events: EventEmitter,
|
||||
tokensService: 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)
|
||||
|
||||
method delete*(self: Module) =
|
||||
self.view.delete
|
||||
self.viewVariant.delete
|
||||
self.controller.delete
|
||||
|
||||
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,
|
||||
supply: int, infiniteSupply: bool, transferable: bool, selfDestruct: bool, network: string) =
|
||||
self.tempAddressFrom = fromAddress
|
||||
self.tempDeploymentParams.name = name
|
||||
self.tempDeploymentParams.symbol = symbol
|
||||
self.tempDeploymentParams.description = description
|
||||
self.tempDeploymentParams.supply = supply
|
||||
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)
|
||||
else:
|
||||
self.controller.authenticateUser()
|
||||
|
||||
method onUserAuthenticated*(self: Module, password: string) =
|
||||
defer: self.tempAddressFrom = ""
|
||||
defer: self.tempDeploymentParams = DeploymentParameters()
|
||||
if password.len == 0:
|
||||
discard
|
||||
#TODO signalize somehow
|
||||
else:
|
||||
self.controller.mintCollectibles(self.tempAddressFrom, password, self.tempDeploymentParams)
|
|
@ -0,0 +1,43 @@
|
|||
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
|
||||
|
||||
|
||||
|
||||
|
|
@ -21,7 +21,9 @@ 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/chat/dto/chat
|
||||
import ./minting/module as minting_module
|
||||
|
||||
export io_interface
|
||||
|
||||
|
@ -38,6 +40,7 @@ type
|
|||
view: View
|
||||
viewVariant: QVariant
|
||||
moduleLoaded: bool
|
||||
mintingModule: minting_module.AccessInterface
|
||||
|
||||
# Forward declaration
|
||||
method setCommunityTags*(self: Module, communityTags: string)
|
||||
|
@ -48,7 +51,8 @@ proc newModule*(
|
|||
delegate: delegate_interface.AccessInterface,
|
||||
events: EventEmitter,
|
||||
communityService: community_service.Service,
|
||||
contactsService: contacts_service.Service): Module =
|
||||
contactsService: contacts_service.Service,
|
||||
tokensService: tokens_service.Service): Module =
|
||||
result = Module()
|
||||
result.delegate = delegate
|
||||
result.view = newView(result)
|
||||
|
@ -59,16 +63,19 @@ proc newModule*(
|
|||
communityService,
|
||||
contactsService,
|
||||
)
|
||||
result.mintingModule = minting_module.newMintingModule(result, events, tokensService)
|
||||
result.moduleLoaded = false
|
||||
|
||||
method delete*(self: Module) =
|
||||
self.view.delete
|
||||
self.viewVariant.delete
|
||||
self.controller.delete
|
||||
self.mintingModule.delete
|
||||
|
||||
method load*(self: Module) =
|
||||
singletonInstance.engine.setRootContextProperty("communitiesModule", self.viewVariant)
|
||||
self.controller.init()
|
||||
self.mintingModule.load()
|
||||
self.view.load()
|
||||
|
||||
method isLoaded*(self: Module): bool =
|
||||
|
|
|
@ -51,6 +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/network/service as network_service
|
||||
import ../../../app_service/service/general/service as general_service
|
||||
import ../../../app_service/service/keycard/service as keycard_service
|
||||
|
@ -132,6 +133,7 @@ proc newModule*[T](
|
|||
nodeService: node_service.Service,
|
||||
gifService: gif_service.Service,
|
||||
ensService: ens_service.Service,
|
||||
tokensService: tokens_service.Service,
|
||||
networkService: network_service.Service,
|
||||
generalService: general_service.Service,
|
||||
keycardService: keycard_service.Service
|
||||
|
@ -187,7 +189,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)
|
||||
result.communitiesModule = communities_module.newModule(result, events, communityService, contactsService, tokensService)
|
||||
result.appSearchModule = app_search_module.newModule(result, events, contactsService, chatService, communityService,
|
||||
messageService)
|
||||
result.nodeSectionModule = node_section_module.newModule(result, events, settingsService, nodeService, nodeConfigurationService)
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
import json, stint
|
||||
|
||||
type
|
||||
DeploymentParameters* = object
|
||||
name*: string
|
||||
symbol*: string
|
||||
supply*: int
|
||||
infiniteSupply*: bool
|
||||
transferable*: bool
|
||||
remoteSelfDestruct*: bool
|
||||
tokenUri*: string
|
||||
description*: string # not part of smart contract
|
||||
|
||||
proc `%`*(x: DeploymentParameters): JsonNode =
|
||||
result = newJobject()
|
||||
result["name"] = %x.name
|
||||
result["symbol"] = %x.symbol
|
||||
result["supply"] = %x.supply
|
||||
result["infiniteSupply"] = %x.infiniteSupply
|
||||
result["transferable"] = %x.transferable
|
||||
result["remoteSelfDestruct"] = %x.remoteSelfDestruct
|
||||
result["tokenUri"] = %x.tokenUri
|
||||
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
import NimQml, Tables, chronicles, sequtils, json, sugar, stint
|
||||
import ../../../app/core/eventemitter
|
||||
import ../../../app/core/tasks/[qt, threadpool]
|
||||
|
||||
import ../../../backend/community_tokens as tokens_backend
|
||||
import ../network/service as network_service
|
||||
import ../transaction/service as transaction_service
|
||||
|
||||
import ../eth/dto/transaction
|
||||
|
||||
import ../../../backend/response_type
|
||||
|
||||
import ../../common/json_utils
|
||||
import ../../common/conversion
|
||||
|
||||
import ./dto/deployment_parameters
|
||||
|
||||
#include async_tasks
|
||||
|
||||
logScope:
|
||||
topics = "community-tokens-service"
|
||||
|
||||
QtObject:
|
||||
type
|
||||
Service* = ref object of QObject
|
||||
events: EventEmitter
|
||||
threadpool: ThreadPool
|
||||
networkService: network_service.Service
|
||||
transactionService: transaction_service.Service
|
||||
|
||||
proc delete*(self: Service) =
|
||||
self.QObject.delete
|
||||
|
||||
proc newService*(
|
||||
events: EventEmitter,
|
||||
threadpool: ThreadPool,
|
||||
networkService: network_service.Service,
|
||||
transactionService: transaction_service.Service
|
||||
): Service =
|
||||
result = Service()
|
||||
result.QObject.setup
|
||||
result.events = events
|
||||
result.threadpool = threadpool
|
||||
result.networkService = networkService
|
||||
result.transactionService = transactionService
|
||||
|
||||
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"
|
||||
|
||||
proc mintCollectibles*(self: Service, 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
|
||||
# observe transaction state
|
||||
self.transactionService.watchTransaction(
|
||||
transactionHash,
|
||||
addressFrom,
|
||||
contractAddress,
|
||||
$PendingTransactionTypeDto.CollectibleDeployment,
|
||||
"",
|
||||
chainId,
|
||||
)
|
||||
except RpcException:
|
||||
error "Error minting collectibles", message = getCurrentExceptionMsg()
|
|
@ -15,6 +15,7 @@ type
|
|||
ReleaseENS = "ReleaseENS",
|
||||
BuyStickerPack = "BuyStickerPack"
|
||||
WalletTransfer = "WalletTransfer"
|
||||
CollectibleDeployment = "CollectibleDeployment"
|
||||
|
||||
proc event*(self:PendingTransactionTypeDto):string =
|
||||
result = "transaction:" & $self
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
import json
|
||||
import ./eth
|
||||
import ./utils
|
||||
import ./core, ./response_type
|
||||
|
||||
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)
|
|
@ -17,6 +17,7 @@ Feature: Status Desktop Wallet
|
|||
Given the user opens wallet screen
|
||||
And the user clicks on the first account
|
||||
|
||||
@mayfail
|
||||
Scenario: The user can manage and observe a watch only account
|
||||
When the user adds watch only account "0xea123F7beFF45E3C9fdF54B324c29DBdA14a639A" named "AccountWatch"
|
||||
Then the new account "AccountWatch" is added
|
||||
|
@ -25,20 +26,24 @@ Feature: Status Desktop Wallet
|
|||
# And the collectibles are listed for the on
|
||||
# And the transactions are listed for the added account
|
||||
|
||||
@mayfail
|
||||
Scenario: The user imports a private key
|
||||
When an account named "AccountPrivate" is added via private key "8da4ef21b864d2cc526dbdb2a120bd2874c36c9d0a1fb7f8c63d7f7a8b41de8f" and authenticated using password "TesTEr16843/!@00"
|
||||
Then the new account "AccountPrivate" is added
|
||||
|
||||
@mayfail
|
||||
Scenario: The user generates a new account from wallet and deletes it
|
||||
When an account named "AccountGenerated" is generated and authenticated using password "TesTEr16843/!@00"
|
||||
Then the new account "AccountGenerated" is added
|
||||
When the user deletes the account "AccountGenerated" with password "TesTEr16843/!@00"
|
||||
Then the account "AccountGenerated" is not in the list of accounts
|
||||
|
||||
@mayfail
|
||||
Scenario: The user can import seed phrase
|
||||
When an account named "AccountSeed" is added via imported seed phrase "pelican chief sudden oval media rare swamp elephant lawsuit wheat knife initial" and authenticated using password "TesTEr16843/!@00"
|
||||
Then the new account "AccountSeed" is added
|
||||
|
||||
@mayfail
|
||||
Scenario: The user edits the default account
|
||||
Given the user opens app settings screen
|
||||
And the user opens the wallet settings
|
||||
|
@ -46,6 +51,7 @@ Feature: Status Desktop Wallet
|
|||
And the user edits default account to "Default" name and "#FFCA0F" color
|
||||
Then the default account is updated to be named "DefaultStatus account" with color "#FFCA0F"
|
||||
|
||||
@mayfail
|
||||
Scenario Outline: The user can manage a saved address
|
||||
When the user adds a saved address named "<name>" and address "<address>"
|
||||
And the user toggles favourite for the saved address with name "<name>"
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
import QtQuick 2.14
|
||||
import QtQuick.Layouts 1.14
|
||||
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
|
||||
import utils 1.0
|
||||
import shared.popups 1.0
|
||||
import shared.stores 1.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property var tokensModel
|
||||
|
||||
signal mintCollectible(string address, string name, string symbol, string description, int supply,
|
||||
bool infiniteSupply, bool transferable, bool selfDestruct, string network)
|
||||
|
||||
readonly property var transactionStore: TransactionStore{}
|
||||
|
||||
ColumnLayout {
|
||||
id: layout
|
||||
anchors.left: parent.left
|
||||
|
||||
spacing: Style.current.padding
|
||||
|
||||
StatusInput {
|
||||
id: name
|
||||
width: 200
|
||||
label: qsTr("Name")
|
||||
}
|
||||
|
||||
StatusInput {
|
||||
id: symbol
|
||||
width: 100
|
||||
label: qsTr("Symbol")
|
||||
}
|
||||
|
||||
StatusInput {
|
||||
id: description
|
||||
width: 200
|
||||
label: qsTr("Description")
|
||||
}
|
||||
|
||||
StatusInput {
|
||||
id: supply
|
||||
width: 100
|
||||
label: qsTr("Total finite supply")
|
||||
text: "0"
|
||||
}
|
||||
|
||||
StatusCheckBox {
|
||||
id: transferable
|
||||
text: qsTr("Transferable")
|
||||
}
|
||||
|
||||
StatusCheckBox {
|
||||
id: selfDestruct
|
||||
text: qsTr("Remote self-destruct")
|
||||
}
|
||||
|
||||
StatusComboBox {
|
||||
id: network
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
Layout.maximumWidth: 200
|
||||
label: qsTr("Select network")
|
||||
model: ListModel {
|
||||
ListElement {
|
||||
name: "Goerli"
|
||||
}
|
||||
ListElement {
|
||||
name: "Optimism Goerli"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StatusButton {
|
||||
id: mintButton
|
||||
text: "Mint"
|
||||
//TODO use address from SendModal
|
||||
onClicked: root.mintCollectible(root.transactionStore.currentAccount.address, name.text, symbol.text, description.text, parseInt(supply.text),
|
||||
false, transferable.checked, selfDestruct.checked, network.currentValue)
|
||||
}
|
||||
|
||||
StatusBaseText {
|
||||
text: "Minted collectibles"
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: collectibles
|
||||
|
||||
width: 200
|
||||
height: 100
|
||||
|
||||
model: root.tokensModel
|
||||
|
||||
delegate: Text {
|
||||
text: "name: " + name + ", descr: " + description + ", supply: " + supply
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
import QtQuick 2.14
|
||||
|
||||
import AppLayouts.Chat.layouts 1.0
|
||||
|
||||
SettingsPageLayout {
|
||||
id: root
|
||||
|
||||
property var tokensModel
|
||||
|
||||
signal mintCollectible(string address, string name, string symbol, string description, int supply,
|
||||
bool infiniteSupply, bool transferable, bool selfDestruct, string network)
|
||||
|
||||
property int viewWidth: 560 // by design
|
||||
|
||||
CommunityMintTokenPanel {
|
||||
anchors.fill: parent
|
||||
tokensModel: root.tokensModel
|
||||
onMintCollectible: root.mintCollectible(address, name, symbol, description, supply,
|
||||
infiniteSupply, transferable, selfDestruct, network)
|
||||
}
|
||||
}
|
|
@ -5,6 +5,8 @@ QtObject {
|
|||
|
||||
readonly property bool isOwner: false
|
||||
|
||||
property var mintingModuleInst: mintingModule
|
||||
|
||||
property var permissionsModel: ListModel {} // Backend permissions list object model assignment. Please check the current expected data in qml defined in `createPermissions` method
|
||||
property var permissionConflict: QtObject { // Backend conflicts object model assignment. Now mocked data.
|
||||
property bool exists: false
|
||||
|
@ -164,4 +166,15 @@ QtObject {
|
|||
console.log("TODO: Remove permissions - backend call")
|
||||
root.permissionsModel.remove(index)
|
||||
}
|
||||
|
||||
//MINTING
|
||||
|
||||
property var mintTokensModel: mintingModuleInst.tokensModel
|
||||
|
||||
function mintCollectible(address, name, symbol, description, supply,
|
||||
infiniteSupply, transferable, selfDestruct, network)
|
||||
{
|
||||
mintingModuleInst.mintCollectible(address, name, symbol, description, supply,
|
||||
infiniteSupply, transferable, selfDestruct, network)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -141,6 +141,7 @@ QtObject {
|
|||
property var communitiesModuleInst: communitiesModule
|
||||
property var communitiesList: communitiesModuleInst.model
|
||||
property bool communityPermissionsEnabled: localAccountSensitiveSettings.isCommunityPermissionsEnabled
|
||||
property bool communityTokensEnabled: localAccountSensitiveSettings.isCommunityTokensEnabled
|
||||
|
||||
property var userProfileInst: userProfile
|
||||
|
||||
|
|
|
@ -16,6 +16,8 @@ import StatusQ.Components 0.1
|
|||
import StatusQ.Controls 0.1
|
||||
import StatusQ.Controls.Validators 0.1
|
||||
|
||||
import AppLayouts.Chat.stores 1.0
|
||||
|
||||
import "../panels/communities"
|
||||
import "../popups/community"
|
||||
import "../layouts"
|
||||
|
@ -26,11 +28,11 @@ StatusSectionLayout {
|
|||
notificationCount: activityCenterStore.unreadNotificationsCount
|
||||
onNotificationButtonClicked: Global.openActivityCenterPopup()
|
||||
// TODO: get this model from backend?
|
||||
property var settingsMenuModel: root.rootStore.communityPermissionsEnabled ? [{name: qsTr("Overview"), icon: "show"},
|
||||
{name: qsTr("Members"), icon: "group-chat"},
|
||||
{name: qsTr("Permissions"), icon: "objects"}] :
|
||||
[{name: qsTr("Overview"), icon: "show"},
|
||||
{name: qsTr("Members"), icon: "group-chat"}]
|
||||
property var settingsMenuModel: [{name: qsTr("Overview"), icon: "show", enabled: true},
|
||||
{name: qsTr("Members"), icon: "group-chat", enabled: true},
|
||||
{name: qsTr("Permissions"), icon: "objects", enabled: root.rootStore.communityPermissionsEnabled},
|
||||
{name: qsTr("Tokens"), icon: "token", enabled: root.rootStore.communityTokensEnabled}]
|
||||
|
||||
// TODO: Next community settings options:
|
||||
// {name: qsTr("Tokens"), icon: "token"},
|
||||
// {name: qsTr("Airdrops"), icon: "airdrop"},
|
||||
|
@ -40,6 +42,7 @@ StatusSectionLayout {
|
|||
property var rootStore
|
||||
property var community
|
||||
property var chatCommunitySectionModule
|
||||
property var communityStore: CommunitiesStore {}
|
||||
property bool hasAddedContacts: false
|
||||
|
||||
readonly property string filteredSelectedTags: {
|
||||
|
@ -114,6 +117,8 @@ StatusSectionLayout {
|
|||
asset.width: 24
|
||||
selected: d.currentIndex === index
|
||||
onClicked: d.currentIndex = index
|
||||
visible: modelData.enabled
|
||||
height: modelData.enabled ? implicitHeight : 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -243,6 +248,14 @@ StatusSectionLayout {
|
|||
onPreviousPageNameChanged: root.backButtonName = previousPageName
|
||||
}
|
||||
|
||||
CommunityTokensPanel {
|
||||
tokensModel: root.communityStore.mintTokensModel
|
||||
onMintCollectible: {
|
||||
root.communityStore.mintCollectible(address, name, symbol, description, supply,
|
||||
infiniteSupply, transferable, selfDestruct, network)
|
||||
}
|
||||
}
|
||||
|
||||
onCurrentIndexChanged: root.backButtonName = centerPanelContentLoader.item.children[d.currentIndex].previousPageName
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ QtObject {
|
|||
readonly property string communityPermissions: "communityPermissions"
|
||||
readonly property string discordImportTool: "discordImportTool"
|
||||
readonly property string wakuV2StoreEnabled: "wakuV2StoreEnabled"
|
||||
readonly property string communityTokens: "communityTokens"
|
||||
}
|
||||
|
||||
function logDir() {
|
||||
|
@ -137,5 +138,8 @@ QtObject {
|
|||
else if (feature === experimentalFeatures.discordImportTool) {
|
||||
localAccountSensitiveSettings.isDiscordImportToolEnabled = !localAccountSensitiveSettings.isDiscordImportToolEnabled
|
||||
}
|
||||
else if (feature === experimentalFeatures.communityTokens) {
|
||||
localAccountSensitiveSettings.isCommunityTokensEnabled = !localAccountSensitiveSettings.isCommunityTokensEnabled
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -168,6 +168,23 @@ SettingsContentBase {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: replace with StatusQ component
|
||||
StatusSettingsLineButton {
|
||||
anchors.leftMargin: 0
|
||||
anchors.rightMargin: 0
|
||||
text: qsTr("Community Tokens")
|
||||
isSwitch: true
|
||||
switchChecked: localAccountSensitiveSettings.isCommunityTokensEnabled
|
||||
onClicked: {
|
||||
if (!localAccountSensitiveSettings.isCommunityTokensEnabled) {
|
||||
confirmationPopup.experimentalFeature = root.advancedStore.experimentalFeatures.communityTokens
|
||||
confirmationPopup.open()
|
||||
} else {
|
||||
root.advancedStore.toggleExperimentalFeature(root.advancedStore.experimentalFeatures.communityTokens)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StatusSettingsLineButton {
|
||||
anchors.leftMargin: 0
|
||||
anchors.rightMargin: 0
|
||||
|
|
Loading…
Reference in New Issue