diff --git a/src/app/modules/main/communities/module.nim b/src/app/modules/main/communities/module.nim index 84bc85cbbe..2b08b7978c 100644 --- a/src/app/modules/main/communities/module.nim +++ b/src/app/modules/main/communities/module.nim @@ -71,7 +71,7 @@ proc newModule*( communityTokensService, networksService, ) - result.communityTokensModule = community_tokens_module.newCommunityTokensModule(result, events, communityTokensService, transactionService) + result.communityTokensModule = community_tokens_module.newCommunityTokensModule(result, events, communityTokensService, transactionService, networksService) result.moduleLoaded = false result.curatedCommunitiesLoaded = false diff --git a/src/app/modules/main/communities/tokens/controller.nim b/src/app/modules/main/communities/tokens/controller.nim index e2fa44fcf9..24c8ca8c7a 100644 --- a/src/app/modules/main/communities/tokens/controller.nim +++ b/src/app/modules/main/communities/tokens/controller.nim @@ -2,6 +2,7 @@ import ./io_interface as community_tokens_module_interface import ../../../../../app_service/service/community_tokens/service as community_tokens_service import ../../../../../app_service/service/transaction/service as transaction_service +import ../../../../../app_service/service/network/service as networks_service import ../../../../../app_service/service/community/dto/community import ../../../../core/signals/types import ../../../../core/eventemitter @@ -16,18 +17,21 @@ type events: EventEmitter communityTokensService: community_tokens_service.Service transactionService: transaction_service.Service + networksService: networks_service.Service proc newCommunityTokensController*( communityTokensModule: community_tokens_module_interface.AccessInterface, events: EventEmitter, communityTokensService: community_tokens_service.Service, - transactionService: transaction_service.Service + transactionService: transaction_service.Service, + networksService: networks_service.Service ): Controller = result = Controller() result.communityTokensModule = communityTokensModule result.events = events result.communityTokensService = communityTokensService result.transactionService = transactionService + result.networksService = networksService proc delete*(self: Controller) = discard @@ -41,6 +45,12 @@ proc init*(self: Controller) = self.events.on(SIGNAL_COMPUTE_DEPLOY_FEE) do(e:Args): let args = ComputeDeployFeeArgs(e) self.communityTokensModule.onDeployFeeComputed(args.ethCurrency, args.fiatCurrency, args.errorCode) + self.events.on(SIGNAL_COMMUNITY_TOKEN_DEPLOYED) do(e: Args): + let args = CommunityTokenDeployedArgs(e) + self.communityTokensModule.onCommunityTokenDeployStateChanged(args.communityToken.chainId, args.transactionHash, args.communityToken.deployState) + self.events.on(SIGNAL_COMMUNITY_TOKEN_DEPLOY_STATUS) do(e: Args): + let args = CommunityTokenDeployedStatusArgs(e) + self.communityTokensModule.onCommunityTokenDeployStateChanged(args.chainId, args.transactionHash, args.deployState) proc deployCollectibles*(self: Controller, communityId: string, addressFrom: string, password: string, deploymentParams: DeploymentParameters, tokenMetadata: CommunityTokensMetadataDto, chainId: int) = self.communityTokensService.deployCollectibles(communityId, addressFrom, password, deploymentParams, tokenMetadata, chainId) @@ -60,3 +70,6 @@ proc computeDeployFee*(self: Controller, chainId: int, accountAddress: string) = proc getCommunityTokenBySymbol*(self: Controller, communityId: string, symbol: string): CommunityTokenDto = return self.communityTokensService.getCommunityTokenBySymbol(communityId, symbol) + +proc getNetwork*(self:Controller, chainId: int): NetworkDto = + self.networksService.getNetwork(chainId) \ No newline at end of file diff --git a/src/app/modules/main/communities/tokens/io_interface.nim b/src/app/modules/main/communities/tokens/io_interface.nim index 40b572d14b..989da347f1 100644 --- a/src/app/modules/main/communities/tokens/io_interface.nim +++ b/src/app/modules/main/communities/tokens/io_interface.nim @@ -27,4 +27,7 @@ method computeDeployFee*(self: AccessInterface, chainId: int, accountAddress: st raise newException(ValueError, "No implementation available") method onDeployFeeComputed*(self: AccessInterface, ethCurrency: CurrencyAmount, fiatCurrency: CurrencyAmount, errorCode: ComputeFeeErrorCode) {.base.} = + raise newException(ValueError, "No implementation available") + +method onCommunityTokenDeployStateChanged*(self: AccessInterface, chainId: int, transactionHash: string, deployState: DeployState) {.base.} = raise newException(ValueError, "No implementation available") \ No newline at end of file diff --git a/src/app/modules/main/communities/tokens/module.nim b/src/app/modules/main/communities/tokens/module.nim index edea263211..8926ed365e 100644 --- a/src/app/modules/main/communities/tokens/module.nim +++ b/src/app/modules/main/communities/tokens/module.nim @@ -2,6 +2,7 @@ import NimQml, json, stint, strutils, chronicles import ../../../../../app_service/service/community_tokens/service as community_tokens_service import ../../../../../app_service/service/transaction/service as transaction_service +import ../../../../../app_service/service/network/service as networks_service import ../../../../../app_service/service/community/dto/community import ../../../../../app_service/service/accounts/utils as utl import ../../../../core/eventemitter @@ -38,12 +39,13 @@ proc newCommunityTokensModule*( parent: parent_interface.AccessInterface, events: EventEmitter, communityTokensService: community_tokens_service.Service, - transactionService: transaction_service.Service): Module = + transactionService: transaction_service.Service, + networksService: networks_service.Service): Module = result = Module() result.parent = parent result.view = newView(result) result.viewVariant = newQVariant(result.view) - result.controller = controller.newCommunityTokensController(result, events, communityTokensService, transactionService) + result.controller = controller.newCommunityTokensController(result, events, communityTokensService, transactionService, networksService) method delete*(self: Module) = self.view.delete @@ -123,3 +125,8 @@ method onDeployFeeComputed*(self: Module, ethCurrency: CurrencyAmount, fiatCurre method computeDeployFee*(self: Module, chainId: int, accountAddress: string) = self.controller.computeDeployFee(chainId, accountAddress) + +method onCommunityTokenDeployStateChanged*(self: Module, chainId: int, transactionHash: string, deployState: DeployState) = + let network = self.controller.getNetwork(chainId) + let url = if network != nil: network.blockExplorerURL & "/tx/" & transactionHash else: "" + self.view.emitDeploymentStateChanged(deployState.int, url) \ No newline at end of file diff --git a/src/app/modules/main/communities/tokens/view.nim b/src/app/modules/main/communities/tokens/view.nim index 7c5a7b2ccb..54c02be683 100644 --- a/src/app/modules/main/communities/tokens/view.nim +++ b/src/app/modules/main/communities/tokens/view.nim @@ -33,4 +33,6 @@ QtObject: proc updateDeployFee*(self: View, ethCurrency: CurrencyAmount, fiatCurrency: CurrencyAmount, errorCode: int) = self.deployFeeUpdated(newQVariant(ethCurrency), newQVariant(fiatCurrency), errorCode) - + proc deploymentStateChanged*(self: View, status: int, url: string) {.signal.} + proc emitDeploymentStateChanged*(self: View, status: int, url: string) = + self.deploymentStateChanged(status, url) \ No newline at end of file diff --git a/src/app/modules/main/controller.nim b/src/app/modules/main/controller.nim index e24ba3b854..52f21a488d 100644 --- a/src/app/modules/main/controller.nim +++ b/src/app/modules/main/controller.nim @@ -474,5 +474,5 @@ proc getVerificationRequestFrom*(self: Controller, publicKey: string): Verificat proc getCommunityTokens*(self: Controller, communityId: string): seq[CommunityTokenDto] = self.communityTokensService.getCommunityTokens(communityId) -proc getNetworks*(self:Controller): seq[NetworkDto] = - self.networksService.getNetworks() \ No newline at end of file +proc getNetwork*(self:Controller, chainId: int): NetworkDto = + self.networksService.getNetwork(chainId) \ No newline at end of file diff --git a/src/app/modules/main/module.nim b/src/app/modules/main/module.nim index 7bf1242ecc..e09e851576 100644 --- a/src/app/modules/main/module.nim +++ b/src/app/modules/main/module.nim @@ -237,25 +237,23 @@ method delete*[T](self: Module[T]) = self.view.delete self.viewVariant.delete -proc createTokenItem[T](self: Module[T], tokenDto: CommunityTokenDto, networks: seq[NetworkDto]) : TokenItem = +proc createTokenItem[T](self: Module[T], tokenDto: CommunityTokenDto, network: NetworkDto) : TokenItem = var chainName, chainIcon: string - for network in networks: - if network.chainId == tokenDto.chainId: - chainName = network.chainName - chainIcon = network.iconURL - break + if network != nil: + chainName = network.chainName + chainIcon = network.iconURL result = initTokenItem(tokenDto, chainName, chainIcon) proc createChannelGroupItem[T](self: Module[T], channelGroup: ChannelGroupDto): SectionItem = let isCommunity = channelGroup.channelGroupType == ChannelGroupType.Community var communityDetails: CommunityDto var communityTokensItems: seq[TokenItem] - let networks = self.controller.getNetworks() if (isCommunity): communityDetails = self.controller.getCommunityById(channelGroup.id) let communityTokens = self.controller.getCommunityTokens(channelGroup.id) communityTokensItems = communityTokens.map(proc(tokenDto: CommunityTokenDto): TokenItem = - result = self.createTokenItem(tokenDto, networks) + let network = self.controller.getNetwork(tokenDto.chainId) + result = self.createTokenItem(tokenDto, network) ) let unviewedCount = channelGroup.unviewedMessagesCount @@ -987,8 +985,8 @@ method contactsStatusUpdated*[T](self: Module[T], statusUpdates: seq[StatusUpdat method onCommunityTokenDeployed*[T](self: Module[T], communityToken: CommunityTokenDto) {.base.} = let item = self.view.model().getItemById(communityToken.communityId) if item.id != "": - let networks = self.controller.getNetworks() - item.appendCommunityToken(self.createTokenItem(communityToken, networks)) + let network = self.controller.getNetwork(communityToken.chainId) + item.appendCommunityToken(self.createTokenItem(communityToken, network)) method onCommunityTokenDeployStateChanged*[T](self: Module[T], communityId: string, contractAddress: string, deployState: DeployState) = let item = self.view.model().getItemById(communityId) diff --git a/src/app_service/service/community_tokens/service.nim b/src/app_service/service/community_tokens/service.nim index bf5e8dfdbf..14554af9ca 100644 --- a/src/app_service/service/community_tokens/service.nim +++ b/src/app_service/service/community_tokens/service.nim @@ -37,11 +37,14 @@ type CommunityTokenDeployedStatusArgs* = ref object of Args communityId*: string contractAddress*: string + chainId*: int + transactionHash*: string deployState*: DeployState type CommunityTokenDeployedArgs* = ref object of Args communityToken*: CommunityTokenDto + transactionHash*: string type ComputeFeeErrorCode* {.pure.} = enum @@ -56,6 +59,10 @@ type fiatCurrency*: CurrencyAmount errorCode*: ComputeFeeErrorCode +type ContractTuple = tuple + address: string + chainId: int + # Signals which may be emitted by this service: const SIGNAL_COMMUNITY_TOKEN_DEPLOY_STATUS* = "communityTokenDeployStatus" const SIGNAL_COMMUNITY_TOKEN_DEPLOYED* = "communityTokenDeployed" @@ -72,6 +79,7 @@ QtObject: walletAccountService: wallet_account_service.Service tempAccountAddress: string tempChainId: int + addressAndTxMap: Table[ContractTuple, string] proc delete*(self: Service) = self.QObject.delete @@ -92,6 +100,7 @@ QtObject: result.tokenService = tokenService result.settingsService = settingsService result.walletAccountService = walletAccountService + result.addressAndTxMap = initTable[ContractTuple, string]() proc init*(self: Service) = self.events.on(PendingTransactionTypeDto.CollectibleDeployment.event) do(e: Args): @@ -104,7 +113,9 @@ QtObject: 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) + let data = CommunityTokenDeployedStatusArgs(communityId: tokenDto.communityId, contractAddress: tokenDto.address, + deployState: deployState, chainId: tokenDto.chainId, + transactionHash: self.addressAndTxMap.getOrDefault((tokenDto.address,tokenDto.chainId))) self.events.emit(SIGNAL_COMMUNITY_TOKEN_DEPLOY_STATUS, data) self.events.on(PendingTransactionTypeDto.CollectibleAirdrop.event) do(e: Args): @@ -147,6 +158,8 @@ QtObject: debug "Deployed contract address ", contractAddress=contractAddress debug "Deployment transaction hash ", transactionHash=transactionHash + self.addressAndTxMap[(contractAddress, chainId)] = transactionHash + var communityToken: CommunityTokenDto communityToken.tokenType = TokenType.ERC721 communityToken.communityId = communityId @@ -166,7 +179,7 @@ QtObject: # save token to db let communityTokenJson = tokens_backend.addCommunityToken(communityToken) communityToken = communityTokenJson.result.toCommunityTokenDto() - let data = CommunityTokenDeployedArgs(communityToken: communityToken) + let data = CommunityTokenDeployedArgs(communityToken: communityToken, transactionHash: transactionHash) self.events.emit(SIGNAL_COMMUNITY_TOKEN_DEPLOYED, data) # observe transaction state diff --git a/ui/app/AppLayouts/Chat/stores/RootStore.qml b/ui/app/AppLayouts/Chat/stores/RootStore.qml index 673449b27e..10404c57e2 100644 --- a/ui/app/AppLayouts/Chat/stores/RootStore.qml +++ b/ui/app/AppLayouts/Chat/stores/RootStore.qml @@ -9,6 +9,7 @@ QtObject { id: root property var contactsStore + property var communityTokensStore property var networkConnectionStore @@ -17,8 +18,6 @@ QtObject { chatCommunitySectionModuleInst: chatCommunitySectionModule } - readonly property CommunityTokensStore communityTokensStore: CommunityTokensStore { rootStore: root } - property bool openCreateChat: false property string createChatInitMessage: "" property var createChatFileUrls: [] diff --git a/ui/app/AppLayouts/Chat/stores/qmldir b/ui/app/AppLayouts/Chat/stores/qmldir index 00d7e85583..22a8298fd0 100644 --- a/ui/app/AppLayouts/Chat/stores/qmldir +++ b/ui/app/AppLayouts/Chat/stores/qmldir @@ -1,5 +1,4 @@ CommunitiesStore 1.0 CommunitiesStore.qml -CommunityTokensStore 1.0 CommunityTokensStore.qml PermissionsStore 1.0 PermissionsStore.qml RootStore 1.0 RootStore.qml StickerData 1.0 StickerData.qml diff --git a/ui/app/AppLayouts/Chat/views/CommunitySettingsView.qml b/ui/app/AppLayouts/Chat/views/CommunitySettingsView.qml index ac1689a6aa..8757255cbe 100644 --- a/ui/app/AppLayouts/Chat/views/CommunitySettingsView.qml +++ b/ui/app/AppLayouts/Chat/views/CommunitySettingsView.qml @@ -354,15 +354,32 @@ StatusSectionLayout { mintPanel.isFeeLoading = true } - // TODO: Self-destruct backend - function onSelfDestructFeeUpdated(value) { - // TODO better error handling - if (value === "-") { - mintPanel.isFeeLoading = true - } else { - mintPanel.isFeeLoading = false - mintPanel.feeText = value + function onDeploymentStateChanged(status, url) { + let title = "" + let loading = false + let type = Constants.ephemeralNotificationType.normal + switch (status) { + case Constants.DeployState.InProgress: + title = qsTr("Token is being minted...") + loading = true + break + case Constants.DeployState.Deployed: + title = qsTr("Token minting finished") + type = Constants.ephemeralNotificationType.success + break + case Constants.DeployState.Failed: + title = qsTr("Token minting failed") + break + default: + console.warn("Unknown deploy state: "+status) + return } + Global.displayToastMessage(title, + qsTr("View on etherscan"), + "", + loading, + type, + url) } } } diff --git a/ui/app/AppLayouts/Chat/views/communities/CommunityCollectibleView.qml b/ui/app/AppLayouts/Chat/views/communities/CommunityCollectibleView.qml index e942e8816e..7271f0fa67 100644 --- a/ui/app/AppLayouts/Chat/views/communities/CommunityCollectibleView.qml +++ b/ui/app/AppLayouts/Chat/views/communities/CommunityCollectibleView.qml @@ -51,12 +51,6 @@ StatusScrollView { readonly property int iconSize: 20 } - enum DeployState { - Failed, - InProgress, - Deployed - } - contentWidth: mainLayout.width contentHeight: mainLayout.height padding: 0 @@ -68,7 +62,7 @@ StatusScrollView { spacing: Style.current.padding RowLayout { - visible: !root.preview && (root.deployState === CommunityCollectibleView.DeployState.InProgress) + visible: !root.preview && (root.deployState === Constants.DeployState.InProgress) spacing: Style.current.halfPadding StatusDotsLoadingIndicator {} diff --git a/ui/app/AppLayouts/Chat/views/communities/CommunityMintedTokensView.qml b/ui/app/AppLayouts/Chat/views/communities/CommunityMintedTokensView.qml index db6af9cfa7..1b0b84c4d7 100644 --- a/ui/app/AppLayouts/Chat/views/communities/CommunityMintedTokensView.qml +++ b/ui/app/AppLayouts/Chat/views/communities/CommunityMintedTokensView.qml @@ -21,21 +21,15 @@ StatusScrollView { string accountName, string accountAddress) - enum DeployState { - Failed, - InProgress, - Deployed - } - QtObject { id: d function getStateText(deployState) { - if(deployState === CommunityMintedTokensView.DeployState.Failed) { + if(deployState === Constants.DeployState.Failed) { return qsTr("Failed") } - if(deployState === CommunityMintedTokensView.DeployState.InProgress) { + if(deployState === Constants.DeployState.InProgress) { return qsTr("Minting...") } return "" diff --git a/ui/app/mainui/AppMain.qml b/ui/app/mainui/AppMain.qml index 18fa7a26e6..3be416f2c6 100644 --- a/ui/app/mainui/AppMain.qml +++ b/ui/app/mainui/AppMain.qml @@ -49,12 +49,14 @@ Item { property RootStore rootStore: RootStore {} property var rootChatStore: ChatStores.RootStore { contactsStore: appMain.rootStore.contactStore + communityTokensStore: appMain.communityTokensStore emojiReactionsModel: appMain.rootStore.emojiReactionsModel openCreateChat: createChatView.opened networkConnectionStore: appMain.networkConnectionStore } property ActivityCenterStore activityCenterStore: ActivityCenterStore {} property NetworkConnectionStore networkConnectionStore: NetworkConnectionStore {} + property CommunityTokensStore communityTokensStore: CommunityTokensStore {} // set from main.qml property var sysPalette @@ -876,6 +878,7 @@ Item { rootStore: ChatStores.RootStore { contactsStore: appMain.rootStore.contactStore + communityTokensStore: appMain.communityTokensStore emojiReactionsModel: appMain.rootStore.emojiReactionsModel openCreateChat: createChatView.opened chatCommunitySectionModule: appMain.rootStore.mainModuleInst.getChatSectionModule() @@ -1000,6 +1003,7 @@ Item { rootStore: ChatStores.RootStore { contactsStore: appMain.rootStore.contactStore + communityTokensStore: appMain.communityTokensStore emojiReactionsModel: appMain.rootStore.emojiReactionsModel openCreateChat: createChatView.opened chatCommunitySectionModule: { @@ -1041,10 +1045,10 @@ Item { sourceComponent: CreateChatView { rootStore: ChatStores.RootStore { contactsStore: appMain.rootStore.contactStore + communityTokensStore: appMain.communityTokensStore emojiReactionsModel: appMain.rootStore.emojiReactionsModel openCreateChat: createChatView.opened chatCommunitySectionModule: appMain.rootStore.mainModuleInst.getChatSectionModule() - } emojiPopup: statusEmojiPopup stickersPopup: statusStickersPopupLoader.item @@ -1064,6 +1068,7 @@ Item { height: appView.height - _buttonSize * 2 store: ChatStores.RootStore { contactsStore: appMain.rootStore.contactStore + communityTokensStore: appMain.communityTokensStore emojiReactionsModel: appMain.rootStore.emojiReactionsModel openCreateChat: createChatView.opened chatCommunitySectionModule: appMain.rootStore.mainModuleInst.getChatSectionModule() diff --git a/ui/app/AppLayouts/Chat/stores/CommunityTokensStore.qml b/ui/imports/shared/stores/CommunityTokensStore.qml similarity index 95% rename from ui/app/AppLayouts/Chat/stores/CommunityTokensStore.qml rename to ui/imports/shared/stores/CommunityTokensStore.qml index 25a38d84a2..21dad5f1e5 100644 --- a/ui/app/AppLayouts/Chat/stores/CommunityTokensStore.qml +++ b/ui/imports/shared/stores/CommunityTokensStore.qml @@ -1,9 +1,9 @@ import QtQuick 2.15 +import utils 1.0 QtObject { id: root - property var rootStore property var communityTokensModuleInst: communityTokensModule ?? null // Network selection properties: @@ -56,9 +56,6 @@ QtObject { ]) } - signal deployFeeUpdated(var ethCurrency, var fiatCurrency, int error) - signal selfDestructFeeUpdated(string value) // TO BE REMOVED - // Minting tokens: function deployCollectible(communityId, accountAddress, name, symbol, description, supply, infiniteSupply, transferable, selfDestruct, chainId, artworkSource, accountName) @@ -68,11 +65,18 @@ QtObject { infiniteSupply, transferable, selfDestruct, chainId, artworkSource) } + signal deployFeeUpdated(var ethCurrency, var fiatCurrency, int error) + signal deploymentStateChanged(int status, string url) + signal selfDestructFeeUpdated(string value) // TO BE REMOVED + readonly property Connections connections: Connections { target: communityTokensModuleInst function onDeployFeeUpdated(ethCurrency, fiatCurrency, errorCode) { root.deployFeeUpdated(ethCurrency, fiatCurrency, errorCode) } + function onDeploymentStateChanged(status, url) { + root.deploymentStateChanged(status, url) + } } function computeDeployFee(chainId, accountAddress) { diff --git a/ui/imports/shared/stores/qmldir b/ui/imports/shared/stores/qmldir index 760852646f..4ad71f4a37 100644 --- a/ui/imports/shared/stores/qmldir +++ b/ui/imports/shared/stores/qmldir @@ -1,6 +1,7 @@ singleton RootStore 1.0 RootStore.qml CurrenciesStore 1.0 CurrenciesStore.qml TransactionStore 1.0 TransactionStore.qml +CommunityTokensStore 1.0 CommunityTokensStore.qml BIP39_en 1.0 BIP39_en.qml ChartStoreBase 1.0 ChartStoreBase.qml TokenBalanceHistoryStore 1.0 TokenBalanceHistoryStore.qml diff --git a/ui/imports/utils/Constants.qml b/ui/imports/utils/Constants.qml index 755b5b80d2..5d42ffcc95 100644 --- a/ui/imports/utils/Constants.qml +++ b/ui/imports/utils/Constants.qml @@ -883,6 +883,12 @@ QtObject { Everyone = 4 } + enum DeployState { + Failed, + InProgress, + Deployed + } + readonly property QtObject walletSection: QtObject { readonly property string cancelledMessage: "cancelled" }