fix(networks): enable network before mint or airdrop (#15601)

Fixes #15507

Makes sure to enable the network where the owner token was minted before minting or airdroping a token.
This makes sure that the account selector shows the right balance and there is no ETH error before doing the transation
This commit is contained in:
Jonathan Rainville 2024-07-22 09:52:44 -04:00 committed by GitHub
parent 83db905e28
commit 8db0ac94f0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 170 additions and 15 deletions

View File

@ -91,6 +91,9 @@ QtObject:
let (chainIds, enable) = self.flatNetworks.networksToChangeStateOnUserActionFor(chainId, self.areTestNetworksEnabled) let (chainIds, enable) = self.flatNetworks.networksToChangeStateOnUserActionFor(chainId, self.areTestNetworksEnabled)
self.delegate.setNetworksState(chainIds, enable) self.delegate.setNetworksState(chainIds, enable)
proc enableNetwork*(self: View, chainId: int) {.slot.} =
self.delegate.setNetworksState(@[chainId], enable = true)
proc getNetworkShortNames*(self: View, preferredNetworks: string): string {.slot.} = proc getNetworkShortNames*(self: View, preferredNetworks: string): string {.slot.} =
return self.flatNetworks.getNetworkShortNames(preferredNetworks, self.areTestNetworksEnabled) return self.flatNetworks.getNetworkShortNames(preferredNetworks, self.areTestNetworksEnabled)

View File

@ -235,6 +235,8 @@ StackLayout {
id: communitySettingsView id: communitySettingsView
rootStore: root.rootStore rootStore: root.rootStore
walletAccountsModel: WalletStore.RootStore.nonWatchAccounts walletAccountsModel: WalletStore.RootStore.nonWatchAccounts
enabledChainIds: WalletStore.RootStore.networkFilters
onEnableNetwork: WalletStore.RootStore.enableNetwork(chainId)
tokensStore: root.tokensStore tokensStore: root.tokensStore
sendModalPopup: root.sendModalPopup sendModalPopup: root.sendModalPopup
transactionStore: root.transactionStore transactionStore: root.transactionStore

View File

@ -33,12 +33,15 @@ StackView {
required property var membersModel required property var membersModel
required property var accountsModel required property var accountsModel
required property string enabledChainIds
property int viewWidth: 560 // by design property int viewWidth: 560 // by design
property string previousPageName: depth > 1 ? qsTr("Airdrops") : "" property string previousPageName: depth > 1 ? qsTr("Airdrops") : ""
signal airdropClicked(var airdropTokens, var addresses, string feeAccountAddress) signal airdropClicked(var airdropTokens, var addresses, string feeAccountAddress)
signal navigateToMintTokenSettings(bool isAssetType) signal navigateToMintTokenSettings(bool isAssetType)
signal registerAirdropFeeSubscriber(var feeSubscriber) signal registerAirdropFeeSubscriber(var feeSubscriber)
signal enableNetwork(int chainId)
function navigateBack() { function navigateBack() {
pop(StackView.Immediate) pop(StackView.Immediate)
@ -120,6 +123,8 @@ StackView {
feeErrorText: feesSubscriber.feesError feeErrorText: feesSubscriber.feesError
feesPerSelectedContract: feesSubscriber.feesPerContract feesPerSelectedContract: feesSubscriber.feesPerContract
feesAvailable: !!feesSubscriber.airdropFeesResponse feesAvailable: !!feesSubscriber.airdropFeesResponse
enabledChainIds: root.enabledChainIds
onEnableNetwork: root.enableNetwork(chainId)
onAirdropClicked: { onAirdropClicked: {
root.airdropClicked(airdropTokens, addresses, feeAccountAddress) root.airdropClicked(airdropTokens, addresses, feeAccountAddress)

View File

@ -49,15 +49,19 @@ StackView {
// It will monitorize if Owner and/or TMaster token items are included in the `tokensModel` despite the deployment state // It will monitorize if Owner and/or TMaster token items are included in the `tokensModel` despite the deployment state
property bool ownerOrTMasterTokenItemsExist: false property bool ownerOrTMasterTokenItemsExist: false
// Network related properties:
property var flatNetworks
readonly property int ownerTokenChainId: SQUtils.ModelUtils.get(root.tokensModel, "privilegesLevel", Constants.TokenPrivilegesLevel.Owner).chainId ?? 0
readonly property int chainIndex: NetworkModelHelpers.getChainIndexByChainId(root.flatNetworks, root.ownerTokenChainId)
readonly property string chainName: NetworkModelHelpers.getChainName(root.flatNetworks, chainIndex)
property string enabledChainIds
// Models: // Models:
property var tokensModel property var tokensModel
property var membersModel property var membersModel
property var accounts // Expected roles: address, name, color, emoji, walletType property var accounts // Expected roles: address, name, color, emoji, walletType
required property var referenceAssetsBySymbolModel required property var referenceAssetsBySymbolModel
// Network related properties:
property var flatNetworks
signal mintCollectible(var collectibleItem) signal mintCollectible(var collectibleItem)
signal mintAsset(var assetItem) signal mintAsset(var assetItem)
signal mintOwnerToken(var ownerToken, var tMasterToken) signal mintOwnerToken(var ownerToken, var tMasterToken)
@ -83,6 +87,8 @@ StackView {
signal startTokenHoldersManagement(int chainId, string address) signal startTokenHoldersManagement(int chainId, string address)
signal stopTokenHoldersManagement() signal stopTokenHoldersManagement()
signal enableNetwork(int chainId)
function navigateBack() { function navigateBack() {
pop(StackView.Immediate) pop(StackView.Immediate)
} }
@ -122,6 +128,8 @@ StackView {
QtObject { QtObject {
id: d id: d
property string networkThatIsNotActive
// Owner or TMaster token retry navigation // Owner or TMaster token retry navigation
function retryPrivilegedToken(key, chainId, accountName, accountAddress) { function retryPrivilegedToken(key, chainId, accountName, accountAddress) {
var properties = { var properties = {
@ -136,6 +144,18 @@ StackView {
} }
} }
onVisibleChanged: {
if (!visible) {
return
}
// If the tokens' network is not activated, show a warning to the user
if (!root.enabledChainIds.includes(root.ownerTokenChainId)) {
d.networkThatIsNotActive = root.chainName
} else {
d.networkThatIsNotActive = ""
}
}
initialItem: SettingsPage { initialItem: SettingsPage {
implicitWidth: 0 implicitWidth: 0
title: qsTr("Tokens") title: qsTr("Tokens")
@ -276,18 +296,15 @@ StackView {
SettingsPage { SettingsPage {
id: newTokenPage id: newTokenPage
readonly property int ownerTokenChainId: SQUtils.ModelUtils.get(root.tokensModel, "privilegesLevel", Constants.TokenPrivilegesLevel.Owner).chainId ?? 0 readonly property string chainIcon: NetworkModelHelpers.getChainIconUrl(root.flatNetworks, root.chainIndex)
readonly property int chainIndex: NetworkModelHelpers.getChainIndexByChainId(root.flatNetworks, ownerTokenChainId)
readonly property string chainName: NetworkModelHelpers.getChainName(root.flatNetworks, chainIndex)
readonly property string chainIcon: NetworkModelHelpers.getChainIconUrl(root.flatNetworks, chainIndex)
property TokenObject asset: TokenObject{ property TokenObject asset: TokenObject{
type: Constants.TokenType.ERC20 type: Constants.TokenType.ERC20
multiplierIndex: 18 multiplierIndex: 18
// Minted tokens will use ALWAYS the same chain where the owner token was deployed. // Minted tokens will use ALWAYS the same chain where the owner token was deployed.
chainId: newTokenPage.ownerTokenChainId chainId: root.ownerTokenChainId
chainName: newTokenPage.chainName chainName: root.chainName
chainIcon: newTokenPage.chainIcon chainIcon: newTokenPage.chainIcon
} }
@ -295,13 +312,11 @@ StackView {
type: Constants.TokenType.ERC721 type: Constants.TokenType.ERC721
// Minted tokens will use ALWAYS the same chain where the owner token was deployed. // Minted tokens will use ALWAYS the same chain where the owner token was deployed.
chainId: newTokenPage.ownerTokenChainId chainId: root.ownerTokenChainId
chainName: newTokenPage.chainName chainName: root.chainName
chainIcon: newTokenPage.chainIcon chainIcon: newTokenPage.chainIcon
} }
property bool isAssetView: false property bool isAssetView: false
property int validationMode: StatusInput.ValidationMode.OnlyWhenDirty property int validationMode: StatusInput.ValidationMode.OnlyWhenDirty
property string referenceName: "" property string referenceName: ""
@ -373,6 +388,12 @@ StackView {
feeErrorText: deployFeeSubscriber.feeErrorText feeErrorText: deployFeeSubscriber.feeErrorText
isFeeLoading: !deployFeeSubscriber.feesResponse isFeeLoading: !deployFeeSubscriber.feesResponse
networkThatIsNotActive: d.networkThatIsNotActive
onEnableNetwork: {
root.enableNetwork(root.ownerTokenChainId)
d.networkThatIsNotActive = ""
}
onPreviewClicked: { onPreviewClicked: {
const properties = { const properties = {
token: token token: token
@ -780,7 +801,13 @@ StackView {
feeText: remotelyDestructFeeSubscriber.feeText feeText: remotelyDestructFeeSubscriber.feeText
feeErrorText: remotelyDestructFeeSubscriber.feeErrorText feeErrorText: remotelyDestructFeeSubscriber.feeErrorText
isFeeLoading: !remotelyDestructFeeSubscriber.feesResponse isFeeLoading: !remotelyDestructFeeSubscriber.feesResponse
networkThatIsNotActive: d.networkThatIsNotActive
onEnableNetwork: {
root.enableNetwork(root.ownerTokenChainId)
d.networkThatIsNotActive = ""
}
onRemotelyDestructClicked: { onRemotelyDestructClicked: {
remotelyDestructPopup.close() remotelyDestructPopup.close()
@ -812,6 +839,12 @@ StackView {
tokenSource: footer.token.artworkSource tokenSource: footer.token.artworkSource
chainName: footer.token.chainName chainName: footer.token.chainName
networkThatIsNotActive: d.networkThatIsNotActive
onEnableNetwork: {
root.enableNetwork(root.ownerTokenChainId)
d.networkThatIsNotActive = ""
}
onAmountToBurnChanged: burnTokensFeeSubscriber.updateAmount() onAmountToBurnChanged: burnTokensFeeSubscriber.updateAmount()
feeText: burnTokensFeeSubscriber.feeText feeText: burnTokensFeeSubscriber.feeText

View File

@ -0,0 +1,26 @@
import QtQuick 2.15
import QtQuick.Layouts 1.15
import StatusQ.Core 0.1
import StatusQ.Controls 0.1
RowLayout {
id: root
property string networkThatIsNotActive
signal enableNetwork
spacing: 6
WarningPanel {
id: wantedNetworkNotActive
Layout.fillWidth: true
text: qsTr("The owner token is minted on a network that isn't selected. Click here to enable it:")
}
StatusButton {
text: qsTr("Enable %1").arg(root.networkThatIsNotActive)
Layout.alignment: Qt.AlignVCenter
onClicked: root.enableNetwork()
}
}

View File

@ -19,6 +19,7 @@ MembersSettingsPanel 1.0 MembersSettingsPanel.qml
MembersTabPanel 1.0 MembersTabPanel.qml MembersTabPanel 1.0 MembersTabPanel.qml
MintTokensFooterPanel 1.0 MintTokensFooterPanel.qml MintTokensFooterPanel 1.0 MintTokensFooterPanel.qml
MintTokensSettingsPanel 1.0 MintTokensSettingsPanel.qml MintTokensSettingsPanel 1.0 MintTokensSettingsPanel.qml
NetworkWarningPanel 1.0 NetworkWarningPanel.qml
OverviewSettingsChart 1.0 OverviewSettingsChart.qml OverviewSettingsChart 1.0 OverviewSettingsChart.qml
OverviewSettingsFooter 1.0 OverviewSettingsFooter.qml OverviewSettingsFooter 1.0 OverviewSettingsFooter.qml
OverviewSettingsPanel 1.0 OverviewSettingsPanel.qml OverviewSettingsPanel 1.0 OverviewSettingsPanel.qml

View File

@ -26,6 +26,7 @@ StatusDialog {
property int multiplierIndex property int multiplierIndex
property url tokenSource property url tokenSource
property string chainName property string chainName
property string networkThatIsNotActive
readonly property alias amountToBurn: d.amountToBurn readonly property alias amountToBurn: d.amountToBurn
readonly property alias selectedAccountAddress: d.accountAddress readonly property alias selectedAccountAddress: d.accountAddress
@ -41,6 +42,7 @@ StatusDialog {
signal burnClicked(string burnAmount, string accountAddress) signal burnClicked(string burnAmount, string accountAddress)
signal cancelClicked signal cancelClicked
signal enableNetwork
QtObject { QtObject {
id: d id: d
@ -186,6 +188,14 @@ StatusDialog {
readonly property bool error: d.isFeeError readonly property bool error: d.isFeeError
} }
} }
NetworkWarningPanel {
visible: !!root.networkThatIsNotActive
Layout.fillWidth: true
networkThatIsNotActive: root.networkThatIsNotActive
onEnableNetwork: root.enableNetwork()
}
} }
header: StatusDialogHeader { header: StatusDialogHeader {

View File

@ -19,6 +19,7 @@ StatusDialog {
property alias model: tokenHoldersPanel.model property alias model: tokenHoldersPanel.model
property string collectibleName property string collectibleName
property string chainName property string chainName
property string networkThatIsNotActive
// Fees related properties: // Fees related properties:
property bool isFeeLoading property bool isFeeLoading
@ -38,6 +39,7 @@ StatusDialog {
property var accounts property var accounts
signal remotelyDestructClicked(var walletsAndAmounts, string accountAddress) signal remotelyDestructClicked(var walletsAndAmounts, string accountAddress)
signal enableNetwork
QtObject { QtObject {
id: d id: d
@ -103,7 +105,7 @@ StatusDialog {
id: feesBox id: feesBox
Layout.fillWidth: true Layout.fillWidth: true
Layout.bottomMargin: 16 Layout.bottomMargin: networkWarningPanel.visible ? 0 : 16
Layout.leftMargin: 16 Layout.leftMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16
@ -129,6 +131,19 @@ StatusDialog {
readonly property bool error: d.isFeeError readonly property bool error: d.isFeeError
} }
} }
NetworkWarningPanel {
id: networkWarningPanel
visible: !!root.networkThatIsNotActive
Layout.fillWidth: true
Layout.bottomMargin: 16
Layout.leftMargin: 18
Layout.rightMargin: 18
networkThatIsNotActive: root.chainName
onEnableNetwork: root.enableNetwork()
}
} }
footer: StatusDialogFooter { footer: StatusDialogFooter {

View File

@ -40,6 +40,8 @@ StatusSectionLayout {
property bool communitySettingsDisabled property bool communitySettingsDisabled
property var sendModalPopup property var sendModalPopup
required property string enabledChainIds
required property var walletAccountsModel // name, address, emoji, color required property var walletAccountsModel // name, address, emoji, color
readonly property bool isOwner: community.memberRole === Constants.memberRole.owner readonly property bool isOwner: community.memberRole === Constants.memberRole.owner
@ -51,6 +53,8 @@ StatusSectionLayout {
required property bool isPendingOwnershipRequest required property bool isPendingOwnershipRequest
signal finaliseOwnershipClicked signal finaliseOwnershipClicked
signal enableNetwork(int chainId)
readonly property string filteredSelectedTags: { readonly property string filteredSelectedTags: {
let tagsArray = [] let tagsArray = []
if (community && community.tags) { if (community && community.tags) {
@ -334,6 +338,7 @@ StatusSectionLayout {
readonly property string sectionName: qsTr("Tokens") readonly property string sectionName: qsTr("Tokens")
readonly property string sectionIcon: "token" readonly property string sectionIcon: "token"
readonly property bool sectionEnabled: true readonly property bool sectionEnabled: true
enabledChainIds: root.enabledChainIds
readonly property CommunityTokensStore communityTokensStore: readonly property CommunityTokensStore communityTokensStore:
rootStore.communityTokensStore rootStore.communityTokensStore
@ -373,6 +378,8 @@ StatusSectionLayout {
onStopTokenHoldersManagement: communityTokensStore.stopTokenHoldersManagement() onStopTokenHoldersManagement: communityTokensStore.stopTokenHoldersManagement()
onEnableNetwork: root.enableNetwork(chainId)
onMintCollectible: onMintCollectible:
communityTokensStore.deployCollectible( communityTokensStore.deployCollectible(
root.community.id, collectibleItem) root.community.id, collectibleItem)
@ -526,6 +533,8 @@ StatusSectionLayout {
assetsModel: assetsModelLoader.item assetsModel: assetsModelLoader.item
collectiblesModel: collectiblesModelLoader.item collectiblesModel: collectiblesModelLoader.item
membersModel: community.members membersModel: community.members
enabledChainIds: root.enabledChainIds
onEnableNetwork: root.enableNetwork(chainId)
accountsModel: root.walletAccountsModel accountsModel: root.walletAccountsModel
onAirdropClicked: communityTokensStore.airdrop( onAirdropClicked: communityTokensStore.airdrop(

View File

@ -45,6 +45,8 @@ StatusScrollView {
// Bool property indicating whether the fees are available // Bool property indicating whether the fees are available
required property bool feesAvailable required property bool feesAvailable
property string enabledChainIds
property int viewWidth: 560 // by design property int viewWidth: 560 // by design
readonly property var selectedHoldingsModel: ListModel {} readonly property var selectedHoldingsModel: ListModel {}
@ -101,6 +103,8 @@ StatusScrollView {
signal navigateToMintTokenSettings(bool isAssetType) signal navigateToMintTokenSettings(bool isAssetType)
signal enableNetwork(int chainId)
function selectToken(key, amount, type) { function selectToken(key, amount, type) {
if(selectedHoldingsModel) if(selectedHoldingsModel)
selectedHoldingsModel.clear() selectedHoldingsModel.clear()
@ -125,6 +129,9 @@ StatusScrollView {
&& airdropRecipientsSelector.valid && airdropRecipientsSelector.valid
&& airdropRecipientsSelector.count > 0 && airdropRecipientsSelector.count > 0
property string networkThatIsNotActive
property int networkIdThatIsNotActive
readonly property var selectedContractKeysAndAmounts: { readonly property var selectedContractKeysAndAmounts: {
//Depedencies: //Depedencies:
root.selectedHoldingsModel root.selectedHoldingsModel
@ -161,6 +168,7 @@ StatusScrollView {
key, amount, type, key, amount, type,
tokenText: amountLocalized + " " + modelItem.name, tokenText: amountLocalized + " " + modelItem.name,
tokenImage: modelItem.iconSource, tokenImage: modelItem.iconSource,
networkId: modelItem.chainId,
networkText: modelItem.chainName, networkText: modelItem.chainName,
networkImage: Style.svg(modelItem.chainIcon), networkImage: Style.svg(modelItem.chainIcon),
remainingSupply: modelItem.remainingSupply, remainingSupply: modelItem.remainingSupply,
@ -292,12 +300,25 @@ StatusScrollView {
root.selectedHoldingsModel, ["key", "amount"]) root.selectedHoldingsModel, ["key", "amount"])
} }
function isChainEnabled(entry) {
// If the tokens' network is not activated, show a warning to the user
if (!!entry && !root.enabledChainIds.includes(entry.networkId)) {
d.networkThatIsNotActive = entry.networkText
d.networkIdThatIsNotActive = entry.networkId
} else {
d.networkThatIsNotActive = ""
d.networkIdThatIsNotActive = 0
}
}
onAddAsset: { onAddAsset: {
const entry = d.prepareEntry(key, amount, Constants.TokenType.ERC20) const entry = d.prepareEntry(key, amount, Constants.TokenType.ERC20)
entry.valid = true entry.valid = true
selectedHoldingsModel.append(entry) selectedHoldingsModel.append(entry)
dropdown.close() dropdown.close()
isChainEnabled(entry)
} }
onAddCollectible: { onAddCollectible: {
@ -306,6 +327,8 @@ StatusScrollView {
selectedHoldingsModel.append(entry) selectedHoldingsModel.append(entry)
dropdown.close() dropdown.close()
isChainEnabled(entry)
} }
onUpdateAsset: { onUpdateAsset: {
@ -554,6 +577,18 @@ StatusScrollView {
recipientsCountInstantiator.maximumRecipientsCount < airdropRecipientsSelector.count recipientsCountInstantiator.maximumRecipientsCount < airdropRecipientsSelector.count
} }
NetworkWarningPanel {
visible: !!d.networkThatIsNotActive
Layout.fillWidth: true
Layout.topMargin: Style.current.padding
networkThatIsNotActive: d.networkThatIsNotActive
onEnableNetwork: {
root.enableNetwork(d.networkIdThatIsNotActive)
d.networkThatIsNotActive = ""
d.networkIdThatIsNotActive = 0
}
}
StatusButton { StatusButton {
Layout.preferredHeight: 44 Layout.preferredHeight: 44
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter

View File

@ -44,6 +44,9 @@ StatusScrollView {
property string feeErrorText property string feeErrorText
property bool isFeeLoading property bool isFeeLoading
property string networkThatIsNotActive
signal enableNetwork
readonly property string feeLabel: readonly property string feeLabel:
isAssetView ? qsTr("Mint asset on %1").arg(root.token.chainName) isAssetView ? qsTr("Mint asset on %1").arg(root.token.chainName)
: qsTr("Mint collectible on %1").arg(root.token.chainName) : qsTr("Mint collectible on %1").arg(root.token.chainName)
@ -253,6 +256,15 @@ StatusScrollView {
} }
} }
NetworkWarningPanel {
visible: !!root.networkThatIsNotActive
Layout.fillWidth: true
Layout.topMargin: Style.current.padding
networkThatIsNotActive: root.networkThatIsNotActive
onEnableNetwork: root.enableNetwork()
}
CustomSwitchRowComponent { CustomSwitchRowComponent {
id: unlimitedSupplyChecker id: unlimitedSupplyChecker

View File

@ -375,6 +375,10 @@ QtObject {
networksModule.toggleNetwork(chainId) networksModule.toggleNetwork(chainId)
} }
function enableNetwork(chainId) {
networksModule.enableNetwork(chainId)
}
function copyToClipboard(text) { function copyToClipboard(text) {
globalUtils.copyToClipboard(text) globalUtils.copyToClipboard(text)
} }