chore_: put multi tx send under the feature flag and add integrate simple send

The easiest way of adding single chain only is integrated.
Selecting networks is done within the Advance tab.
Multi tx is set under the feature flag, disabled by default.
This commit is contained in:
Sale Djenic 2024-07-26 17:02:18 +02:00
parent ff005a219a
commit fb7c7ded8f
11 changed files with 147 additions and 25 deletions

View File

@ -4,6 +4,7 @@ import os
const DEFAULT_FLAG_DAPPS_ENABLED = false
const DEFAULT_FLAG_SWAP_ENABLED = true
const DEFAULT_FLAG_CONNECTOR_ENABLED = true
const DEFAULT_FLAG_MULTI_TX_ENABLED = false
proc boolToEnv(defaultValue: bool): string =
return if defaultValue: "1" else: "0"
@ -13,12 +14,14 @@ QtObject:
dappsEnabled: bool
swapEnabled: bool
connectorEnabled: bool
multiTxEnabled: bool
proc setup(self: FeatureFlags) =
self.QObject.setup()
self.dappsEnabled = getEnv("FLAG_DAPPS_ENABLED", boolToEnv(DEFAULT_FLAG_DAPPS_ENABLED)) != "0"
self.swapEnabled = getEnv("FLAG_SWAP_ENABLED", boolToEnv(DEFAULT_FLAG_SWAP_ENABLED)) != "0"
self.connectorEnabled = getEnv("FLAG_CONNECTOR_ENABLED", boolToEnv(DEFAULT_FLAG_CONNECTOR_ENABLED)) != "0"
self.multiTxEnabled = getEnv("FLAG_MULTI_TX_ENABLED", boolToEnv(DEFAULT_FLAG_MULTI_TX_ENABLED)) != "0"
proc delete*(self: FeatureFlags) =
self.QObject.delete()
@ -44,3 +47,10 @@ QtObject:
QtProperty[bool] connectorEnabled:
read = getConnectorEnabled
proc getMultiTxEnabled*(self: FeatureFlags): bool {.slot.} =
return self.multiTxEnabled
QtProperty[bool] multiTxEnabled:
read = getMultiTxEnabled

View File

@ -16,6 +16,7 @@ export user_profile
export utils
export global_events
export loader_deactivator
export feature_flags
type
GlobalSingleton = object

View File

@ -21,6 +21,8 @@ import app/modules/shared_models/collectibles_model as collectibles
import app/modules/shared_models/collectibles_nested_model as nested_collectibles
import backend/collectibles as backend_collectibles
import constants as main_constants
export io_interface
logScope:
@ -109,7 +111,7 @@ proc convertSendToNetworkToNetworkItem(self: Module, network: SendToNetwork): Ne
proc convertNetworkDtoToNetworkRouteItem(self: Module, network: network_service_item.NetworkItem): NetworkRouteItem =
result = initNetworkRouteItem(
network.chainId,
network.chainId,
network.layer,
true,
false,
@ -220,7 +222,7 @@ method authenticateAndTransferWithPaths*(self: Module, fromAddr: string, toAddr:
# Temporary until transaction service rework is completed
let pathsV2 = rawPaths.toTransactionPathsDtoV2()
let pathsV1 = pathsV2.convertToOldRoute().addFirstSimpleBridgeTxFlag()
self.tmpSendTransactionDetails.paths = pathsV1
self.tmpSendTransactionDetails.slippagePercentage = slippagePercentage
self.authenticateAndTransfer(fromAddr, toAddr, assetKey, toAssetKey, uuid, sendType, selectedTokenName, selectedTokenIsOwnerToken)
@ -310,6 +312,29 @@ method suggestedRoutes*(self: Module,
disabledToChainIDs: seq[int] = @[],
lockedInAmounts: Table[string, string] = initTable[string, string](),
extraParamsTable: Table[string, string] = initTable[string, string]()) =
var
finalLockedInAmounts = lockedInAmounts
finalDisbaledFromChains = disabledFromChainIDs
finalDisbaledToChains = disabledToChainIDs
if not singletonInstance.featureFlags.getMultiTxEnabled():
finalLockedInAmounts.clear()
const maxDisabledChains = 2 # at any given time, only 2 chains can be disabled
if finalDisbaledFromChains.len != maxDisabledChains:
if self.controller.areTestNetworksEnabled():
finalDisbaledFromChains = @[main_constants.SEPOLIA_OPTIMISM_CHAIN_ID, main_constants.SEPOLIA_ARBITRUM_CHAIN_ID]
else:
finalDisbaledFromChains = @[main_constants.OPTIMISM_CHAIN_ID, main_constants.ARBITRUM_CHAIN_ID]
if finalDisbaledToChains.len != maxDisabledChains:
if self.controller.areTestNetworksEnabled():
finalDisbaledToChains = @[main_constants.SEPOLIA_OPTIMISM_CHAIN_ID, main_constants.SEPOLIA_ARBITRUM_CHAIN_ID]
else:
finalDisbaledToChains = @[main_constants.OPTIMISM_CHAIN_ID, main_constants.ARBITRUM_CHAIN_ID]
self.controller.suggestedRoutes(
uuid,
sendType,
@ -319,9 +344,9 @@ method suggestedRoutes*(self: Module,
amountIn,
toToken,
amountOut,
disabledFromChainIDs,
disabledToChainIDs,
lockedInAmounts,
finalDisbaledFromChains,
finalDisbaledToChains,
finalLockedInAmounts,
extraParamsTable
)

View File

@ -76,3 +76,10 @@ proc runtimeLogLevelSet*(): bool =
return existsEnv(RUN_TIME_PREFIX & "_LOG_LEVEL") or hasLogLevelOption()
const MAIN_STATUS_SHARD_CLUSTER_ID* = 16
const MAINNET_CHAIN_ID* = 1
const SEPOLIA_CHAIN_ID* = 11155111
const OPTIMISM_CHAIN_ID* = 10
const SEPOLIA_OPTIMISM_CHAIN_ID* = 11155420
const ARBITRUM_CHAIN_ID* = 42161
const SEPOLIA_ARBITRUM_CHAIN_ID* = 421614

View File

@ -158,6 +158,26 @@ StatusDialog {
recalculateRoutesAndFees()
}
// This function is used in single selected chain mode, not for multitx sending.
// Providing correct chainId will make that chain selected, otherwise the mainnet chain will be selecte as default one.
function changeSelectedChain(chainId) {
if (Global.featureFlags.multiTxEnabled) {
return
}
for( var i = 0; i < fromNetworksRouteModel.rowCount(); i++ ) {
const item = SQUtils.ModelUtils.get(fromNetworksRouteModel, i)
if (item.chainId === chainId) {
store.setRouteDisabledFromChains(item.chainId, false)
store.setRouteDisabledToChains(item.chainId, false)
continue
}
store.setRouteDisabledFromChains(item.chainId, true)
store.setRouteDisabledToChains(item.chainId, true)
}
popup.recalculateRoutesAndFees()
}
}
LeftJoinModel {
@ -549,6 +569,12 @@ StatusDialog {
onIsLoading: popup.isLoading = true
onRecalculateRoutesAndFees: popup.recalculateRoutesAndFees()
onAddressTextChanged: store.setSelectedRecipient(addressText)
fromNetworksList: fromNetworksRouteModel
onChangeSelectedChain: {
d.changeSelectedChain(chainId)
}
}
}
}
@ -634,6 +660,10 @@ StatusDialog {
totalFeesInFiat: d.totalFeesInFiat
fromNetworksList: fromNetworksRouteModel
toNetworksList: toNetworksRouteModel
onChangeSelectedChain:{
d.changeSelectedChain(chainId)
}
}
}
}

View File

@ -32,6 +32,8 @@ Item {
property int errorType: Constants.NoError
property bool isLoading
signal changeSelectedChain(int chainId)
QtObject {
id: d
property double customAmountToSend: 0
@ -114,15 +116,20 @@ Item {
(root.errorMode || !advancedInput.valid) && advancedInputCurrencyAmount > 0 ? "error" : "default"
cardIcon.source: Style.svg(model.iconUrl)
disabledText: qsTr("Disabled")
disableText: qsTr("Disable")
enableText: qsTr("Enable")
disableText: Global.featureFlags.multiTxEnabled? qsTr("Disable") : ""
enableText: Global.featureFlags.multiTxEnabled? qsTr("Enable") : qsTr("Select")
advancedMode: root.customMode
disabled: !model.isRouteEnabled
clickable: root.interactive
clickable: Global.featureFlags.multiTxEnabled && root.interactive ||
!Global.featureFlags.multiTxEnabled && disabled
onClicked: {
store.toggleFromDisabledChains(model.chainId)
store.lockCard(model.chainId, 0, false)
root.reCalculateSuggestedRoute()
if (!Global.featureFlags.multiTxEnabled) {
root.changeSelectedChain(model.chainId)
} else {
store.toggleFromDisabledChains(model.chainId)
store.lockCard(model.chainId, 0, false)
root.reCalculateSuggestedRoute()
}
}
onLockCard: {
let amount = lock ? (advancedInputCurrencyAmount * Math.pow(10, root.selectedAsset.decimals)).toString(16) : ""
@ -183,14 +190,19 @@ Item {
opacity: preferred || store.showUnPreferredChains ? 1 : 0
cardIcon.source: Style.svg(model.iconUrl)
disabledText: qsTr("Disabled")
disableText: qsTr("Disable")
enableText: qsTr("Enable")
disableText: Global.featureFlags.multiTxEnabled? qsTr("Disable") : ""
enableText: Global.featureFlags.multiTxEnabled? qsTr("Enable") : qsTr("Select")
disabled: !model.isRouteEnabled
clickable: root.interactive
clickable: Global.featureFlags.multiTxEnabled && root.interactive ||
!Global.featureFlags.multiTxEnabled && disabled
loading: root.isLoading
onClicked: {
store.toggleToDisabledChains(model.chainId)
root.reCalculateSuggestedRoute()
if (!Global.featureFlags.multiTxEnabled) {
root.changeSelectedChain(model.chainId)
} else {
store.toggleToDisabledChains(model.chainId)
root.reCalculateSuggestedRoute()
}
}
}
}

View File

@ -37,6 +37,7 @@ Item {
property double totalFeesInFiat
signal reCalculateSuggestedRoute()
signal changeSelectedChain(int chainId)
implicitHeight: childrenRect.height
@ -59,6 +60,7 @@ Item {
}
StatusSwitchTabButton {
text: qsTr("Custom")
enabled: Global.featureFlags.multiTxEnabled
}
}
@ -133,6 +135,10 @@ Item {
return parseFloat(store.getWei2Eth(wei, selectedAsset.decimals))
return 0
}
onChangeSelectedChain: {
root.changeSelectedChain(chainId)
}
}
}
}

View File

@ -33,6 +33,7 @@ ColumnLayout {
property int errorType: Constants.NoError
signal reCalculateSuggestedRoute()
signal changeSelectedChain(int chainId)
RowLayout {
Layout.fillWidth: true
@ -67,7 +68,7 @@ ColumnLayout {
icon.height: 16
icon.width: 16
text: checked ? qsTr("Hide Unpreferred Networks"): qsTr("Show Unpreferred Networks")
visible: !isBridgeTx
visible: Global.featureFlags.multiTxEnabled && !isBridgeTx
checked: root.store.showUnPreferredChains
onClicked: {
root.store.toggleShowUnPreferredChains()
@ -79,8 +80,13 @@ ColumnLayout {
Layout.fillWidth: true
font.pixelSize: 15
color: Theme.palette.baseColor1
text: isBridgeTx ? qsTr("Routes will be automatically calculated to give you the lowest cost.") :
qsTr("The networks where the recipient will receive tokens. Amounts calculated automatically for the lowest cost.")
text: {
if (Global.featureFlags.multiTxEnabled) {
return isBridgeTx ? qsTr("Routes will be automatically calculated to give you the lowest cost.") :
qsTr("The networks where the recipient will receive tokens. Amounts calculated automatically for the lowest cost.")
}
return qsTr("Select the network to make a transaction on")
}
wrapMode: Text.WordWrap
}
Loader {
@ -108,6 +114,10 @@ ColumnLayout {
interactive: root.interactive
errorType: root.errorType
isLoading: root.isLoading
onChangeSelectedChain: {
root.changeSelectedChain(chainId)
}
}
}
}

View File

@ -157,7 +157,7 @@ RowLayout {
}
}
onCheckedChanged: {
store.setRouteDisabledChains(chainId, !gasRectangle.checked)
store.setRouteDisabledToChains(chainId, !gasRectangle.checked)
if(checked)
root.reCalculateSuggestedRoute()
}
@ -167,7 +167,7 @@ RowLayout {
height: card.height
}
Component.onCompleted: {
store.setRouteDisabledChains(chainId, !gasRectangle.checked)
store.setRouteDisabledToChains(chainId, !gasRectangle.checked)
if(index === (repeater.count -1))
root.reCalculateSuggestedRoute()
}

View File

@ -29,12 +29,15 @@ Loader {
property var selectedRecipient: null
property int selectedRecipientType: Helpers.RecipientAddressObjectType.Address
property var fromNetworksList // needed just for simple view
readonly property bool ready: (d.isAddressValid || !!resolvedENSAddress) && !d.isPending
property string addressText
property string resolvedENSAddress
signal recalculateRoutesAndFees()
signal isLoading()
signal changeSelectedChain(int chainId)
onAddressTextChanged: d.isPending = false
@ -74,10 +77,24 @@ Loader {
// set preferred chains
if(!isCollectiblesTransfer) {
if(root.isBridgeTx)
if (Global.featureFlags.multiTxEnabled) {
if(root.isBridgeTx)
root.store.setAllNetworksAsRoutePreferredChains()
else
root.store.updateRoutePreferredChains(preferredChainIds)
} else {
// for simple sending we always set all chains as preferred chains, but we select the first one from the prefferd chains
// as selected chain (just to obey address prefixes)
let chainIds = preferredChainIds.split(":").filter(Boolean).map(Number)
root.store.setAllNetworksAsRoutePreferredChains()
else
root.store.updateRoutePreferredChains(preferredChainIds)
if (chainIds.length > 0) {
root.changeSelectedChain(chainIds[0])
} else {
root.changeSelectedChain(-1)
}
return
}
}
recalculateRoutesAndFees()

View File

@ -124,10 +124,14 @@ QtObject {
walletSectionSendInst.toNetworksRouteModel.toggleRouteDisabledChains(chainId)
}
function setRouteDisabledChains(chainId, disabled) {
function setRouteDisabledToChains(chainId, disabled) {
walletSectionSendInst.toNetworksRouteModel.setRouteDisabledChains(chainId, disabled)
}
function setRouteDisabledFromChains(chainId, disabled) {
walletSectionSendInst.fromNetworksRouteModel.setRouteDisabledChains(chainId, disabled)
}
function setSelectedTokenName(tokenName) {
walletSectionSendInst.setSelectedTokenName(tokenName)
}